diff --git a/src/main/java/org/olat/collaboration/CollaborationTools.java b/src/main/java/org/olat/collaboration/CollaborationTools.java
index 7bebf36f6c8a94cf1a3665910c348cad89288774..d44dc60d21fad04260a1a8fe80194ab6f6349157 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/learningpath/ui/LearningPathNodeConfigController.java b/src/main/java/org/olat/course/learningpath/ui/LearningPathNodeConfigController.java
index 2d492632f2ead52b4b7d78c6330d0cd5f70fc7e0..25afddffee257e831a0c0b962e16d90941241e82 100644
--- a/src/main/java/org/olat/course/learningpath/ui/LearningPathNodeConfigController.java
+++ b/src/main/java/org/olat/course/learningpath/ui/LearningPathNodeConfigController.java
@@ -91,7 +91,7 @@ public class LearningPathNodeConfigController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("config.title");
-		
+		setFormContextHelp("Learning path element");
 		KeyValues obligationKV = new KeyValues();
 		obligationKV.add(entry(AssessmentObligation.mandatory.name(), translate("config.obligation.mandatory")));
 		obligationKV.add(entry(AssessmentObligation.optional.name(), translate("config.obligation.optional")));
diff --git a/src/main/java/org/olat/course/learningpath/ui/_content/identity.html b/src/main/java/org/olat/course/learningpath/ui/_content/identity.html
index 43833403c7e0d14e40bd943bdb022f46f9f8d914..017395035eaff4ab12e79626c209768fd34e6289 100644
--- a/src/main/java/org/olat/course/learningpath/ui/_content/identity.html
+++ b/src/main/java/org/olat/course/learningpath/ui/_content/identity.html
@@ -3,6 +3,7 @@
 		<i class="o_icon o_icon_learning_path"> </i> 
 		$r.translate("identity.list.title") 
 		<small>$r.translate("identity.list.course",$courseTitle)</small>
+		$r.contextHelpWithWrapper("Learning path profile")
 	</h2>
 	$r.render("user")
 	$r.render("list")
diff --git a/src/main/java/org/olat/course/nodeaccess/ui/NodeAccessSettingsController.java b/src/main/java/org/olat/course/nodeaccess/ui/NodeAccessSettingsController.java
index 42ce0e9a6e24f248f119559ce2791bfbbedddb2c..871734d52e929e3c004132f41d7e1a63006547e7 100644
--- a/src/main/java/org/olat/course/nodeaccess/ui/NodeAccessSettingsController.java
+++ b/src/main/java/org/olat/course/nodeaccess/ui/NodeAccessSettingsController.java
@@ -103,7 +103,7 @@ public class NodeAccessSettingsController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("settings.title");
-		
+		setFormContextHelp("Access course elements");
 		String nodeAccessTypeName = nodeAccessService.getNodeAccessTypeName(courseConfig.getNodeAccessType(),
 				getLocale());
 		uifactory.addStaticTextElement("settings.type", nodeAccessTypeName, formLayout);;
diff --git a/src/main/java/org/olat/course/nodes/CPCourseNode.java b/src/main/java/org/olat/course/nodes/CPCourseNode.java
index 55abf30ca7bca2dd1af0f429f88adf8dcc9baa04..075cdeb22db2a8c28e7251161eb0fdc87f19277c 100644
--- a/src/main/java/org/olat/course/nodes/CPCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/CPCourseNode.java
@@ -75,7 +75,7 @@ public class CPCourseNode extends AbstractAccessableCourseNode {
 	private static final Logger log = Tracing.createLoggerFor(CPCourseNode.class);
 
 	private static final long serialVersionUID = -4317662219173515498L;
-	private static final String TYPE = "cp";
+	public static final String TYPE = "cp";
 
 	public CPCourseNode() {
 		this(null);
@@ -101,14 +101,14 @@ public class CPCourseNode extends AbstractAccessableCourseNode {
 	public NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl,
 			UserCourseEnvironment userCourseEnv, CourseNodeSecurityCallback nodeSecCallback, String nodecmd) {
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance(ICourse.class, userCourseEnv.getCourseEnvironment().getCourseResourceableId());
-		CPRunController cprunC = new CPRunController(getModuleConfiguration(), ureq, wControl, this, nodecmd, ores, false);
+		CPRunController cprunC = new CPRunController(getModuleConfiguration(), ureq, wControl, this, nodecmd, ores, false, userCourseEnv);
 		return cprunC.createNodeRunConstructionResult(ureq, null);
 	}
 
 	@Override
 	public Controller createPreviewController(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, CourseNodeSecurityCallback nodeSecCallback) {
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance(ICourse.class, userCourseEnv.getCourseEnvironment().getCourseResourceableId());
-		return new CPRunController(getModuleConfiguration(), ureq, wControl, this, null, ores, true);
+		return new CPRunController(getModuleConfiguration(), ureq, wControl, this, null, ores, true, userCourseEnv);
 	}
 	
 	@Override
diff --git a/src/main/java/org/olat/course/nodes/WikiCourseNode.java b/src/main/java/org/olat/course/nodes/WikiCourseNode.java
index faf51a6fdd5067fb167417e4115b8e8d290adae8..5dabf59951d6e7b5d9d7b563d105f30cc75f5cc4 100644
--- a/src/main/java/org/olat/course/nodes/WikiCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/WikiCourseNode.java
@@ -56,6 +56,7 @@ import org.olat.course.ICourse;
 import org.olat.course.condition.Condition;
 import org.olat.course.condition.interpreter.ConditionExpression;
 import org.olat.course.condition.interpreter.ConditionInterpreter;
+import org.olat.course.editor.ConditionAccessEditConfig;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.editor.StatusDescription;
@@ -83,11 +84,19 @@ import org.olat.repository.handlers.RepositoryHandlerFactory;
  * @author Felix Jost
  */
 public class WikiCourseNode extends AbstractAccessableCourseNode {
+
 	private static final long serialVersionUID = -5800975339569440113L;
 
 	private static final Logger log = Tracing.createLoggerFor(WikiCourseNode.class);
 
 	public static final String TYPE = "wiki";
+
+	private static final int CURRENT_VERSION = 2;
+	public static final String CONFIG_KEY_REPOSITORY_SOFTKEY = "reporef";
+	public static final String CONFIG_KEY_EDIT_BY_COACH = "edit.by.coach";
+	public static final String CONFIG_KEY_EDIT_BY_PARTICIPANT = "edit.by.participant";
+	
+	public static final String EDIT_CONDITION = "editarticle";
 	private Condition preConditionEdit;
 
 	public WikiCourseNode() {
@@ -105,6 +114,31 @@ public class WikiCourseNode extends AbstractAccessableCourseNode {
 			config.setBooleanEntry(NodeEditController.CONFIG_STARTPAGE, false);
 			config.setConfigurationVersion(1);
 		}
+		if (config.getConfigurationVersion() < 2) {
+			config.setBooleanEntry(CONFIG_KEY_EDIT_BY_COACH, Boolean.TRUE);
+			config.setBooleanEntry(CONFIG_KEY_EDIT_BY_PARTICIPANT, Boolean.TRUE);
+			removeDefaultPreconditions();
+		}
+		
+		config.setConfigurationVersion(CURRENT_VERSION);
+	}
+	
+	private void removeDefaultPreconditions() {
+		if (hasCustomPreConditions()) {
+			boolean defaultPreconditions =
+					!preConditionEdit.isExpertMode()
+				&& !preConditionEdit.isEasyModeCoachesAndAdmins()
+				&& !preConditionEdit.isEasyModeAlwaysAllowCoachesAndAdmins()
+				&& !preConditionEdit.isAssessmentMode()
+				&& !preConditionEdit.isAssessmentModeViewResults();
+			if (defaultPreconditions) {
+				removeCustomPreconditions();
+			}
+		}
+	}
+	
+	public void removeCustomPreconditions() {
+		preConditionEdit = null;
 	}
 	
 	@Override
@@ -121,10 +155,17 @@ public class WikiCourseNode extends AbstractAccessableCourseNode {
 
 	@Override
 	public TabbableController createEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, ICourse course,UserCourseEnvironment euce) {
-		WikiEditController childTabCntrllr = new WikiEditController(getModuleConfiguration(), ureq, wControl, this, course,euce);
+		WikiEditController childTabCntrllr = new WikiEditController(ureq, wControl, stackPanel, this, course,euce);
 		CourseNode chosenNode = course.getEditorTreeModel().getCourseNode(euce.getCourseEditorEnv().getCurrentCourseNodeId());
 		return new NodeEditController(ureq, wControl, course, chosenNode, euce, childTabCntrllr);
 	}
+	
+	@Override
+	public ConditionAccessEditConfig getAccessEditConfig() {
+		return hasCustomPreConditions()
+				? ConditionAccessEditConfig.custom()
+				: ConditionAccessEditConfig.regular(false);
+	}
 
 	@Override
 	public NodeRunConstructionResult createNodeRunConstructionResult(UserRequest ureq, WindowControl wControl,
@@ -139,9 +180,6 @@ public class WikiCourseNode extends AbstractAccessableCourseNode {
 
 	@Override
 	public StatusDescription isConfigValid() {
-		/*
-		 * first check the one click cache
-		 */
 		if(oneClickStatusCache!=null) {
 			return oneClickStatusCache[0];
 		}
@@ -242,37 +280,40 @@ public class WikiCourseNode extends AbstractAccessableCourseNode {
 	
 	@Override
 	public List<ConditionExpression> getConditionExpressions() {
-		List<ConditionExpression> parentConditions = super.getConditionExpressions();
-		List<ConditionExpression> conditions = new ArrayList<>();
-		if(parentConditions != null && parentConditions.size() > 0) {
-			conditions.addAll(parentConditions);
-		}
-		Condition editCondition = getPreConditionEdit();
-		if(editCondition != null && StringHelper.containsNonWhitespace(editCondition.getConditionExpression())) {
-			ConditionExpression ce = new ConditionExpression(editCondition.getConditionId());
-			ce.setExpressionString(editCondition.getConditionExpression());
-			conditions.add(ce);
+		if (hasCustomPreConditions()) {
+			List<ConditionExpression> parentConditions = super.getConditionExpressions();
+			List<ConditionExpression> conditions = new ArrayList<>();
+			if(parentConditions != null && parentConditions.size() > 0) {
+				conditions.addAll(parentConditions);
+			}
+			Condition editCondition = getPreConditionEdit();
+			if(editCondition != null && StringHelper.containsNonWhitespace(editCondition.getConditionExpression())) {
+				ConditionExpression ce = new ConditionExpression(editCondition.getConditionId());
+				ce.setExpressionString(editCondition.getConditionExpression());
+				conditions.add(ce);
+			}
+			return conditions;
 		}
-		return conditions;
+		return super.getConditionExpressions();
+	}
+	
+	public boolean hasCustomPreConditions() {
+		return preConditionEdit != null;
 	}
 
 	public Condition getPreConditionEdit() {
 		if (preConditionEdit == null) {
 			preConditionEdit = new Condition();
 		}
-		preConditionEdit.setConditionId("editarticle");
+		preConditionEdit.setConditionId(EDIT_CONDITION);
 		return preConditionEdit;
 	}
 
-	/**
-	 * 
-	 * @param preConditionEdit
-	 */
 	public void setPreConditionEdit(Condition preConditionEdit) {
 		if (preConditionEdit == null) {
 			preConditionEdit = getPreConditionEdit();
 		}
-		preConditionEdit.setConditionId("editarticle");
+		preConditionEdit.setConditionId(EDIT_CONDITION);
 		this.preConditionEdit = preConditionEdit;
 	}
 	
@@ -285,10 +326,12 @@ public class WikiCourseNode extends AbstractAccessableCourseNode {
 	 */
 	@Override
 	public void calcAccessAndVisibility(ConditionInterpreter ci, NodeEvaluation nodeEval) {
-	  super.calcAccessAndVisibility(ci, nodeEval);
-		
-	  boolean editor = (getPreConditionEdit().getConditionExpression() == null ? true : ci.evaluateCondition(getPreConditionEdit()));
-		nodeEval.putAccessStatus("editarticle", editor);		
+		super.calcAccessAndVisibility(ci, nodeEval);
+	
+		if (hasCustomPreConditions()) {
+			boolean editor = (getPreConditionEdit().getConditionExpression() == null ? true : ci.evaluateCondition(getPreConditionEdit()));
+			nodeEval.putAccessStatus(EDIT_CONDITION, editor);
+		}
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/nodes/cp/CPAssessmentHandler.java b/src/main/java/org/olat/course/nodes/cp/CPAssessmentHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..198ca119e54ce43e93d651a8f16226d2a773121a
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/cp/CPAssessmentHandler.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.cp;
+
+import org.olat.course.learningpath.LearningPathOnlyAssessmentHandler;
+import org.olat.course.nodes.CPCourseNode;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 27.02.2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class CPAssessmentHandler extends LearningPathOnlyAssessmentHandler {
+
+	@Override
+	public String acceptCourseNodeType() {
+		return CPCourseNode.TYPE;
+	}
+
+}
diff --git a/src/main/java/org/olat/course/nodes/cp/CPLearningPathNodeHandler.java b/src/main/java/org/olat/course/nodes/cp/CPLearningPathNodeHandler.java
new file mode 100644
index 0000000000000000000000000000000000000000..13e6aeb891fa40fafc7ea2e3e3445382bfdb482a
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/cp/CPLearningPathNodeHandler.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.cp;
+
+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.CPCourseNode;
+import org.olat.course.nodes.CourseNode;
+import org.olat.repository.RepositoryEntry;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 27.02.2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class CPLearningPathNodeHandler implements LearningPathNodeHandler {
+
+	private static final LearningPathEditConfigs EDIT_CONFIGS = LearningPathEditConfigs.builder()
+			.enableNodeVisited()
+			.enableConfirmed()
+			.build();
+	
+	@Override
+	public String acceptCourseNodeType() {
+		return CPCourseNode.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/cp/CPRunController.java b/src/main/java/org/olat/course/nodes/cp/CPRunController.java
index 9010b2d3a45d8677846dcd4f7079b4fe114e6e52..160ec30744f82ffba46198838b2448a841e76172 100644
--- a/src/main/java/org/olat/course/nodes/cp/CPRunController.java
+++ b/src/main/java/org/olat/course/nodes/cp/CPRunController.java
@@ -54,13 +54,17 @@ import org.olat.course.editor.NodeEditController;
 import org.olat.course.nodes.CPCourseNode;
 import org.olat.course.nodes.TitledWrapperHelper;
 import org.olat.course.run.navigation.NodeRunConstructionResult;
+import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.fileresource.FileResourceManager;
 import org.olat.ims.cp.CPManager;
 import org.olat.ims.cp.ui.CPPackageConfig;
 import org.olat.modules.ModuleConfiguration;
+import org.olat.modules.cp.CPAssessmentProvider;
 import org.olat.modules.cp.CPDisplayController;
 import org.olat.modules.cp.CPManifestTreeModel;
 import org.olat.modules.cp.CPUIFactory;
+import org.olat.modules.cp.DryRunAssessmentProvider;
+import org.olat.modules.cp.PersistingAssessmentProvider;
 import org.olat.modules.cp.TreeNodeEvent;
 import org.olat.repository.RepositoryEntry;
 import org.olat.util.logging.activity.LoggingResourceable;
@@ -91,10 +95,12 @@ public class CPRunController extends BasicController implements ControllerEventL
 	private String selNodeId;
 	private boolean preview;
 	private OLATResourceable courseResource;
-
+	private final UserCourseEnvironment userCourseEnv;
+	private CPAssessmentProvider cpAssessmentProvider;
+	
 	@Autowired
 	private CPManager cpManager;
-	
+
 	/**
 	 * Use this constructor to launch a CP via Repository reference key set in the
 	 * ModuleConfiguration. On the into page a title and the learning objectives
@@ -105,9 +111,10 @@ public class CPRunController extends BasicController implements ControllerEventL
 	 * @param userCourseEnv
 	 * @param wControl
 	 * @param cpNode
+	 * @param userCourseEnv 
 	 */
 	public CPRunController(ModuleConfiguration config, UserRequest ureq, WindowControl wControl, CPCourseNode cpNode, String nodecmd,
-			OLATResourceable course, boolean preview) {
+			OLATResourceable course, boolean preview, UserCourseEnvironment userCourseEnv) {
 		super(ureq, wControl);
 		this.nodecmd = nodecmd;
 		this.courseResource = OresHelper.clone(course);
@@ -116,6 +123,7 @@ public class CPRunController extends BasicController implements ControllerEventL
 		this.config = config;
 		this.cpNode = cpNode;
 		this.preview = preview;
+		this.userCourseEnv = userCourseEnv;
 		addLoggingResourceable(LoggingResourceable.wrap(cpNode));
 
 		// jump to either the forum or the folder if the business-launch-path says so.
@@ -140,10 +148,6 @@ public class CPRunController extends BasicController implements ControllerEventL
 		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 == showCPButton) { // those must be links
@@ -152,10 +156,6 @@ public class CPRunController extends BasicController implements ControllerEventL
 		}
 	}
 
-	/**
-	 * @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 == null) { // external source (from the course at this time being)
@@ -202,6 +202,10 @@ public class CPRunController extends BasicController implements ControllerEventL
 					deliveryOptions = packageConfig.getDeliveryOptions();
 				}
 			}
+			
+			cpAssessmentProvider = userCourseEnv.getIdentityEnvironment().getRoles().isGuestOnly()
+					? DryRunAssessmentProvider.create()
+					: PersistingAssessmentProvider.create(re, getIdentity());
 		}
 		// else cpRoot is already set (save some db access if the user opens /
 		// closes / reopens the cp from the same CPRuncontroller instance)
@@ -210,8 +214,10 @@ public class CPRunController extends BasicController implements ControllerEventL
  		  activateFirstPage = false; 
 		}
 		boolean showNavigation = !config.getBooleanSafe(NodeEditController.CONFIG_COMPONENT_MENU);
-		cpDispC = CPUIFactory.getInstance().createContentOnlyCPDisplayController(ureq, getWindowControl(), new LocalFolderImpl(cpRoot),
-				activateFirstPage, showNavigation, deliveryOptions, nodecmd, courseResource, cpNode.getIdent(), preview);
+		
+		cpDispC = CPUIFactory.getInstance().createContentOnlyCPDisplayController(ureq, getWindowControl(),
+				new LocalFolderImpl(cpRoot), activateFirstPage, showNavigation, deliveryOptions, nodecmd,
+				courseResource, cpNode.getIdent(), preview, cpAssessmentProvider);
 		cpDispC.setContentEncoding(deliveryOptions.getContentEncoding());
 		cpDispC.setJSEncoding(deliveryOptions.getJavascriptEncoding());
 		cpDispC.addControllerListener(this);
@@ -240,9 +246,6 @@ public class CPRunController extends BasicController implements ControllerEventL
 		return (config.getBooleanEntry(NodeEditController.CONFIG_COMPONENT_MENU).booleanValue());
 	}
 	
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
 	@Override
 	protected void doDispose() {
 		if (cpDispC != null) {
diff --git a/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathConfigController.java b/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathConfigController.java
index ca4ea02b7cdbdf636b874d2cc75046bce74cbc69..1e73e148882af1ccb910d2003f796d182c7f50c7 100644
--- a/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathConfigController.java
+++ b/src/main/java/org/olat/course/nodes/st/assessment/STLearningPathConfigController.java
@@ -58,7 +58,7 @@ public class STLearningPathConfigController extends FormBasicController {
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormTitle("config.title");
-		
+		setFormContextHelp("Learning Path");
 		KeyValues sequenceKV = new KeyValues();
 		sequenceKV.add(KeyValues.entry(STCourseNode.CONFIG_LP_SEQUENCE_VALUE_SEQUENTIAL, translate("config.sequence.sequential")));
 		sequenceKV.add(KeyValues.entry(STCourseNode.CONFIG_LP_SEQUENCE_VALUE_WITHOUT, translate("config.sequence.without")));
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 0000000000000000000000000000000000000000..3750ed7599760272e67607c88a1767d62a2397a4
--- /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/WikiConfigController.java b/src/main/java/org/olat/course/nodes/wiki/WikiConfigController.java
new file mode 100644
index 0000000000000000000000000000000000000000..ece7c1f484d83e45483d8d9006373a1d8c1ac1f5
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/wiki/WikiConfigController.java
@@ -0,0 +1,262 @@
+/**
+ * <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 static org.olat.core.gui.translator.TranslatorHelper.translateAll;
+
+import java.util.Collection;
+
+import org.olat.basesecurity.GroupRoles;
+import org.olat.basesecurity.OrganisationRoles;
+import org.olat.core.commons.services.notifications.SubscriptionContext;
+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.StaticTextElement;
+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.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.id.Roles;
+import org.olat.core.util.StringHelper;
+import org.olat.course.ICourse;
+import org.olat.course.editor.NodeEditController;
+import org.olat.course.nodes.AbstractFeedCourseNode;
+import org.olat.course.nodes.CourseNodeFactory;
+import org.olat.course.nodes.WikiCourseNode;
+import org.olat.course.run.environment.CourseEnvironment;
+import org.olat.fileresource.types.WikiResource;
+import org.olat.modules.ModuleConfiguration;
+import org.olat.modules.wiki.DryRunAssessmentProvider;
+import org.olat.modules.wiki.WikiManager;
+import org.olat.modules.wiki.WikiSecurityCallback;
+import org.olat.modules.wiki.WikiSecurityCallbackImpl;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.ReferencableEntriesSearchController;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 2 Mar 2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class WikiConfigController extends FormBasicController {
+	
+	private static final String ROLE_COACH = "config.role.coach";
+	private static final String ROLE_PARTICIPANT = "config.role.participant";
+	private static final String[] EDIT_KEYS = new String[] {
+			ROLE_COACH,
+			ROLE_PARTICIPANT
+	};
+	
+	private StaticTextElement wikiNotChoosenEl;
+	private FormLink previewLink;
+	private FormLink chooseLink;
+	private FormLink replaceLink;
+	private FormLink editLink;
+	private MultipleSelectionElement editRolesEl;
+	
+	private CloseableModalController cmc;
+	private ReferencableEntriesSearchController repositorySearchCtrl;
+	private Controller wikiCtrl;
+	
+	private final BreadcrumbPanel stackPanel;
+	private final WikiCourseNode courseNode;
+	private final ModuleConfiguration config;
+	private final ICourse course;
+	private RepositoryEntry wikiEntry;
+	
+	@Autowired
+	private RepositoryService repositoryService;
+	
+	public WikiConfigController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel,
+			WikiCourseNode courseNode, ICourse course) {
+		super(ureq, wControl, LAYOUT_BAREBONE);
+		this.stackPanel = stackPanel;
+		this.courseNode = courseNode;
+		this.course = course;
+		this.config = courseNode.getModuleConfiguration();
+		this.wikiEntry = courseNode.getReferencedRepositoryEntry();
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		FormLayoutContainer generalCont = FormLayoutContainer.createDefaultFormLayout("general", getTranslator());
+		formLayout.add(generalCont);
+		generalCont.setRootForm(mainForm);
+		generalCont.setFormTitle(translate("header"));
+		generalCont.setFormContextHelp("Communication and Collaboration#_bb_wiki");
+		
+		wikiNotChoosenEl = uifactory.addStaticTextElement("chosenwiki", "chosenwiki",
+				translate("no.entry.chosen"), generalCont);
+		previewLink = uifactory.addFormLink("command.preview", "", translate("command.preview"), generalCont,
+				Link.NONTRANSLATED);
+		previewLink.setIconLeftCSS("o_icon o_icon-fw o_icon_preview");
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		buttonsCont.setRootForm(mainForm);
+		generalCont.add(buttonsCont);
+		chooseLink = uifactory.addFormLink("command.create", buttonsCont, "btn btn-default o_xsmall");
+		chooseLink.setElementCssClass("o_sel_survey_choose_repofile");
+		replaceLink = uifactory.addFormLink("command.change", buttonsCont, "btn btn-default o_xsmall");
+		editLink = uifactory.addFormLink("edit", buttonsCont, "btn btn-default o_xsmall");
+		
+		
+		if (!courseNode.hasCustomPreConditions()) {
+			FormLayoutContainer rightsCont = FormLayoutContainer.createDefaultFormLayout("rights", getTranslator());
+			formLayout.add(rightsCont);
+			rightsCont.setFormTitle(translate("config.rights"));
+			
+			editRolesEl = uifactory.addCheckboxesVertical("config.edit", rightsCont, EDIT_KEYS,
+					translateAll(getTranslator(), EDIT_KEYS), 1);
+			editRolesEl.select(ROLE_COACH,
+					config.getBooleanSafe(WikiCourseNode.CONFIG_KEY_EDIT_BY_COACH));
+			editRolesEl.select(ROLE_PARTICIPANT,
+					config.getBooleanSafe(WikiCourseNode.CONFIG_KEY_EDIT_BY_PARTICIPANT));
+			editRolesEl.addActionListener(FormEvent.ONCHANGE);
+		}
+		
+		updateUI();
+	}
+	
+	private void updateUI() {
+		boolean feedSelected = wikiEntry != null;
+		if (feedSelected) {
+			String displayname = StringHelper.escapeHtml(wikiEntry.getDisplayname());
+			previewLink.setI18nKey(displayname);
+			flc.setDirty(true);
+		}
+		wikiNotChoosenEl.setVisible(!feedSelected);
+		chooseLink.setVisible(!feedSelected);
+		previewLink.setVisible(feedSelected);
+		replaceLink.setVisible(feedSelected);
+		editLink.setVisible(feedSelected);
+	}
+	
+	@Override
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
+		if (source == chooseLink || source == replaceLink) {
+			doSelectFeed(ureq);
+		} else if (source == previewLink) {
+			doPreviewFeed(ureq);
+		} else if (source == editLink) {
+			doEditFeed(ureq);
+		} else if (source == editRolesEl) {
+			doUpdatedEditRoles(ureq);
+		}
+		super.formInnerEvent(ureq, source, event);
+	}
+	
+	@Override
+	public void event(UserRequest urequest, Controller source, Event event) {
+		if (source == repositorySearchCtrl) {
+			if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) {
+				wikiEntry = repositorySearchCtrl.getSelectedEntry();
+				if (wikiEntry != null) {
+					//TODO uh set copnfig
+					AbstractFeedCourseNode.setReference(courseNode.getModuleConfiguration(), wikiEntry);
+					WikiEditController.setWikiRepoReference(wikiEntry, config);
+					fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
+					updateUI();
+				}
+			}
+			cmc.deactivate();
+			cleanUp();
+		} else if (source == cmc) {
+			cmc.deactivate();
+			cleanUp();
+		}
+	}
+
+	private void cleanUp() {
+		removeAsListenerAndDispose(repositorySearchCtrl);
+		removeAsListenerAndDispose(wikiCtrl);
+		removeAsListenerAndDispose(cmc);
+		repositorySearchCtrl = null;
+		wikiCtrl = null;
+		cmc = null;
+	}
+	
+	private void doSelectFeed(UserRequest ureq) {
+		repositorySearchCtrl = new ReferencableEntriesSearchController(getWindowControl(), ureq, WikiResource.TYPE_NAME,
+				translate("command.choose"));
+		listenTo(repositorySearchCtrl);
+		cmc = new CloseableModalController(getWindowControl(), translate("close"),
+				repositorySearchCtrl.getInitialComponent(), true, translate("command.create"));
+		cmc.activate();
+	}
+
+	private void doPreviewFeed(UserRequest ureq) {
+		if (wikiEntry == null) {
+			showError("error.repoentrymissing");
+		} else {
+			Roles roles = ureq.getUserSession().getRoles();
+			boolean isAdministrator = (roles.isAdministrator() || roles.isLearnResourceManager())
+					&& repositoryService.hasRoleExpanded(getIdentity(), wikiEntry,
+							OrganisationRoles.administrator.name(), OrganisationRoles.learnresourcemanager.name());
+			boolean isResourceOwner = repositoryService.hasRole(getIdentity(), wikiEntry, GroupRoles.owner.name());
+			
+			CourseEnvironment cenv = course.getCourseEnvironment();
+			SubscriptionContext subsContext = WikiManager.createTechnicalSubscriptionContextForCourse(cenv, courseNode);
+			WikiSecurityCallback callback = new WikiSecurityCallbackImpl(null, isAdministrator, false, false, isResourceOwner, subsContext);
+			wikiCtrl = WikiManager.getInstance().createWikiMainController(ureq, getWindowControl(), wikiEntry.getOlatResource(),
+					callback, DryRunAssessmentProvider.create(), null);
+			listenTo(wikiCtrl);
+			stackPanel.pushController(translate("preview"), wikiCtrl);
+		}
+	}
+
+	private void doEditFeed(UserRequest ureq) {
+		if (wikiEntry == null) {
+			showError("error.repoentrymissing");
+		} else {
+			CourseNodeFactory.getInstance().launchReferencedRepoEntryEditor(ureq, getWindowControl(), courseNode);
+		}
+	}
+
+	private void doUpdatedEditRoles(UserRequest ureq) {
+		Collection<String> selectedEditKeys = editRolesEl.getSelectedKeys();
+		config.setBooleanEntry(WikiCourseNode.CONFIG_KEY_EDIT_BY_COACH, selectedEditKeys.contains(ROLE_COACH));
+		config.setBooleanEntry(WikiCourseNode.CONFIG_KEY_EDIT_BY_PARTICIPANT, selectedEditKeys.contains(ROLE_PARTICIPANT));
+		
+		fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT);
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+}
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 3f2ac3d52a47fff8a4c9dac6f15eb587b664a983..2b33f445fad53e87945bf66d94730364c2027fde 100644
--- a/src/main/java/org/olat/course/nodes/wiki/WikiEditController.java
+++ b/src/main/java/org/olat/course/nodes/wiki/WikiEditController.java
@@ -25,46 +25,28 @@
 
 package org.olat.course.nodes.wiki;
 
-import org.olat.NewControllerFactory;
-import org.olat.basesecurity.GroupRoles;
-import org.olat.basesecurity.OrganisationRoles;
-import org.olat.core.commons.services.notifications.SubscriptionContext;
 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.panel.Panel;
+import org.olat.core.gui.components.stack.BreadcrumbPanel;
 import org.olat.core.gui.components.tabbedpane.TabbedPane;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.ControllerEventListener;
 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.tabbable.ActivateableTabbableDefaultController;
-import org.olat.core.id.Roles;
 import org.olat.core.logging.AssertException;
-import org.olat.core.util.StringHelper;
 import org.olat.course.ICourse;
 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.nodes.WikiCourseNode;
-import org.olat.course.run.environment.CourseEnvironment;
 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.WikiMainController;
-import org.olat.modules.wiki.WikiManager;
-import org.olat.modules.wiki.WikiSecurityCallback;
-import org.olat.modules.wiki.WikiSecurityCallbackImpl;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
-import org.olat.repository.RepositoryService;
-import org.olat.repository.controllers.ReferencableEntriesSearchController;
-import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description: <BR/>Edit controller for single page course nodes <P/> Initial
@@ -75,204 +57,81 @@ import org.springframework.beans.factory.annotation.Autowired;
 public class WikiEditController extends ActivateableTabbableDefaultController implements ControllerEventListener {
 	public static final String PANE_TAB_ACCESSIBILITY = "pane.tab.accessibility";
 	public static final String PANE_TAB_WIKICONFIG = "pane.tab.wikiconfig";
-	public static final String PANE_TAB_WIKIDISPLAYCONFIG = "pane.tab.wikidisplayconfig";
 	
 	private static final String[] paneKeys = { PANE_TAB_WIKICONFIG, PANE_TAB_ACCESSIBILITY };
 
-	private static final String CHOSEN_ENTRY = "chosen_entry";
-	private static final String CONFIG_KEY_REPOSITORY_SOFTKEY = "reporef";
-
-	private ModuleConfiguration moduleConfiguration;	
-	private WikiCourseNode wikiCourseNode;
-	private ConditionEditController accessCondContr;
 	private TabbedPane tabs;
-	private Panel main;
-	private VelocityContainer content;
-	private ReferencableEntriesSearchController searchController;
-	private WikiMainController wikiCtr;
-	private CloseableModalController cmcWikiCtr;
-	private CloseableModalController cmcSearchController;
-	private Link previewLink;
-	private Link chooseButton;
-	private Link changeButton;
-	private Link editLink;
+	private WikiConfigController configCtrl;
 	private VelocityContainer editAccessVc;
+	private ConditionEditController accessCondCtrl;
 	private ConditionEditController editCondContr;
-	private ICourse course;
-	
-	@Autowired
-	private RepositoryService repositoryService;
 
-	/**
-	 * Constructor for wiki page editor controller
-	 * 
-	 * @param config The node module configuration
-	 * @param ureq The user request
-	 * @param wikiCourseNode The current wiki page course node
-	 * @param course
-	 */
-	public WikiEditController(ModuleConfiguration config, UserRequest ureq, WindowControl wControl, WikiCourseNode wikiCourseNode,
-			ICourse course, UserCourseEnvironment euce) {
+	private final WikiCourseNode wikiCourseNode;
+	
+	public WikiEditController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel,
+			WikiCourseNode wikiCourseNode, ICourse course, UserCourseEnvironment euce) {
 		super(ureq, wControl);
-		this.moduleConfiguration = config;
 		this.wikiCourseNode = wikiCourseNode;
-		//o_clusterOk by guido: save to hold reference to course inside editor
-		this.course = course;
 		
-		main = new Panel("wikimain");
+		configCtrl = new WikiConfigController(ureq, wControl, stackPanel, wikiCourseNode, course);
+		listenTo(configCtrl);
 		
-		content = createVelocityContainer("edit");
-		chooseButton = LinkFactory.createButtonSmall("command.create", content, this);
-		chooseButton.setElementCssClass("o_sel_wiki_choose_repofile");
-		changeButton = LinkFactory.createButtonSmall("command.change", content, this);
-		changeButton.setElementCssClass("o_sel_wiki_choose_repofile");
-				
-		editAccessVc = this.createVelocityContainer("edit_access");
-		CourseEditorTreeModel editorModel = course.getEditorTreeModel();
-		// Accessibility precondition
-		Condition accessCondition = wikiCourseNode.getPreConditionAccess();
-		accessCondContr = new ConditionEditController(ureq, getWindowControl(), euce, accessCondition,
-				AssessmentHelper.getAssessableNodes(editorModel, wikiCourseNode));		
-		listenTo(accessCondContr);
-		editAccessVc.put("readerCondition", accessCondContr.getInitialComponent());
-		
-		//wiki read / write preconditions
-		Condition editCondition = wikiCourseNode.getPreConditionEdit();
-		editCondContr = new ConditionEditController(ureq, getWindowControl(), euce, editCondition, AssessmentHelper
-				.getAssessableNodes(editorModel, wikiCourseNode));		
-		listenTo(editCondContr);
-		editAccessVc.put("editCondition", editCondContr.getInitialComponent());
-		
-
-		if (config.get(CONFIG_KEY_REPOSITORY_SOFTKEY) != null) {
-			// fetch repository entry to display the repository entry title of the
-			// chosen wiki
-			RepositoryEntry re = getWikiRepoReference(config, false);
-			if (re == null) { // we cannot display the entrie's name, because the
-				// repository entry had been deleted between the time
-				// when it was chosen here, and now				
-				this.showError("error.repoentrymissing");
-				content.contextPut("showPreviewLink", Boolean.FALSE);
-				content.contextPut(CHOSEN_ENTRY, translate("no.entry.chosen"));
-			} else {
-				// no securitycheck on wiki, editable by everybody
-				editLink = LinkFactory.createButtonSmall("edit", content, this);
-				content.contextPut("showPreviewLink", Boolean.TRUE);
-				String displayname = StringHelper.escapeHtml(re.getDisplayname());
-				previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", displayname, Link.NONTRANSLATED, content, this);
-				previewLink.setIconLeftCSS("o_icon o_icon-fw o_icon_preview");
-				previewLink.setCustomEnabledLinkCSS("o_preview");
-				previewLink.setTitle(getTranslator().translate("command.preview"));
-			}
-		} else {
-			// no valid config yet
-			content.contextPut("showPreviewLink", Boolean.FALSE);
-			content.contextPut(CHOSEN_ENTRY, translate("no.entry.chosen"));
+		if (wikiCourseNode.hasCustomPreConditions()) {
+			editAccessVc = this.createVelocityContainer("edit_access");
+			CourseEditorTreeModel editorModel = course.getEditorTreeModel();
+			// Accessibility precondition
+			Condition accessCondition = wikiCourseNode.getPreConditionAccess();
+			accessCondCtrl = new ConditionEditController(ureq, getWindowControl(), euce, accessCondition,
+					AssessmentHelper.getAssessableNodes(editorModel, wikiCourseNode));
+			listenTo(accessCondCtrl);
+			editAccessVc.put("readerCondition", accessCondCtrl.getInitialComponent());
+			
+			//wiki read / write preconditions
+			Condition editCondition = wikiCourseNode.getPreConditionEdit();
+			editCondContr = new ConditionEditController(ureq, getWindowControl(), euce, editCondition, AssessmentHelper
+					.getAssessableNodes(editorModel, wikiCourseNode));
+			listenTo(editCondContr);
+			editAccessVc.put("editCondition", editCondContr.getInitialComponent());
 		}
-
-		main.setContent(content);
 	}
 
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
-		if (source == previewLink) {				
-			doPreview(ureq);
-		} else if (source == chooseButton || source == changeButton) {
-			searchController = new ReferencableEntriesSearchController(getWindowControl(), ureq, WikiResource.TYPE_NAME, translate("command.choose"));			
-			listenTo(searchController);
-			cmcSearchController = new CloseableModalController(getWindowControl(), translate("close"), searchController.getInitialComponent(), true, translate("command.create"));
-			cmcSearchController.activate();			
-		}  else if (source == editLink) {
-			RepositoryEntry repositoryEntry = wikiCourseNode.getReferencedRepositoryEntry();
-			if (repositoryEntry == null) {
-				// do nothing
-				return;
-			}
-			String bPath = "[RepositoryEntry:" + repositoryEntry.getKey() + "][Editor:0]";
-			NewControllerFactory.getInstance().launch(bPath, ureq, getWindowControl());
-		}
+		//
 	}
 
 	@Override
-	public void event(UserRequest urequest, Controller source, Event event) {
-		if (source == searchController) {
-			cmcSearchController.deactivate();
-			// repository search controller done
-			if (event == ReferencableEntriesSearchController.EVENT_REPOSITORY_ENTRY_SELECTED) {
-				RepositoryEntry re = searchController.getSelectedEntry();				
-				if (re != null) {
-					setWikiRepoReference(re, moduleConfiguration);
-					content.contextPut("showPreviewLink", Boolean.TRUE);
-					String displayname = StringHelper.escapeHtml(re.getDisplayname());
-					previewLink = LinkFactory.createCustomLink("command.preview", "command.preview", displayname, Link.NONTRANSLATED, content, this);
-					previewLink.setIconLeftCSS("o_icon o_icon-fw o_icon_preview");
-					previewLink.setCustomEnabledLinkCSS("o_preview");
-					previewLink.setTitle(getTranslator().translate("command.preview"));
-					// no securitycheck on wiki, editable by everybody
-					editLink = LinkFactory.createButtonSmall("edit", content, this);
-					// fire event so the updated config is saved by the
-					// editormaincontroller
-					fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
-				}
-			}	// else cancelled repo search
-		} else if (source == accessCondContr) {
+	public void event(UserRequest ureq, Controller source, Event event) {
+		if (source == configCtrl) {
+			fireEvent(ureq, event);
+		} else if (source == accessCondCtrl) {
 			if (event == Event.CHANGED_EVENT) {
-				Condition cond = accessCondContr.getCondition();
+				Condition cond = accessCondCtrl.getCondition();
 				wikiCourseNode.setPreConditionAccess(cond);
-				fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
+				fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT);
 			}
 		} else if (source == editCondContr) {
 			if (event == Event.CHANGED_EVENT) {
 				Condition cond = editCondContr.getCondition();
 				wikiCourseNode.setPreConditionEdit(cond);
-				fireEvent(urequest, NodeEditController.NODECONFIG_CHANGED_EVENT);
+				fireEvent(ureq, NodeEditController.NODECONFIG_CHANGED_EVENT);
 			}
-		} else if (source == cmcWikiCtr) {
-			if (event == CloseableModalController.CLOSE_MODAL_EVENT) {
-				cmcWikiCtr.dispose();
-				wikiCtr.dispose();
-			}
-		} 
-	}
-	
-	private void doPreview(UserRequest ureq) {
-		// Preview as modal dialogue only if the config is valid		
-		RepositoryEntry re = getWikiRepoReference(moduleConfiguration, false);
-		if (re == null) { // we cannot preview it, because the repository entry
-			// had been deleted between the time when it was
-			// chosen here, and now				
-			showError("error.repoentrymissing");
-		} else {
-			Roles roles = ureq.getUserSession().getRoles();
-			boolean isAdministrator = (roles.isAdministrator() || roles.isLearnResourceManager())
-					&& repositoryService.hasRoleExpanded(getIdentity(), re,
-							OrganisationRoles.administrator.name(), OrganisationRoles.learnresourcemanager.name());
-			boolean isResourceOwner = repositoryService.hasRole(getIdentity(), re, GroupRoles.owner.name());
-			
-			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);
-			cmcWikiCtr = new CloseableModalController(getWindowControl(), translate("command.close"), wikiCtr.getInitialComponent());				
-			listenTo(cmcWikiCtr);
-			cmcWikiCtr.activate();
 		}
 	}
 
 	@Override
 	public void addTabs(TabbedPane tabbedPane) {
 		tabs = tabbedPane;
-		tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), editAccessVc);
-		tabbedPane.addTab(translate(PANE_TAB_WIKICONFIG), main);
+		if (editAccessVc != null) {
+			tabbedPane.addTab(translate(PANE_TAB_ACCESSIBILITY), editAccessVc);
+			
+		}
+		tabbedPane.addTab(translate(PANE_TAB_WIKICONFIG), configCtrl.getInitialComponent());
 	}
 
 	@Override
 	protected void doDispose() {
-    //child controllers registered with listenTo() get disposed in BasicController
-		if (wikiCtr != null) {
-			wikiCtr.dispose();
-			wikiCtr = null;
-		}		
+		//
 	}
 
 	@Override
@@ -295,7 +154,7 @@ public class WikiEditController extends ActivateableTabbableDefaultController im
 	 */
 	public static RepositoryEntry getWikiRepoReference(ModuleConfiguration config, boolean strict) {
 		if (config == null) throw new AssertException("missing config in wiki course node");
-		String repoSoftkey = (String) config.get(WikiEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
+		String repoSoftkey = (String) config.get(WikiCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY);
 		if (repoSoftkey == null) throw new AssertException("invalid config when being asked for references");
 		RepositoryManager rm = RepositoryManager.getInstance();
 		return rm.lookupRepositoryEntryBySoftkey(repoSoftkey, strict);
@@ -307,7 +166,7 @@ public class WikiEditController extends ActivateableTabbableDefaultController im
 	 * @param moduleConfiguration
 	 */
 	public static void setWikiRepoReference(RepositoryEntry re, ModuleConfiguration moduleConfiguration) {
-		moduleConfiguration.set(CONFIG_KEY_REPOSITORY_SOFTKEY, re.getSoftkey());
+		moduleConfiguration.set(WikiCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY, re.getSoftkey());
 	}
 	
 	/**
@@ -315,7 +174,7 @@ public class WikiEditController extends ActivateableTabbableDefaultController im
 	 * @return boolean
 	 */
 	public static boolean isModuleConfigValid(ModuleConfiguration moduleConfiguration) {
-		return (moduleConfiguration.get(CONFIG_KEY_REPOSITORY_SOFTKEY) != null);
+		return (moduleConfiguration.get(WikiCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY) != null);
 	}
 
 	
@@ -332,7 +191,7 @@ public class WikiEditController extends ActivateableTabbableDefaultController im
 			if (strict) throw new AssertException("missing config in Wiki");
 			else return null;
 		}
-		String repoSoftkey = (String) config.get(WikiEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
+		String repoSoftkey = (String) config.get(WikiCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY);
 		if (repoSoftkey == null) {
 			if (strict) throw new AssertException("invalid config when being asked for references");
 			else return null;
@@ -346,7 +205,7 @@ public class WikiEditController extends ActivateableTabbableDefaultController im
 	 * @param moduleConfig
 	 */
 	public static void removeWikiReference(ModuleConfiguration moduleConfig) {
-		moduleConfig.remove(WikiEditController.CONFIG_KEY_REPOSITORY_SOFTKEY);
+		moduleConfig.remove(WikiCourseNode.CONFIG_KEY_REPOSITORY_SOFTKEY);
 	}
 	
 }
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 0000000000000000000000000000000000000000..afc381a9319d6428c6bf70aa4d9a5919de1634c3
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/wiki/WikiLearningPathNodeHandler.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.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) {
+		if (courseNode instanceof WikiCourseNode) {
+			((WikiCourseNode)courseNode).removeCustomPreconditions();
+		}
+	}
+
+}
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 16e5eecb6afda3991554b937094b30ba03e45b9e..c34a609dee8f55a2a7c22aa8231eecc98efe3266 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,20 @@ 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);
+			Boolean courseEditRight = Boolean.valueOf(hasEditRights(wikiCourseNode, userCourseEnv, ne));
+			callback = new WikiSecurityCallbackImpl(courseEditRight, 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 +129,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);
 
@@ -145,6 +156,20 @@ public class WikiRunController extends BasicController implements Activateable2
 			putInitialPanel(new Panel("uups.no.clone.controller"));			
 		}
 	}
+	
+	private boolean hasEditRights(WikiCourseNode courseNode, UserCourseEnvironment userCourseEnv, NodeEvaluation ne) {
+		if (courseNode.hasCustomPreConditions()) {
+			return ne.isCapabilityAccessible(WikiCourseNode.EDIT_CONDITION);
+		}
+		
+		ModuleConfiguration moduleConfig = courseNode.getModuleConfiguration();
+		if ((moduleConfig.getBooleanSafe(WikiCourseNode.CONFIG_KEY_EDIT_BY_COACH) && userCourseEnv.isCoach())
+				|| (moduleConfig.getBooleanSafe(WikiCourseNode.CONFIG_KEY_EDIT_BY_PARTICIPANT) && userCourseEnv.isParticipant())) {
+			return true;
+		}
+		
+		return false;
+	}
 
 	@Override
 	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
diff --git a/src/main/java/org/olat/course/nodes/wiki/_content/edit.html b/src/main/java/org/olat/course/nodes/wiki/_content/edit.html
deleted file mode 100644
index e89831383cd0b16a45d9ecb7ddda545cde085b3f..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/course/nodes/wiki/_content/edit.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<fieldset class="o_form form-horizontal clearfix">
-	<legend>$r.contextHelpWithWrapper("Communication and Collaboration#_bb_wiki")
-	$r.translate("header")</legend>
-	
-	#if ($showPreviewLink)
-		<div class="form-group">
-			<label class="control-label col-sm-3">$r.translate("chosenwiki")</label>
-			<div class="col-sm-9"><p class="form-control-static">$r.render("command.preview")</p></div>
-		</div>
-		<div class="form-group">
-			<div class="col-sm-offset-3 col-sm-9">
-			$r.render("command.change")	 	
-			#if($r.available("edit"))
-				$r.render("edit")
-			#end
-			</div>
-		</div>
-	#else
-	    <div class="form-group">
-			<label class="control-label col-sm-3">$r.translate("chosenwiki")</label>
-			<div class="col-sm-9"><p class="form-control-static">$chosen_entry</p></div>
-		</div>
-		<div class="form-group">
-			<div class="col-sm-offset-3 col-sm-9">$r.render("command.create")</div>
-		</div>	
-	#end	
-</fieldset>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ar.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ar.properties
index ae1be6ecc8ea615df419d7eec1925106be4e40cd..9370bf7489ad38594ebb4eb6305654981c4ceb4e 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ar.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ar.properties
@@ -56,7 +56,6 @@
 chosenwiki=\u0627\u0644\u0648\u064A\u0643\u0649 \u0627\u0644\u0645\u062D\u062F\u062F
 command.change=\u0627\u0633\u062A\u0628\u062F\u0627\u0644 \u0627\u0644\u0648\u064A\u0643\u0649
 command.choose=\u0627\u062E\u062A\u064A\u0627\u0631 \u0648\u064A\u0643\u0649
-command.close=\u0625\u063A\u0644\u0627\u0642 \u0627\u0644\u0639\u0631\u0636
 command.create=\u0627\u062E\u062A\u064A\u0627\u0631 \u0623\u0648 \u0625\u0646\u0634\u0627\u0621 \u0623\u0648 \u0627\u0633\u062A\u064A\u0631\u0627\u062F \u0648\u064A\u0643\u0649
 command.preview=\u0639\u0631\u0636 \u0627\u0644\u0645\u0639\u0627\u064A\u0646\u0629
 command.show=\u0639\u0631\u0636 \u0627\u0644\u0648\u064A\u0643\u0649
@@ -77,4 +76,3 @@ header=\u0627\u062E\u062A\u064A\u0627\u0631 \u0648\u064A\u0643\u0649
 no.entry.chosen=<i>\u0644\u0645 \u064A\u062A\u0645 \u0627\u062E\u062A\u064A\u0627\u0631 \u0623\u0649 \u0648\u064A\u0643\u0649</i>
 pane.tab.accessibility=\u0648\u0635\u0648\u0644
 pane.tab.wikiconfig=\u0645\u062D\u062A\u0648\u0649 \u0627\u0644\u0648\u064A\u0643\u0649 \u0627\u0644\u062A\u0639\u0644\u064A\u0645\u0649
-pane.tab.wikidisplayconfig=\u0639\u0631\u0636
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_bg.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_bg.properties
index ddb87c48176c791ad4b600842ace43c2c685df0b..41e72cf5f3e666c3b697e4ca12a77f2303ffefcf 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_bg.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_bg.properties
@@ -56,7 +56,6 @@
 chosenwiki=\u0418\u0437\u0431\u0440\u0430\u043D\u043E \u0423\u0438\u043A\u0438
 command.change=\u0421\u043C\u0435\u043D\u0435\u0442\u0435 \u0423\u0438\u043A\u0438
 command.choose=\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0423\u0438\u043A\u0438
-command.close=\u0417\u0430\u0442\u0432\u043E\u0440\u0435\u0442\u0435 \u043F\u0440\u043E\u0437\u043E\u0440\u0435\u0446
 command.preview=\u041F\u043E\u043A\u0430\u0436\u0435\u0442\u0435 \u043F\u0440\u0435\u0433\u043B\u0435\u0434
 command.show=\u041F\u043E\u043A\u0430\u0436\u0435\u0442\u0435 \u0423\u0438\u043A\u0438
 command.showpopup=\u041F\u043E\u043A\u0430\u0436\u0435\u0442\u0435 \u0423\u0438\u043A\u0438 \u0432 \u043D\u043E\u0432 \u043F\u0440\u043E\u0437\u043E\u0440\u0435\u0446
@@ -76,4 +75,3 @@ header=\u0418\u0437\u0431\u0435\u0440\u0435\u0442\u0435 \u0423\u0438\u043A\u0438
 no.entry.chosen=<i>\u041D\u0435 \u0435 \u0438\u0437\u0431\u0440\u0430\u043D\u043E \u0423\u0438\u043A\u0438</i>
 pane.tab.accessibility=\u0414\u043E\u0441\u0442\u044A\u043F
 pane.tab.wikiconfig=\u0423\u0438\u043A\u0438 \u0443\u0447\u0435\u0431\u043D\u043E \u0441\u044A\u0434\u044A\u0440\u0436\u0430\u043D\u0438\u0435
-pane.tab.wikidisplayconfig=\u041F\u043E\u043A\u0430\u0436\u0435\u0442\u0435
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_cs.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_cs.properties
index cbd2d7a3881624591e5fe4bed8320273b5ad43e3..f2e11dacc264cf2c350ebc5c0bea2e44e48babc7 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_cs.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_cs.properties
@@ -46,7 +46,6 @@
 chosenwiki=Vybran\u00FD Wiki studijn\u00ED materi\u00E1l
 command.change=P\u0159esunout studijn\u00ED materi\u00E1l Wiki
 command.choose=Vybrat studijn\u00ED materi\u00E1l Wiki
-command.close=Zav\u0159\u00EDt n\u00E1hled
 command.preview=N\u00E1hled
 command.show=Zobrazit studijn\u00ED materi\u00E1l Wiki
 command.showpopup=Zobrazit studijn\u00ED materi\u00E1l Wiki v nov\u00E9m okn\u011B
@@ -66,4 +65,3 @@ header=Vyberte studijn\u00ED materi\u00E1l Wiki
 no.entry.chosen=<i>\u017D\u00E1dn\u00FD Wiki studijn\u00ED materi\u00E1l nebyl vybr\u00E1n</i>
 pane.tab.accessibility=P\u0159\u00EDstup
 pane.tab.wikiconfig=Studijn\u00ED materi\u00E1l
-pane.tab.wikidisplayconfig=Zobrazit
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_da.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_da.properties
index 72adff973d251245ffb619a3d292736bd2a53e2d..af07f5e41053e137f06fb39d7f5711ced5dc0fff 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_da.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_da.properties
@@ -46,7 +46,6 @@
 chosenwiki=Valgte Wiki
 command.change=Erstat Wiki
 command.choose=V\u00E6lg Wiki
-command.close=Luk 
 command.preview=Forh\u00E5ndsvisning
 command.show=Vis wiki
 command.showpopup=Vis Wiki i et nyt vindue
@@ -64,4 +63,3 @@ header=V\u00E6lg Wiki
 no.entry.chosen=<i>Ingen Wiki er valgt</i>
 pane.tab.accessibility=Adgange
 pane.tab.wikiconfig=L\u00E6ringsindhold
-pane.tab.wikidisplayconfig=Visning
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_de.properties
index 6234681ba7cb5972cc51a062dd6c1380c7546ccf..fe4ba6f3d2f3e68f82349552199932114f0f9099 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_de.properties
@@ -58,12 +58,15 @@ chosenwiki=Gew\u00E4hltes Wiki
 command.change=Wiki auswechseln
 command.create=Wiki w\u00E4hlen, erstellen oder importieren
 command.choose=Wiki w\u00E4hlen
-command.close=Ansicht schliessen
 command.preview=Vorschau anzeigen
 command.show=Wiki anzeigen
 command.showpopup=Wiki in neuem Fenster anzeigen
 condition.accessibility.title=Zugang
 condition.editable.title=Artikel bearbeiten / erstellen
+config.edit=Artikel bearbeiten
+config.rights=Benutzerberechtigungen
+config.role.coach=Betreuer
+config.role.participant=Teilnehmer
 display.config=Wiki-Menu in Kursmenu?
 display.config.fieldsettitle=Konfiguration
 error.launch=Wiki konnte nicht gestartet werden.
@@ -78,4 +81,4 @@ header=Wiki ausw\u00E4hlen
 no.entry.chosen=<i>Kein Wiki ausgew\u00E4hlt</i>
 pane.tab.accessibility=Zugang
 pane.tab.wikiconfig=Wiki-Lerninhalt
-pane.tab.wikidisplayconfig=Anzeige
+preview=Vorschau
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_el.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_el.properties
index 3c58e3a5346983d6a2bcbef2156b672402d116f0..29caf6bb8de81347876f9789615a04e9a5af2f36 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_el.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_el.properties
@@ -44,7 +44,6 @@
 chosenwiki=\u0395\u03C0\u03B9\u03BB\u03B5\u03B3\u03BC\u03AD\u03BD\u03BF Wiki 
 command.change=\u0391\u03BD\u03C4\u03B9\u03BA\u03B1\u03C4\u03AC\u03C3\u03C4\u03B1\u03C3\u03B7 Wiki 
 command.choose=\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE Wiki 
-command.close=\u039A\u03BB\u03B5\u03AF\u03C3\u03B9\u03BC\u03BF \u03B5\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7\u03C2
 command.create=\u0395\u03C0\u03B9\u03BB\u03BF\u03B3\u03AE, \u03B4\u03B7\u03BC\u03B9\u03BF\u03C5\u03C1\u03B3\u03AF\u03B1 \u03AE \u03B5\u03B9\u03C3\u03B1\u03B3\u03C9\u03B3\u03AE Wiki
 command.preview=\u0395\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7 \u03C0\u03C1\u03BF\u03B5\u03C0\u03B9\u03C3\u03BA\u03CC\u03C0\u03B7\u03C3\u03B7\u03C2
 command.show=\u0395\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7 Wiki
@@ -65,5 +64,4 @@ header=Select Wiki
 no.entry.chosen=<i>\u0394\u03B5\u03BD \u03B5\u03C0\u03B9\u03BB\u03AD\u03C7\u03C4\u03B7\u03BA\u03B5 Wiki</i>
 pane.tab.accessibility=\u03A0\u03C1\u03CC\u03C3\u03B2\u03B1\u03C3\u03B7
 pane.tab.wikiconfig=\u03A0\u03B5\u03C1\u03B9\u03B5\u03C7\u03CC\u03BC\u03B5\u03BD\u03BF \u03BC\u03AC\u03B8\u03B7\u03C3\u03B7\u03C2 Wiki
-pane.tab.wikidisplayconfig=\u0395\u03BC\u03C6\u03AC\u03BD\u03B9\u03C3\u03B7
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_en.properties
index 4854ff5f1a3b73d003775bbd1f2fd6b27d7d5598..46efef79f42e60294d494193c3d9aa278c1a68f0 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_en.properties
@@ -56,13 +56,16 @@
 chosenwiki=Selected Wiki 
 command.change=Replace Wiki 
 command.choose=Choose Wiki 
-command.close=Close view
 command.create=Choose, create or import Wiki
 command.preview=Show preview
 command.show=Show Wiki
 command.showpopup=Show Wiki in new window
 condition.accessibility.title=Access
 condition.editable.title=Create/edit material
+config.edit=Edit Material
+config.rights=User rights
+config.role.coach=Coach
+config.role.participant=Participant
 display.config=Wiki menu in course menu?
 display.config.fieldsettitle=Configuration
 error.launch=Unable to start Wiki.
@@ -77,5 +80,5 @@ header=Select Wiki
 no.entry.chosen=<i>No Wiki selected</i>
 pane.tab.accessibility=Access
 pane.tab.wikiconfig=Wiki learning content
-pane.tab.wikidisplayconfig=Display
+preview=Preview
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_es.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_es.properties
index 94cf7cc6b867624c05704007eaeab3bff2f65699..682449ce885f3a34309aa527f9c558bb279705e5 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_es.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_es.properties
@@ -56,7 +56,6 @@
 chosenwiki=Contenido did\u00E1ctico Wiki elegido
 command.change=Substituye contenido did\u00E1ctico Wiki
 command.choose=Elige contenido did\u00E1ctico Wiki
-command.close=Cerrar
 command.preview=Mostrar vista previa
 command.show=Muesta contenido did\u00E1ctico Wiki
 command.showpopup=Muesta contenido did\u00E1ctico Wiki en p\u00E1gina nueva
@@ -76,4 +75,3 @@ header=Elegir contenido did\u00E1ctico Wiki
 no.entry.chosen=<i>Ningun Wiki fue elegido</i>
 pane.tab.accessibility=Acceso
 pane.tab.wikiconfig=Contenido did\u00E1ctico Wiki
-pane.tab.wikidisplayconfig=Presentaci\u00F3n
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_fr.properties
index 41050b51542c9109547946e437b2d6057bedac03..00a38486739dcca65c4fe5bf8c28c0c5bc67c040 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_fr.properties
@@ -56,7 +56,6 @@
 chosenwiki=Wiki s\u00E9lectionn\u00E9
 command.change=Remplacer wiki
 command.choose=Choisir wiki
-command.close=Fermer aper\u00E7u
 command.create=S\u00E9lectionner, cr\u00E9er ou importer wiki
 command.preview=Afficher aper\u00E7u
 command.show=Afficher wiki
@@ -77,5 +76,4 @@ header=Choisir wiki
 no.entry.chosen=<i>aucun wiki s\u00E9lectionn\u00E9</i>
 pane.tab.accessibility=Acc\u00E8s
 pane.tab.wikiconfig=Contenu didactique Wiki
-pane.tab.wikidisplayconfig=Affichage
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_it.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_it.properties
index d2d460f8acb4ea02a11a8f263004efde31f07966..1ae98b73b6626bfa952c51dbf9f8210c27ffec72 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_it.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_it.properties
@@ -56,7 +56,6 @@
 chosenwiki=Wiki selezionato
 command.change=Sostituire wiki
 command.choose=Selezionare wiki
-command.close=Chiudere
 command.create=Selezionare, creare o importare un wiki
 command.preview=Mostrare anteprima
 command.show=Mostrare wiki
@@ -77,5 +76,4 @@ header=Selezione del wiki
 no.entry.chosen=<i>Nessun wiki selezionato</i>
 pane.tab.accessibility=Accesso
 pane.tab.wikiconfig=Contenuto didattico wiki
-pane.tab.wikidisplayconfig=Visualizzazione
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_jp.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_jp.properties
index 621e7525db2cedccf216545da918680dcf341acc..5e2e82940af476dc9dc9b34f8bbc8610a343fb65 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_jp.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_jp.properties
@@ -48,7 +48,6 @@
 chosenwiki=\u9078\u629E\u6E08\u307FWiki
 command.change=Wiki\u3092\u7F6E\u63DB\u3059\u308B
 command.choose=Wiki\u3092\u9078\u629E\u3059\u308B
-command.close=\u30D3\u30E5\u30FC\u3092\u9589\u3058\u308B
 command.create=Wik\u3092\u9078\u629E\u3001\u4F5C\u6210\u307E\u305F\u306F\u30A4\u30F3\u30DD\u30FC\u30C8\u3059\u308B
 command.preview=\u30D7\u30EC\u30D3\u30E5\u30FC\u3092\u8868\u793A\u3059\u308B
 command.show=Wiki\u3092\u8868\u793A\u3059\u308B
@@ -68,4 +67,3 @@ header=Wiki\u3092\u9078\u629E\u3059\u308B
 no.entry.chosen=<i>Wiki\u304C\u9078\u629E\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002</i>
 pane.tab.accessibility=\u30A2\u30AF\u30BB\u30B9
 pane.tab.wikiconfig=Wiki\u5B66\u7FD2\u30B3\u30F3\u30C6\u30F3\u30C4
-pane.tab.wikidisplayconfig=\u8868\u793A
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_lt.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_lt.properties
index 92e06495ff113f38fff6f8fa276d6da96f2c6855..f6ac75e26efca1f91d4decd2dedea4c3d94a9f6c 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_lt.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_lt.properties
@@ -18,7 +18,6 @@
 chosenwiki=Pasirinktas turinys
 command.change=Wiki mokymo turin\u012F pakeisti kitu
 command.choose=Pasirinkti Wiki mokymo turin\u012F
-command.close=U\u017Edaryti 
 command.preview=Per\u017Ei\u016Bra
 command.show=Rodyti Wiki mokymo turin\u012F
 command.showpopup=Wiki mokymo turin\u012F rodyti naujame lange 
@@ -35,4 +34,3 @@ header=I\u0161rinkite Wiki mokymo turin\u012F
 no.entry.chosen=<i>Turinys nepasirinktas</i>
 pane.tab.accessibility=Prieiga
 pane.tab.wikiconfig=Mokymo turinys 
-pane.tab.wikidisplayconfig=Pavaizduoti 
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_nl_NL.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_nl_NL.properties
index bfcf630df581065fb562709e9d5abf23e38b33bd..da733aba2da086fb9d3016f8523f196d06ddd1f8 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_nl_NL.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_nl_NL.properties
@@ -56,7 +56,6 @@
 chosenwiki=Selecteer Wiki
 command.change=Vervang Wiki
 command.choose=Kies Wiki
-command.close=Sluit weergave
 command.create=Eem Wiki kiezen, aanmaken of importeren
 command.preview=Toon voorvertoning
 command.show=Toon Wiki
@@ -77,5 +76,4 @@ header=Selecteer Wiki
 no.entry.chosen=<i>Geen Wiki geselecteerd</i>
 pane.tab.accessibility=Toegang
 pane.tab.wikiconfig=Wiki leerinhoud
-pane.tab.wikidisplayconfig=Weergave
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pl.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pl.properties
index 2cc891758b831b410d33bacd7a88fdc969e5d787..fd16d7f2eb7eddb3f46b9c5f21948c4ee93fb7b3 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pl.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pl.properties
@@ -56,7 +56,6 @@
 chosenwiki=Wybrany portal Wiki
 command.change=Zmie\u0144 portal Wiki
 command.choose=Wybierz portal Wiki
-command.close=Zamknij widok
 command.create=Wybierz, utw\u00F3rz lub zaimportuj Wiki
 command.preview=Podgl\u0105d
 command.show=Poka\u017C portal Wiki
@@ -77,5 +76,4 @@ header=Wybierz portal Wiki
 no.entry.chosen=<i>Portal Wiki nie zosta\u0142 wybrany</i>
 pane.tab.accessibility=Dost\u0119p
 pane.tab.wikiconfig=Konfiguracja Wiki
-pane.tab.wikidisplayconfig=Wy\u015Bwietl
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_BR.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_BR.properties
index 5705a0c5b0516ee1730f8df45d71ba45e70a849a..7900e647dfe201f2615cbf5c3cc66a8287ffeebf 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_BR.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_BR.properties
@@ -56,7 +56,6 @@
 chosenwiki=Conte\u00FAdo did\u00E1tico Wiki selecionado
 command.change=Substituir conte\u00FAdo did\u00E1tico Wiki
 command.choose=Escolher conte\u00FAdo did\u00E1tico Wiki
-command.close=Fechar visualiza\u00E7\u00E3o
 command.create=<b>Data de vencimento</b> Data de in\u00EDcio
 command.preview=Visualiza\u00E7\u00E3o
 command.show=Exibir conte\u00FAdo did\u00E1tico Wiki
@@ -77,5 +76,4 @@ header=Escolher conte\u00FAdo did\u00E1tico Wiki
 no.entry.chosen=<i>Nenhum conte\u00FAdo did\u00E1tico Wiki selecionado</i>
 pane.tab.accessibility=Acesso
 pane.tab.wikiconfig=Conte\u00FAdo did\u00E1tico
-pane.tab.wikidisplayconfig=Exibir
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_PT.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_PT.properties
index 1176f6fb07e70ba2dfad5ad26d086405c41e38d1..e425d8bbf0220889fde16b7d2f640a63916e8520 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_PT.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_pt_PT.properties
@@ -46,7 +46,6 @@
 chosenwiki=Conte\u00FAdo did\u00E1tico Wiki selecionado
 command.change=Substituir conte\u00FAdo did\u00E1tico Wiki
 command.choose=Escolher conte\u00FAdo did\u00E1tico Wiki
-command.close=Fechar visualiza\u00E7\u00E3o
 command.preview=Visualiza\u00E7\u00E3o
 command.show=Exibir conte\u00FAdo did\u00E1tico Wiki
 command.showpopup=Exibir conte\u00FAdo did\u00E1tico Wiki em nova janela
@@ -64,4 +63,3 @@ header=Escolher conte\u00FAdo did\u00E1tico Wiki
 no.entry.chosen=<i>Nenhum conte\u00FAdo did\u00E1tico Wiki selecionado</i>
 pane.tab.accessibility=Acesso
 pane.tab.wikiconfig=Conte\u00FAdo did\u00E1tico
-pane.tab.wikidisplayconfig=Exibir
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ru.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ru.properties
index b1bcc43af2fa79e6edf0469da4c3058635d13bfc..09de776218f02b2f638c7a757e71d7e10dd3dc0c 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ru.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_ru.properties
@@ -18,7 +18,6 @@
 chosenwiki=\u0412\u044B\u0431\u0440\u0430\u043D\u043D\u0430\u044F \u0432\u0438\u043A\u0438
 command.change=\u0417\u0430\u043C\u0435\u043D\u0438\u0442\u044C \u0432\u0438\u043A\u0438  
 command.choose=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0438\u043A\u0438
-command.close=\u0417\u0430\u043A\u0440\u044B\u0442\u044C \u043F\u043E\u043A\u0430\u0437
 command.create=\u0412\u044B\u0431\u0440\u0430\u0442\u044C, \u0441\u043E\u0437\u0434\u0430\u0442\u044C \u0438\u043B\u0438 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0412\u0438\u043A\u0438
 command.preview=\u041F\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0439 \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440
 command.show=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0432\u0438\u043A\u0438
@@ -39,4 +38,3 @@ header=\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0438\u043A\u0438
 no.entry.chosen=<i>\u041D\u0435 \u0431\u044B\u043B\u043E \u0432\u044B\u0431\u0440\u0430\u043D\u043E \u043D\u0438 \u043E\u0434\u043D\u043E\u0439 \u0432\u0438\u043A\u0438</i>
 pane.tab.accessibility=\u0414\u043E\u0441\u0442\u0443\u043F
 pane.tab.wikiconfig=\u0423\u0447\u0435\u0431\u043D\u043E\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u043D\u0438\u0435 \u0432\u0438\u043A\u0438
-pane.tab.wikidisplayconfig=\u041F\u043E\u043A\u0430\u0437
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_sq.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_sq.properties
index c7420030152451821ed377e55a897562eb12f340..b28c1d5fdfc20c0704e55a93bca8a223edf90c3d 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_sq.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_sq.properties
@@ -18,7 +18,6 @@
 chosenwiki=Wiki t\u00EB p\u00EBrzgjedhur
 command.change=Z\u00EBvend\u00EBso Wiki 
 command.choose=P\u00EBrzgjedh Wiki 
-command.close=Mbylle pamjen
 command.preview=Paraafisho
 command.show=Shfaq Wiki
 command.showpopup=Shfaq Wiki n\u00EB nj\u00EB dritare t\u00EB re
@@ -36,4 +35,3 @@ header=P\u00EBrzgjedh Wiki
 no.entry.chosen=<i>Asjnj\u00EB Wiki t\u00EB p\u00EBrzgjedhur</i>
 pane.tab.accessibility=Qasshm\u00EBria 
 pane.tab.wikiconfig=P\u00EBrmbajtje m\u00EBsimi
-pane.tab.wikidisplayconfig=Shfaq
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_CN.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_CN.properties
index 530939bf702459b033cfe37d22408fa9d11e6040..f009bb4acf19fbb369818f1aebbcde870fc5737f 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_CN.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_CN.properties
@@ -56,7 +56,6 @@
 chosenwiki=\u9009\u4E2D\u7684Wiki\u5B66\u4E60\u5185\u5BB9
 command.change=\u66FF\u6362Wiki\u5B66\u4E60\u5185\u5BB9
 command.choose=\u9009\u62E9Wiki\u5B66\u4E60\u5185\u5BB9
-command.close=\u5173\u95ED\u89C6\u56FE
 command.create=\u9009\u62E9\uFF0C\u521B\u5EFA\u6216\u8005\u5BFC\u5165\u7EF4\u57FA
 command.preview=\u9884\u89C8
 command.show=\u663E\u793AWiki\u5B66\u4E60\u5185\u5BB9
@@ -77,4 +76,3 @@ header=\u9009\u62E9Wiki\u5B66\u4E60\u5185\u5BB9
 no.entry.chosen=<i>\u6CA1\u6709\u9009\u62E9\u4EFB\u4F55Wiki\u5B66\u4E60\u5185\u5BB9</i>
 pane.tab.accessibility=\u8BBF\u95EE
 pane.tab.wikiconfig=\u5B66\u4E60\u5185\u5BB9
-pane.tab.wikidisplayconfig=\u663E\u793A
diff --git a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_TW.properties b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_TW.properties
index bbbd4891c006ef3eb3961cf1723b401e05ffb4f2..c5c68efd3f3164b4a228c9f83b32674867cca210 100644
--- a/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_TW.properties
+++ b/src/main/java/org/olat/course/nodes/wiki/_i18n/LocalStrings_zh_TW.properties
@@ -27,7 +27,6 @@
 chosenwiki=\u9078\u53D6\u7684 Wiki 
 command.change=\u53D6\u4EE3 Wiki 
 command.choose=\u9078\u53D6 Wiki 
-command.close=\u95DC\u9589\u8996\u7A97
 command.preview=\u986F\u793A\u9810\u89BD
 command.show=\u986F\u793A Wiki
 command.showpopup=\u5728\u65B0\u8996\u7A97\u986F\u793A Wiki
@@ -47,5 +46,4 @@ header=\u9078\u64C7 Wiki
 no.entry.chosen=<i>\u6C92\u6709 Wiki \u88AB\u9078\u53D6</i>
 pane.tab.accessibility=\u5B58\u53D6
 pane.tab.wikiconfig=Wiki \u5B78\u7FD2\u5167\u5BB9
-pane.tab.wikidisplayconfig=\u986F\u793A
 title_wiki=Wiki
diff --git a/src/main/java/org/olat/course/run/RunMainController.java b/src/main/java/org/olat/course/run/RunMainController.java
index 36cd0d817bb844c869ad41070353ac5f394b4d84..f19c6a4cdbb22d007d70f8abbf82168ba59c674b 100644
--- a/src/main/java/org/olat/course/run/RunMainController.java
+++ b/src/main/java/org/olat/course/run/RunMainController.java
@@ -371,11 +371,17 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 		needsRebuildAfterRunDone = true;
 	}
 	
-	private CourseNode updateAfterChanges(CourseNode courseNode) {
+	/**
+	 * 
+	 * @param courseNode
+	 * @param selectedNodeId my be the nodeId of a node of the subtree
+	 * @return
+	 */
+	private CourseNode updateAfterChanges(CourseNode courseNode, String selectedNodeId) {
 		if(currentCourseNode == null) return null;
 		
 		CourseNode newCurrentCourseNode;
-		NodeClickedRef nclr = navHandler.reloadTreeAfterChanges(courseNode);
+		NodeClickedRef nclr = navHandler.reloadTreeAfterChanges(courseNode, selectedNodeId);
 		if(nclr == null) {
 			doDisposeAfterEvent();
 			newCurrentCourseNode = null;
@@ -528,10 +534,12 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 			boolean showDone = false;
 			if (calledCourseNode != null) {
 				TreeNode treeNode = treeModel.getNodeById(calledCourseNode.getIdent());
-				boolean confirmationEnabled = nodeAccessService.isAssessmentConfirmationEnabled(calledCourseNode, getUce());
-				AssessmentEvaluation assessmentEvaluation = getUce().getScoreAccounting().evalCourseNode(calledCourseNode);
-				confirmVisible = confirmationEnabled && treeNode.isAccessible();
-				showDone = !Boolean.TRUE.equals(assessmentEvaluation.getFullyAssessed());
+				if (treeNode != null) {
+					boolean confirmationEnabled = nodeAccessService.isAssessmentConfirmationEnabled(calledCourseNode, getUce());
+					AssessmentEvaluation assessmentEvaluation = getUce().getScoreAccounting().evalCourseNode(calledCourseNode);
+					confirmVisible = confirmationEnabled && treeNode.isAccessible();
+					showDone = !Boolean.TRUE.equals(assessmentEvaluation.getFullyAssessed());
+				}
 			}
 			paginationCtrl.updateAssessmentConfirmUI(confirmVisible, showDone);
 			updateProgressUI();
@@ -582,7 +590,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if(needsRebuildAfter) {
-			currentCourseNode = updateAfterChanges(currentCourseNode);
+			currentCourseNode = updateAfterChanges(currentCourseNode, currentCourseNode.getIdent());
 			needsRebuildAfter = false;
 		}
 		
@@ -643,7 +651,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if(needsRebuildAfter) {
-			currentCourseNode = updateAfterChanges(currentCourseNode);
+			currentCourseNode = updateAfterChanges(currentCourseNode, currentCourseNode.getIdent());
 			needsRebuildAfter = false;
 		}
 		
@@ -734,7 +742,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 	
 	private void doAssessmentConfirmation(boolean confirmed) {
 		nodeAccessService.onAssessmentConfirmed(getCurrentCourseNode(), getUce(), confirmed);
-		updateAfterChanges(getCurrentCourseNode());
+		updateAfterChanges(getCurrentCourseNode(), luTree.getSelectedNodeId());
 		updateAssessmentConfirmUI(getCurrentCourseNode());
 	}
 
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 376a2307c823b8fb25f8b861faaef6076ba456b6..d5368bf3906c801df6a35c52162b92b9bf2b71cb 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;
@@ -187,8 +188,6 @@ public class NavigationHandler implements Disposable {
 			}
 		} else {
 			// Use the subtreemodelhandler
-			Object userObject = selTN.getUserObject();
-			
 			NodeRunConstructionResult nrcr = null;
 			CourseNode internCourseNode = null;
 			GenericTreeModel subTreeModel;
@@ -229,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);
 					}
@@ -239,45 +241,35 @@ public class NavigationHandler implements Disposable {
 				log.debug("delegating to handler: treeNodeId = " + treeNodeId);
 			}
 
-			// Update the node and event to match the new tree model - unless we
-			// are already on the correct node to prevent jumping to other
-			// chapters in CP's when the href (userObject) is not unique and
-			// used in multiple nodes. 
-			if (!userObject.equals(selTN.getUserObject())) {
-				selTN = subTreeModel.findNodeByUserObject(userObject);
-			}
 			treeEvent = new TreeEvent(treeEvent.getCommand(), treeEvent.getSubCommand(), selTN.getIdent());
 
 			boolean dispatch = true;
 			String selectedNodeId = null;
-			if(userObject instanceof String) {
-				String sObject = (String)userObject;
-				if(MenuTree.COMMAND_TREENODE_CLICKED.equals(treeEvent.getCommand()) && treeEvent.getSubCommand() == null) {
-					openCourseNodeIds.add(sObject);
-					selectedNodeId = selTN.getIdent();
-				} else if(TreeEvent.COMMAND_TREENODE_OPEN.equals(treeEvent.getSubCommand())) {
-					openCourseNodeIds.add(sObject);
-					selectedNodeId = selTN.getIdent();
-					dispatch = false;
-				} else if(TreeEvent.COMMAND_TREENODE_CLOSE.equals(treeEvent.getSubCommand())) {
-					removeChildrenFromOpenNodes(selTN);
-					openCourseNodeIds.remove(sObject);
-					openCourseNodeIds.remove(selTN.getIdent());
-					dispatch = false;
-				}
+			if(MenuTree.COMMAND_TREENODE_CLICKED.equals(treeEvent.getCommand()) && treeEvent.getSubCommand() == null) {
+				openCourseNodeIds.add(selTN.getIdent());
+				selectedNodeId = selTN.getIdent();
+			} else if(TreeEvent.COMMAND_TREENODE_OPEN.equals(treeEvent.getSubCommand())) {
+				openCourseNodeIds.add(selTN.getIdent());
+				selectedNodeId = selTN.getIdent();
+				dispatch = false;
+			} else if(TreeEvent.COMMAND_TREENODE_CLOSE.equals(treeEvent.getSubCommand())) {
+				removeChildrenFromOpenNodes(selTN);
+				openCourseNodeIds.remove(selTN.getIdent());
+				dispatch = false;
 			}
 			
 			if(dispatch) {
 			// null as controller source since we are not a controller
 				subtreemodelListener.dispatchEvent(ureq, null, treeEvent);
 				// no node construction result indicates handled
+				reattachExternalTreeModels(treeModel);
 			}
 			ncr = new NodeClickedRef(treeModel, true, selectedNodeId, openCourseNodeIds, internCourseNode, nrcr, true);
 		}
 		return ncr;
 	}
 	
-	public NodeClickedRef reloadTreeAfterChanges(CourseNode courseNode) {
+	public NodeClickedRef reloadTreeAfterChanges(CourseNode courseNode, String selectedNodeId) {
 		GenericTreeModel treeModel = createTreeModel();
 		TreeNode treeNode = treeModel.getNodeById(courseNode.getIdent());
 		NodeClickedRef nclr = null;
@@ -290,12 +282,10 @@ public class NavigationHandler implements Disposable {
 				reattachExternalTreeModels(treeModel);
 			}
 			
-			selectedCourseNodeId = courseTreeNode.getCourseNode().getIdent();
-			
 			if(subtreemodelListener == null) {
-				nclr = new NodeClickedRef(treeModel, true, selectedCourseNodeId, openCourseNodeIds, courseTreeNode.getCourseNode(), null, false);
+				nclr = new NodeClickedRef(treeModel, true, selectedNodeId, openCourseNodeIds, courseTreeNode.getCourseNode(), null, false);
 			} else {
-				nclr = new NodeClickedRef(treeModel, true, selectedCourseNodeId, openCourseNodeIds, courseTreeNode.getCourseNode(), null, true);
+				nclr = new NodeClickedRef(treeModel, true, selectedNodeId, openCourseNodeIds, courseTreeNode.getCourseNode(), null, true);
 			}
 		}
 		return nclr;
@@ -416,8 +406,8 @@ public class NavigationHandler implements Disposable {
 						if(!newSelectedNodeId.equals(ncr.getSelectedTreeNodeId())) {
 							if(ncr.getSelectedTreeNodeId() != null) {
 								TreeNode selectedNode = subTreeModel.getNodeById(ncr.getSelectedTreeNodeId());
-								if(selectedNode != null && selectedNode.getUserObject() instanceof String) {
-									openCourseNodeIds.add((String)selectedNode.getUserObject());
+								if(selectedNode != null) {
+									openCourseNodeIds.add(selectedNode.getIdent());
 								}
 							}
 						}
@@ -458,7 +448,7 @@ public class NavigationHandler implements Disposable {
 					}
 				}
 				if (evaluateTree) {
-					treeModel = createTreeModel();;
+					treeModel = createTreeModel();
 				}
 				
 				if((TreeEvent.COMMAND_TREENODE_OPEN.equals(nodeSubCmd) || TreeEvent.COMMAND_TREENODE_CLOSE.equals(nodeSubCmd)) &&
@@ -490,7 +480,7 @@ public class NavigationHandler implements Disposable {
 		return nodeAccessService.getCourseTreeModelBuilder(userCourseEnv).withFilter(filter).build();
 	}
 	
-	private void reattachExternalTreeModels(GenericTreeModel courseTreeModel) {
+	private void reattachExternalTreeModels(TreeModel courseTreeModel) {
 		if(externalTreeModels == null || externalTreeModels.isEmpty()) return;
 		
 		for(Map.Entry<String, SubTree> entry:externalTreeModels.entrySet()) {
@@ -517,7 +507,6 @@ public class NavigationHandler implements Disposable {
 
 	private void removeChildrenFromOpenNodes(TreeNode treeNode) {
 		openCourseNodeIds.remove(treeNode.getIdent());
-		openCourseNodeIds.remove(treeNode.getUserObject());
 		for(int i=treeNode.getChildCount(); i-->0; ) {
 			removeChildrenFromOpenNodes((TreeNode)treeNode.getChildAt(i));
 		}
@@ -568,12 +557,10 @@ public class NavigationHandler implements Disposable {
 	private void addSubTreeModel(TreeNode parent, TreeModel modelToAppend) {
 		// ignore root and directly add children.
 		// need to clone children so that are not detached from their original
-		// parent (which is the cp treemodel)
-		// parent.addChild(modelToAppend.getRootNode());
+		parent.removeAllChildren();
 		TreeNode root = modelToAppend.getRootNode();
 		int chdCnt = root.getChildCount();
 		
-		// full cloning of ETH webclass energie takes about 4/100 of a second
 		for (int i = chdCnt; i > 0; i--) {
 			INode chd = root.getChildAt(i-1);
 			INode chdc = (INode) XStreamHelper.xstreamClone(chd);
@@ -583,20 +570,6 @@ public class NavigationHandler implements Disposable {
 			// always insert before already existing course building block children
 			parent.insert(chdc, 0);
 		}
-		
-		copyIdent(parent, root);
-	}
-	
-	private void copyIdent(TreeNode guiNode, TreeNode originalNode) {
-		if(guiNode instanceof GenericTreeNode) {
-			((GenericTreeNode)guiNode).setIdent(originalNode.getIdent());
-		}
-		
-		for (int i=originalNode.getChildCount(); i-->0; ) {
-			INode originalChild = originalNode.getChildAt(i);
-			INode guiChild = guiNode.getChildAt(i);
-			copyIdent((TreeNode)guiChild, (TreeNode)originalChild);
-		}
 	}
 	
 	private static class SubTree {
diff --git a/src/main/java/org/olat/gui/control/OlatFooterController.java b/src/main/java/org/olat/gui/control/OlatFooterController.java
index 057ccf6681a23863f0bbc2c2e9abfead60562e8d..29df761002fbeca04c4e6716ff4ed3e7e825c012 100644
--- a/src/main/java/org/olat/gui/control/OlatFooterController.java
+++ b/src/main/java/org/olat/gui/control/OlatFooterController.java
@@ -116,13 +116,11 @@ public class OlatFooterController extends BasicController implements LockableCon
 		// Push information about user
 		if (!isGuest && usess.isAuthenticated()) {
 			olatFootervc.contextPut("loggedIn", Boolean.TRUE);
-			if(isInvitee) {
-				String fullName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(ureq.getIdentity());
-				olatFootervc.contextPut("username", StringHelper.escapeHtml(fullName) + " " + translate("logged.in.invitee"));
-			} else {
-				String fullName = CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(ureq.getIdentity());
-				olatFootervc.contextPut("username", StringHelper.escapeHtml(fullName));
+			String fullName = StringHelper.escapeHtml(CoreSpringFactory.getImpl(UserManager.class).getUserDisplayName(ureq.getIdentity()));
+			if (isInvitee) {
+				fullName = fullName + " " + translate("logged.in.invitee");
 			}
+			olatFootervc.contextPut("username", fullName);
 		} else {
 			olatFootervc.contextPut("loggedIn", Boolean.FALSE);
 		}
diff --git a/src/main/java/org/olat/ims/cp/ui/CPEditMainController.java b/src/main/java/org/olat/ims/cp/ui/CPEditMainController.java
index 0ef50abc34b4d3694554d2b26abcf009a2b6b69e..8b61dc064ec7caac71dbe20ec5f3dc8804ec620a 100644
--- a/src/main/java/org/olat/ims/cp/ui/CPEditMainController.java
+++ b/src/main/java/org/olat/ims/cp/ui/CPEditMainController.java
@@ -45,7 +45,10 @@ import org.olat.core.util.coordinate.LockResult;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.ims.cp.CPManager;
 import org.olat.ims.cp.ContentPackage;
+import org.olat.modules.cp.CPAssessmentProvider;
 import org.olat.modules.cp.CPUIFactory;
+import org.olat.modules.cp.PersistingAssessmentProvider;
+import org.olat.repository.RepositoryEntry;
 import org.olat.repository.ui.RepositoryEntryRuntimeController.ToolbarAware;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -65,9 +68,10 @@ public class CPEditMainController extends BasicController implements ToolbarAwar
 	private CPManager cpManager;
 
 	public CPEditMainController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbar,
-			VFSContainer cpContainer, OLATResourceable ores) {
+			VFSContainer cpContainer, RepositoryEntry cpEntry) {
 		super(ureq, wControl);
 		this.stackPanel = toolbar;
+		OLATResourceable ores = cpEntry.getOlatResource();
 
 		// acquire lock for resource
 		lock = CoordinatorManager.getInstance().getCoordinator().getLocker().acquireLock(ores, ureq.getIdentity(), null);
@@ -103,8 +107,10 @@ public class CPEditMainController extends BasicController implements ToolbarAwar
 				}
 			} else {
 				showInfo("contentcontroller.no.lock");
+				
+				CPAssessmentProvider cpAssessmentProvider = PersistingAssessmentProvider.create(cpEntry, getIdentity());
 				Controller cpCtr = CPUIFactory.getInstance()
-						.createMainLayoutController(ureq, wControl, cpContainer, true, deliveryOptions);
+						.createMainLayoutController(ureq, wControl, cpContainer, true, deliveryOptions, cpAssessmentProvider);
 				putInitialPanel(cpCtr.getInitialComponent());
 			}
 		} else {
diff --git a/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java b/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java
index 08f5c5d6beb57105e9c0ee94aeb1834d57be30fe..fce4ef6f6ddfe2295188454f035875f77d2705a8 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI21ExportProcessor.java
@@ -22,6 +22,7 @@ package org.olat.ims.qti21.pool;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.file.FileVisitResult;
@@ -29,8 +30,10 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.concurrent.atomic.DoubleAdder;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
@@ -60,6 +63,7 @@ import org.olat.modules.qpool.manager.QPoolFileStorage;
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection;
 import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest;
+import uk.ac.ed.ph.jqtiplus.node.test.TestPart;
 import uk.ac.ed.ph.jqtiplus.resolution.ResolvedAssessmentItem;
 import uk.ac.ed.ph.jqtiplus.serialization.QtiSerializer;
 
@@ -104,9 +108,9 @@ public class QTI21ExportProcessor {
 				.loadAndResolveAssessmentItemForCopy(assessmentItemUri, rootDirectory);
 		enrichWithMetadata(qitem, resolvedAssessmentItem, manifestBuilder);
 		
-		try {
+		try(OutputStream out = new ShieldOutputStream(zout)) {
 			zout.putNextEntry(new ZipEntry(rootDir + "/imsmanifest.xml"));
-			manifestBuilder.write(new ShieldOutputStream(zout));
+			manifestBuilder.write(out);
 			zout.closeEntry();
 		} catch (Exception e) {
 			log.error("", e);
@@ -180,7 +184,7 @@ public class QTI21ExportProcessor {
 		metadataBuilder.appendMetadataFrom(qitem, resolvedAssessmentItem, locale);	
 	}
 	
-	public void assembleTest(String title, List<QuestionItemFull> fullItems, File directory) {
+	public void assembleTest(String title, List<QuestionItemFull> fullItems, boolean groupByTaxonomyLevel, File directory) {
 		try {
 			QtiSerializer qtiSerializer = qtiService.qtiSerializer();
 			//imsmanifest
@@ -200,7 +204,9 @@ public class QTI21ExportProcessor {
 			manifest.appendAssessmentTest(assessmentTestFilename);
 
 			//make a section
-			AssessmentSection section = assessmentTest.getTestParts().get(0).getAssessmentSections().get(0);
+			final TestPart testPart = assessmentTest.getTestParts().get(0);
+			AssessmentSection defaultSection = testPart.getAssessmentSections().get(0);
+			Map<String,AssessmentSection> sectionByTitles = new HashMap<>();
 
 			//assessment items
 			for(QuestionItemFull qitem:fullItems) {
@@ -217,6 +223,12 @@ public class QTI21ExportProcessor {
 				File newItemFile = new File(containerDir, assessmentItem.getIdentifier() + ".xml");
 				String newItemFilename = container  + "/" + newItemFile.getName();
 				qtiService.persistAssessmentObject(newItemFile, assessmentItem);
+				
+				AssessmentSection section = defaultSection;
+				if(groupByTaxonomyLevel && StringHelper.containsNonWhitespace(qitem.getTaxonomyLevelName())) {
+					section = sectionByTitles.computeIfAbsent(qitem.getTaxonomyLevelName(), level
+							-> AssessmentTestFactory.appendAssessmentSection(level, testPart));
+				}
 
 				AssessmentTestFactory.appendAssessmentItem(section, newItemFilename);
 				manifest.appendAssessmentItem(newItemFilename);
@@ -242,6 +254,10 @@ public class QTI21ExportProcessor {
 				}
 			}
 			
+			if(defaultSection.getSectionParts().isEmpty()) {
+				testPart.getChildAbstractParts().remove(defaultSection);
+			}
+			
 			AssessmentTestBuilder assessmentTestBuilder = new AssessmentTestBuilder(assessmentTest);
 			double sumMaxScore = atomicMaxScore.sum();
 			if(sumMaxScore > 0.0d) {
@@ -263,7 +279,6 @@ public class QTI21ExportProcessor {
 	
 	public void assembleTest(List<QuestionItemFull> fullItems, ZipOutputStream zout) {
 		try {
-			QtiSerializer qtiSerializer = qtiService.qtiSerializer();
 			//imsmanifest
 			ManifestBuilder manifest = ManifestBuilder.createAssessmentTestBuilder();
 			
@@ -310,14 +325,31 @@ public class QTI21ExportProcessor {
 			}
 
 			zout.putNextEntry(new ZipEntry(assessmentTestFilename));
-			qtiSerializer.serializeJqtiObject(assessmentTest, new ShieldOutputStream(zout));
+			serializeAssessmentTest(assessmentTest, zout);
 			zout.closeEntry();
 
 			zout.putNextEntry(new ZipEntry("imsmanifest.xml"));
-			manifest.write(new ShieldOutputStream(zout));
+			writeManifest(manifest, zout);
 			zout.closeEntry();
 		} catch (IOException | URISyntaxException e) {
 			log.error("", e);
 		}
 	}
+	
+	private void writeManifest(ManifestBuilder manifest, ZipOutputStream zout) {
+		try(OutputStream out = new ShieldOutputStream(zout)) {
+			manifest.write(out);
+		} catch(IOException e) {
+			log.error("Cannot write manifest", e);
+		}
+	}
+	
+	private void serializeAssessmentTest(AssessmentTest assessmentTest, ZipOutputStream zout) {
+		try(OutputStream out = new ShieldOutputStream(zout)) {
+			QtiSerializer qtiSerializer = qtiService.qtiSerializer();
+			qtiSerializer.serializeJqtiObject(assessmentTest, out);
+		} catch(IOException e) {
+			log.error("Cannot write manifest", 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 eaab55e620207ee11d57794bcafc3b7fb24e8971..5cc21534b8e8acf535a06976940d2c800f809465 100644
--- a/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java
+++ b/src/main/java/org/olat/ims/qti21/pool/QTI21QPoolServiceProvider.java
@@ -482,10 +482,10 @@ public class QTI21QPoolServiceProvider implements QPoolSPI {
 	 * @param items The list of questions to export
 	 * @param locale The language
 	 */
-	public void exportToEditorPackage(String testTitle, File exportDir, List<QuestionItemShort> items, Locale locale) {
+	public void exportToEditorPackage(String testTitle, File exportDir, List<QuestionItemShort> items, boolean groupByTaxonomyLevel, Locale locale) {
 		List<QuestionItemFull> fullItems = loadQuestionFullItems(items);
 		QTI21ExportProcessor processor = new QTI21ExportProcessor(qtiService, qpoolFileStorage, locale);
-		processor.assembleTest(testTitle, fullItems, exportDir);
+		processor.assembleTest(testTitle, fullItems, groupByTaxonomyLevel, exportDir);
 	}
 	
 	private List<QuestionItemFull> loadQuestionFullItems(List<QuestionItemShort> items) {
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 5165706b610794e21b578cccc07c4cc21ef2664d..d5657989d2fe6b4ba9e8f479516ea242a6f90a04 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
@@ -167,7 +167,8 @@ public class QTI21AssessmentTestHandler extends FileHandler {
 		}
 		if(createObject instanceof QItemList) {
 			QItemList itemToImport = (QItemList)createObject;
-			qpoolServiceProvider.exportToEditorPackage(displayname, repositoryDir, itemToImport.getItems(), locale);
+			qpoolServiceProvider.exportToEditorPackage(displayname, repositoryDir,
+					itemToImport.getItems(), itemToImport.isGroupByTaxonomyLevel(), locale);
 		} else if(createObject instanceof QTIEditorPackage) {
 			QTIEditorPackage testToConvert = (QTIEditorPackage)createObject;
 			QTI21DeliveryOptions options = qtiService.getDeliveryOptions(re);
diff --git a/src/main/java/org/olat/modules/cp/CPAssessmentProvider.java b/src/main/java/org/olat/modules/cp/CPAssessmentProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..c8305fb35eb4a969efde3e336204ae6875754bdc
--- /dev/null
+++ b/src/main/java/org/olat/modules/cp/CPAssessmentProvider.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.cp;
+
+import org.olat.modules.assessment.model.AssessmentEntryStatus;
+
+/**
+ * 
+ * Initial date: 26 Feb 2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public interface CPAssessmentProvider {
+	
+	AssessmentEntryStatus onPageVisited(String itemIdentifier);
+
+	AssessmentEntryStatus getStatus(String itemIdentifier);
+
+}
diff --git a/src/main/java/org/olat/modules/cp/CPDisplayController.java b/src/main/java/org/olat/modules/cp/CPDisplayController.java
index 584bb7800e1aa3a537a06dd7d76e4f9178687cda..2e1a8eb349060cdfa5b88894888f9a59761f5902 100644
--- a/src/main/java/org/olat/modules/cp/CPDisplayController.java
+++ b/src/main/java/org/olat/modules/cp/CPDisplayController.java
@@ -35,6 +35,7 @@ import org.olat.core.gui.components.htmlsite.HtmlStaticPageComponent;
 import org.olat.core.gui.components.htmlsite.NewInlineUriEvent;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.tree.GenericTreeNode;
 import org.olat.core.gui.components.tree.MenuTree;
 import org.olat.core.gui.components.tree.TreeEvent;
 import org.olat.core.gui.components.tree.TreeNode;
@@ -68,6 +69,8 @@ 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.modules.assessment.model.AssessmentEntryStatus;
+import org.olat.modules.cp.CPManifestTreeModel.UserObject;
 import org.olat.search.SearchModule;
 import org.olat.search.SearchServiceUIFactory;
 import org.olat.search.SearchServiceUIFactory.DisplayOption;
@@ -101,24 +104,28 @@ public class CPDisplayController extends BasicController implements Activateable
 	
 	private CPSelectPrintPagesController printController;
 	private CloseableModalController printPopup;
+
+	private final CPAssessmentProvider cpAssessmentProvider;
 	
 	@Autowired
 	private SearchModule searchModule;
 	
 	/**
 	 * @param ureq
-	 * @param cpRoot
 	 * @param showMenu
 	 * @param showNavigation Show the next/previous link
 	 * @param activateFirstPage
 	 * @param identPrefix In a course, set a unique prefix per node, if someone set 2x the same CPs in the course, the node identifiers
 	 * of the CP elements must be different but predictable
+	 * @param cpAssessmentProvider 
+	 * @param cpRoot
 	 */
 	public CPDisplayController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer, boolean showMenu, boolean showNavigation,
 			boolean activateFirstPage, boolean showPrint, DeliveryOptions deliveryOptions, String initialUri, OLATResourceable ores,
-			String identPrefix, boolean randomizeMapper) {
+			String identPrefix, boolean randomizeMapper, CPAssessmentProvider cpAssessmentProvider) {
 		super(ureq, wControl);
 		this.rootContainer = rootContainer;
+		this.cpAssessmentProvider = cpAssessmentProvider;
 
 		// wrapper velocity container for page content
 		myContent = createVelocityContainer("cpcontent");
@@ -146,7 +153,7 @@ public class CPDisplayController extends BasicController implements Activateable
 		}
 		// initialize tree model in any case
 		try {
-			ctm = new CPManifestTreeModel((VFSLeaf) mani, identPrefix);
+			ctm = new CPManifestTreeModel((VFSLeaf) mani, identPrefix, cpAssessmentProvider);
 		} catch (IOException e) {
 			showError("error.manifest.corrupted");
 			return;
@@ -203,7 +210,8 @@ public class CPDisplayController extends BasicController implements Activateable
 				} else node = null;
 			}
 			if (node != null) { // node.isAccessible
-				String nodeUri = (String) node.getUserObject();
+				UserObject userObject = (UserObject)node.getUserObject();
+				String nodeUri = userObject.getHref();
 				if (cpContentCtr != null) cpContentCtr.setCurrentURI(nodeUri);
 				if (cpComponent != null) cpComponent.setCurrentURI(nodeUri);
 				if (showMenu) cpTree.setSelectedNodeId(node.getIdent());
@@ -211,13 +219,11 @@ public class CPDisplayController extends BasicController implements Activateable
 				// empty anyway and saves one user click)
 				selNodeId = node.getIdent();
 
+				onPageVisited(node);
 				nodeInfo = LoggingResourceable.wrapCpNode(nodeUri);
 				updateNextPreviousLink(node);
-				if(node.getUserObject() != null) {
-					String identifierRes = (String)node.getUserObject();
-					OLATResourceable pOres = OresHelper.createOLATResourceableInstanceWithoutCheck("path=" + identifierRes, 0l);
-					addToHistory(ureq, pOres, null);
-				}
+				OLATResourceable pOres = OresHelper.createOLATResourceableInstanceWithoutCheck("path=" + nodeUri, 0l);
+				addToHistory(ureq, pOres, null);
 			}
 		} else if (initialUri != null) {
 			// set page
@@ -234,7 +240,7 @@ public class CPDisplayController extends BasicController implements Activateable
 				}
 				updateNextPreviousLink(newNode);
 				if(newNode.getUserObject() != null) {
-					String identifierRes = (String)newNode.getUserObject();
+					String identifierRes = ((UserObject)newNode.getUserObject()).getHref();
 					Long id = Long.parseLong(newNode.getIdent());
 					OLATResourceable pOres = OresHelper.createOLATResourceableInstanceWithoutCheck("path=" + identifierRes, id);
 					addToHistory(ureq, pOres, null);
@@ -281,11 +287,6 @@ public class CPDisplayController extends BasicController implements Activateable
 		return cpTree;
 	}
 
-	/**
-	 * @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 == cpTree) {
@@ -450,7 +451,8 @@ public class CPDisplayController extends BasicController implements Activateable
 	}
 	
 	public void switchToPage(UserRequest ureq, TreeNode tn) {
-		String identifierRes = (String) tn.getUserObject();
+		UserObject userObject = (UserObject)tn.getUserObject();
+		String identifierRes = userObject.getHref();
 		OLATResourceable ores = OresHelper.createOLATResourceableInstanceWithoutCheck("path=" + identifierRes, 0l);
 		addToHistory(ureq, ores, null);
 		
@@ -487,13 +489,19 @@ public class CPDisplayController extends BasicController implements Activateable
 		}
 		
 		updateNextPreviousLink(tn);
+		onPageVisited(tn);
+		
 		ThreadLocalUserActivityLogger.log(CourseLoggingAction.CP_GET_FILE, getClass(), LoggingResourceable.wrapCpNode(identifierRes));
 	}
 
-	/**
-	 * 
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
+	private void onPageVisited(TreeNode treeNode) {
+		UserObject userObject = (UserObject)treeNode.getUserObject();
+		String identifier = userObject.getIdentifier();
+		AssessmentEntryStatus status = cpAssessmentProvider.onPageVisited(identifier);
+		String cssClass = CPManifestTreeModel.getItemCssClass(status);
+		((GenericTreeNode)treeNode).setCssClass(cssClass);
+	}
+
 	@Override
 	protected void doDispose() {
 		ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_CLOSE, getClass());
diff --git a/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java b/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java
index 8b1fbd8b6ae3f8bb78602039697fb2a66adfd9b9..e939daa7d058eb45e940931fa0094359072d3c1a 100644
--- a/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java
+++ b/src/main/java/org/olat/modules/cp/CPManifestTreeModel.java
@@ -50,6 +50,7 @@ import org.olat.core.util.Encoder;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.xml.XMLParser;
 import org.olat.ims.resources.IMSEntityResolver;
+import org.olat.modules.assessment.model.AssessmentEntryStatus;
 
 /**
 *  Description:<br>
@@ -65,19 +66,23 @@ public class CPManifestTreeModel extends GenericTreeModel {
 	private final List<TreeNode> treeNodes = new ArrayList<>();
 	private final String identPrefix;
 	private final Logger log = Tracing.createLoggerFor(this.getClass());
+	private final CPAssessmentProvider cpAssessmentProvider;
 
 	/**
 	 * Constructor of the content packaging tree model
 	 * @param manifest the imsmanifest.xml file
+	 * @param cpAssessmentProvider 
 	 */
-	CPManifestTreeModel(VFSLeaf manifest, String identPrefix) throws IOException {
+	CPManifestTreeModel(VFSLeaf manifest, String identPrefix, CPAssessmentProvider cpAssessmentProvider) throws IOException {
 		this.identPrefix = identPrefix;
+		this.cpAssessmentProvider = cpAssessmentProvider;
 		Document doc = loadDocument(manifest);
 		initDocument(doc);
 	}
 	
 	CPManifestTreeModel(String manifest,  String identPrefix) throws IOException {
 		this.identPrefix = identPrefix;
+		this.cpAssessmentProvider = DryRunAssessmentProvider.create();
 		Document doc = loadDocument(manifest);
 		initDocument(doc);
 	}
@@ -195,7 +200,7 @@ public class CPManifestTreeModel extends GenericTreeModel {
 						XPath meta = rootElement.createXPath("//ns:resource[@identifier='" + identifierref + "']");
 						meta.setNamespaceURIs(nsuris);
 						gtn.setAccessible(true);
-						gtn.setUserObject(href);
+						gtn.setUserObject(new UserObject(identifier, href));
 						if (hrefToTreeNode.containsKey(href)){
 							log.debug("Duplicate href::" + href + " for identifierref::" + identifierref + " and identifier::" + identifier + ", use first one");
 						} else {					
@@ -207,6 +212,7 @@ public class CPManifestTreeModel extends GenericTreeModel {
 			}
 		} else if (item.getName().equals("item")) {
 			gtn.setIconCssClass("o_cp_item");
+			gtn.setCssClass(getItemCssClass(identifier));
 			//set resolved file path directly
 			String identifierref = item.attributeValue("identifierref");
 			if(identifierref != null) {
@@ -216,7 +222,7 @@ public class CPManifestTreeModel extends GenericTreeModel {
 			meta.setNamespaceURIs(nsuris);
 			String href = resources.get(identifierref);
 			if (href != null) {
-				gtn.setUserObject(href);
+				gtn.setUserObject(new UserObject(identifier, href));
 				// allow lookup of a treenode given a href so we can quickly adjust the menu if the user clicks on hyperlinks within the text
 				if (hrefToTreeNode.containsKey(href)){
 					log.debug("Duplicate href::" + href + " for identifierref::" + identifierref + " and identifier::" + identifier + ", use first one");
@@ -257,6 +263,18 @@ public class CPManifestTreeModel extends GenericTreeModel {
 		return gtn;
 	}
 	
+	private String getItemCssClass(String identifier) {
+		AssessmentEntryStatus status = cpAssessmentProvider.getStatus(identifier);
+		return getItemCssClass(status);
+	}
+
+	public static String getItemCssClass(AssessmentEntryStatus status) {
+		if (AssessmentEntryStatus.done.equals(status)) {
+			return "o_lp_done o_lp_not_in_sequence o_lp_contains_no_sequence";
+		}
+		return "o_lp_ready o_lp_not_in_sequence o_lp_contains_no_sequence";
+	}
+
 	private Document loadDocument(VFSLeaf documentF) throws IOException {
 		InputStream in = null;
 		Document doc = null;
@@ -294,4 +312,24 @@ public class CPManifestTreeModel extends GenericTreeModel {
 		}
 		return doc;
 	}
+	
+	public static final class UserObject {
+		
+		private final String identifier;
+		private final String href;
+
+		public UserObject(String identifier, String href) {
+			this.identifier = identifier;
+			this.href = href;
+		}
+
+		public String getIdentifier() {
+			return identifier;
+		}
+
+		public String getHref() {
+			return href;
+		}
+		
+	}
 }
diff --git a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
index 62be000b01ce0b7ec99e26d1fb2c8607f44ce786..ebf4d8c09cf9f38835d05f9cdb66396ebc8d12a2 100644
--- a/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
+++ b/src/main/java/org/olat/modules/cp/CPOfflineReadableManager.java
@@ -54,6 +54,7 @@ import org.olat.core.util.WebappHelper;
 import org.olat.core.util.ZipUtil;
 import org.olat.core.util.vfs.LocalFileImpl;
 import org.olat.fileresource.FileResourceManager;
+import org.olat.modules.cp.CPManifestTreeModel.UserObject;
 
 /**
  * Description: <br>
@@ -189,7 +190,7 @@ public class CPOfflineReadableManager {
 		/* first, we do the menu-tree */
 		File mani = new File(unzippedDir, FILENAME_IMSMANIFEST);
 		LocalFileImpl vfsMani = new LocalFileImpl(mani);
-		CPManifestTreeModel ctm = new CPManifestTreeModel(vfsMani, "");
+		CPManifestTreeModel ctm = new CPManifestTreeModel(vfsMani, "", DryRunAssessmentProvider.create());
 		TreeNode root = ctm.getRootNode();
 		// let's take the rootnode title as  page title
 		this.rootTitle = root.getTitle(); 
@@ -260,7 +261,7 @@ public class CPOfflineReadableManager {
 		// available
 		// render current node
 
-		String nodeUri = (String) node.getUserObject();
+		String nodeUri = node.getUserObject() != null? ((UserObject)node.getUserObject()).getHref(): null;
 		String title = node.getTitle();
 		String altText = node.getAltText();
 
diff --git a/src/main/java/org/olat/modules/cp/CPPrintMapper.java b/src/main/java/org/olat/modules/cp/CPPrintMapper.java
index d629ab64945022993e6e0a27927836a92cf0df4f..b5894d01ad48e9ccfc4abf168d5a4d6104e27287 100644
--- a/src/main/java/org/olat/modules/cp/CPPrintMapper.java
+++ b/src/main/java/org/olat/modules/cp/CPPrintMapper.java
@@ -48,6 +48,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.cp.CPManifestTreeModel.UserObject;
 import org.xml.sax.InputSource;
 
 import nu.validator.htmlparser.common.XmlViolationPolicy;
@@ -180,7 +181,7 @@ public class CPPrintMapper implements Mapper {
 		for(String nodeId:nodeIds) {
 			HtmlPageHandler parsedPage = null;
 			TreeNode treeNode = ctm.getNodeById(nodeId);
-			String identifierRes = (String)treeNode.getUserObject();	
+			String identifierRes = ((UserObject)treeNode.getUserObject()).getHref();
 			if(StringHelper.containsNonWhitespace(identifierRes)) {
 				VFSItem currentItem = rootDir.resolve(identifierRes);
 				if(currentItem instanceof VFSLeaf) {
diff --git a/src/main/java/org/olat/modules/cp/CPUIFactory.java b/src/main/java/org/olat/modules/cp/CPUIFactory.java
index 75be2d650447d0c61b3092648348fee60df2ef11..dd561f7d5d896b12149ec5eeea074124db547754 100644
--- a/src/main/java/org/olat/modules/cp/CPUIFactory.java
+++ b/src/main/java/org/olat/modules/cp/CPUIFactory.java
@@ -69,13 +69,14 @@ public class CPUIFactory {
 	 * @param activateFirstPage true to automatically activate the first node with
 	 *          content
 	 * @param initialUri can be NULL, will use first page then
+	 * @param cpAssessmentProvider 
 	 * @return a CPDisplayController
 	 */
 	public CPDisplayController createContentOnlyCPDisplayController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
 			boolean activateFirstPage, boolean showNavigation, DeliveryOptions deliveryOptions,
-			String initialUri, OLATResourceable ores, String identPrefix, boolean preview) {
+			String initialUri, OLATResourceable ores, String identPrefix, boolean preview, CPAssessmentProvider cpAssessmentProvider) {
 		return new CPDisplayController(ureq, wControl, rootContainer, false, showNavigation, activateFirstPage, true, deliveryOptions,
-				initialUri, ores, identPrefix, preview);		
+				initialUri, ores, identPrefix, preview, cpAssessmentProvider);
 	}
 	
 	/**
@@ -89,11 +90,13 @@ public class CPUIFactory {
 	 * @param wControl
 	 * @param rootContainer The VFS root container where the CP is found on disk
 	 * @param showMenu true to display the menu, false to hide the menu
+	 * @param cpAssessmentProvider 
 	 * @return A main layout controller
 	 */
 	public MainLayout3ColumnsController createMainLayoutController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
-			boolean showMenu, DeliveryOptions deliveryOptions) {
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null, "", false);
+			boolean showMenu, DeliveryOptions deliveryOptions, CPAssessmentProvider cpAssessmentProvider) {
+		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true,
+				deliveryOptions, null, null, "", false, cpAssessmentProvider);
 		MainLayout3ColumnsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
 		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
 		return layoutCtr;
@@ -114,7 +117,8 @@ public class CPUIFactory {
 	 */
 	public LayoutMain3ColsPreviewController createMainLayoutPreviewController(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
 			boolean showMenu, DeliveryOptions deliveryOptions) {
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null, "", false);		
+		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true,
+				deliveryOptions, null, null, "", false, DryRunAssessmentProvider.create());
 		LayoutMain3ColsPreviewController layoutCtr = new LayoutMain3ColsPreviewController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
 		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
 		return layoutCtr;
@@ -135,7 +139,8 @@ public class CPUIFactory {
 	 */
 	public LayoutMain3ColsController createMainLayoutPreviewController_v2(UserRequest ureq, WindowControl wControl, VFSContainer rootContainer,
 			boolean showMenu, DeliveryOptions deliveryOptions) {
-		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true, deliveryOptions, null, null, "", false);		
+		CPDisplayController cpCtr = new CPDisplayController(ureq, wControl, rootContainer, showMenu, true, true, true,
+				deliveryOptions, null, null, "", false, DryRunAssessmentProvider.create());
 		LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(ureq, wControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), rootContainer.getName());
 		layoutCtr.addDisposableChildController(cpCtr); // cascade disposing requests
 		layoutCtr.addCssClassToMain("o_preview");
diff --git a/src/main/java/org/olat/modules/cp/DryRunAssessmentProvider.java b/src/main/java/org/olat/modules/cp/DryRunAssessmentProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..46eb53be33d31851aee827a2794f5855c7108a70
--- /dev/null
+++ b/src/main/java/org/olat/modules/cp/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.cp;
+
+import org.olat.modules.assessment.model.AssessmentEntryStatus;
+
+/**
+ * 
+ * Initial date: 26 Feb 2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class DryRunAssessmentProvider implements CPAssessmentProvider {
+	
+	private static final CPAssessmentProvider INSTANCE = new DryRunAssessmentProvider();
+	
+	public static final CPAssessmentProvider create() {
+		return INSTANCE;
+	}
+	
+	private DryRunAssessmentProvider() {
+		//
+	}
+	
+	@Override
+	public AssessmentEntryStatus onPageVisited(String itemIdentifier) {
+		return null;
+	}
+
+	@Override
+	public AssessmentEntryStatus getStatus(String itemIdentifier) {
+		return null;
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/cp/PersistingAssessmentProvider.java b/src/main/java/org/olat/modules/cp/PersistingAssessmentProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..af87aad28f7cea642fd84eac80484ea2ee8fe4e6
--- /dev/null
+++ b/src/main/java/org/olat/modules/cp/PersistingAssessmentProvider.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.cp;
+
+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: 26 Feb 2020<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class PersistingAssessmentProvider implements CPAssessmentProvider {
+
+	private final Identity identity;
+	private final RepositoryEntry cpEntry;
+	
+	private Map<String, AssessmentEntryStatus> identifierToStatus;
+	
+	private AssessmentService assessmentService;
+	
+	public static final CPAssessmentProvider create(RepositoryEntry cpEntry, Identity identity) {
+		return new PersistingAssessmentProvider(cpEntry, identity);
+	}
+	
+	private PersistingAssessmentProvider(RepositoryEntry cpEntry, Identity identity) {
+		this.identity = identity;
+		this.cpEntry = cpEntry;
+		this.assessmentService = CoreSpringFactory.getImpl(AssessmentService.class);
+		this.identifierToStatus = assessmentService.loadAssessmentEntriesByAssessedIdentity(identity, cpEntry).stream()
+				.filter(ae -> ae.getSubIdent() != null && ae.getAssessmentStatus() != null)
+				.collect(Collectors.toMap(AssessmentEntry::getSubIdent, AssessmentEntry::getAssessmentStatus));
+	}
+
+	@Override
+	public AssessmentEntryStatus onPageVisited(String itemIdentifier) {
+		AssessmentEntry assessmentEntry = assessmentService.getOrCreateAssessmentEntry(identity, null, cpEntry, itemIdentifier, false, null);
+		if (!AssessmentEntryStatus.done.equals(assessmentEntry.getAssessmentStatus())) {
+			assessmentEntry.setAssessmentStatus(AssessmentEntryStatus.done);
+			assessmentService.updateAssessmentEntry(assessmentEntry);
+			identifierToStatus.put(itemIdentifier, assessmentEntry.getAssessmentStatus());
+		}
+		return assessmentEntry.getAssessmentStatus();
+	}
+
+	@Override
+	public AssessmentEntryStatus getStatus(String itemIdentifier) {
+		return identifierToStatus.get(itemIdentifier);
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/qpool/model/QItemList.java b/src/main/java/org/olat/modules/qpool/model/QItemList.java
index 921a8d107ce10a8167298151876d477375577cba..0976f861508784b0c0d04ad624645c366431fb1a 100644
--- a/src/main/java/org/olat/modules/qpool/model/QItemList.java
+++ b/src/main/java/org/olat/modules/qpool/model/QItemList.java
@@ -31,22 +31,20 @@ import org.olat.modules.qpool.QuestionItemShort;
  */
 public class QItemList {
 
-	private List<QuestionItemShort> items;
+	private final boolean groupByTaxonomyLevel;
+	private final List<QuestionItemShort> items;
 	
-	public QItemList() {
-		//
-	}
-	
-	public QItemList(List<QuestionItemShort> items) {
+	public QItemList(List<QuestionItemShort> items, boolean groupByTaxonomyLevel) {
 		this.items = items;
+		this.groupByTaxonomyLevel = groupByTaxonomyLevel;
 	}
 
-	public List<QuestionItemShort> getItems() {
-		return items;
+	public boolean isGroupByTaxonomyLevel() {
+		return groupByTaxonomyLevel;
 	}
 
-	public void setItems(List<QuestionItemShort> items) {
-		this.items = items;
+	public List<QuestionItemShort> getItems() {
+		return items;
 	}
 
 }
diff --git a/src/main/java/org/olat/modules/qpool/ui/CreateTestOverviewController.java b/src/main/java/org/olat/modules/qpool/ui/CreateTestOverviewController.java
index 7144d4f8c1d0a368861ea85cd960d1e5f36a9bf6..e09a8e7776b3ee0c632f662b246f771ca4df8ca2 100644
--- a/src/main/java/org/olat/modules/qpool/ui/CreateTestOverviewController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/CreateTestOverviewController.java
@@ -36,13 +36,14 @@ import org.olat.core.commons.services.license.ResourceLicense;
 import org.olat.core.commons.services.license.ui.LicenseUIFactory;
 import org.olat.core.gui.UserRequest;
 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.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.CSSIconFlexiCellRenderer;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnDef;
 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.FlexiTableDataModelFactory;
 import org.olat.core.gui.control.Controller;
@@ -52,8 +53,10 @@ import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.modules.qpool.ExportFormatOptions;
 import org.olat.modules.qpool.QPoolSPI;
+import org.olat.modules.qpool.QPoolSecurityCallback;
 import org.olat.modules.qpool.QuestionItemShort;
 import org.olat.modules.qpool.QuestionPoolModule;
+import org.olat.modules.qpool.QuestionStatus;
 import org.olat.modules.qpool.manager.QuestionPoolLicenseHandler;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -64,12 +67,15 @@ import org.springframework.beans.factory.annotation.Autowired;
  *
  */
 public class CreateTestOverviewController extends FormBasicController {
+	
+	private static final String[] groupByKeys = new String[] { "on" };
 
 	private final boolean withLicenses;
+	private final boolean withTaxonomy;
 	private final ExportFormatOptions format;
-	private QItemDataModel itemsModel;
-	
 	
+	private QItemDataModel itemsModel;
+	private MultipleSelectionElement groupByEl;
 	
 	@Autowired
 	private LicenseModule licenseModule;
@@ -78,11 +84,11 @@ public class CreateTestOverviewController extends FormBasicController {
 	@Autowired
 	private QuestionPoolLicenseHandler licenseHandler;
 	
-
 	public CreateTestOverviewController(UserRequest ureq, WindowControl wControl, List<QuestionItemShort> items,
-			ExportFormatOptions format) {
+			ExportFormatOptions format, QPoolSecurityCallback secCallback) {
 		super(ureq, wControl, "create_test");
 		this.format = format;
+		withTaxonomy = secCallback.canUseTaxonomy();
 		withLicenses = licenseModule.isEnabled(licenseHandler);
 		initForm(ureq);
 		loadModel(items);
@@ -98,15 +104,26 @@ public class CreateTestOverviewController extends FormBasicController {
 						new CSSIconFlexiCellRenderer("o_icon_failed"))
 		));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.title));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.topic));
+		if(withTaxonomy) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.taxonomyLevel));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Cols.taxonomyPath));
+		}
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.type));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.format));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.status, new QuestionStatusCellRenderer()));
 		if(withLicenses) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.license));
 		}
 		itemsModel = new QItemDataModel(columnsModel, format, getLocale());
 		uifactory.addTableElement(getWindowControl(), "shares", itemsModel, getTranslator(), formLayout);
 		
-		uifactory.addFormSubmitButton("create.test", formLayout);
+		String[] groupByValues = new String[] { translate("group.by.taxonomy.level") };
+		groupByEl = uifactory.addCheckboxesHorizontal("group.by", null, formLayout, groupByKeys, groupByValues);
+		groupByEl.setVisible(withTaxonomy);
+		
 		uifactory.addFormCancelButton("cancel", formLayout, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("create.test", formLayout);
 	}
 	
 	private void loadModel(List<QuestionItemShort> items) {
@@ -156,6 +173,10 @@ public class CreateTestOverviewController extends FormBasicController {
 		}
 		return exportableItems;
 	}
+	
+	public boolean isGroupByTaxonomyLevel() {
+		return groupByEl.isVisible() && groupByEl.isAtLeastSelected(1);
+	}
 
 	@Override
 	protected void formOK(UserRequest ureq) {
@@ -218,6 +239,18 @@ public class CreateTestOverviewController extends FormBasicController {
 			return question.getTitle();
 		}
 		
+		public String getTopic() {
+			return question.getTopic();
+		}
+		
+		public String getTaxonomyLevelName() {
+			return question.getTaxonomyLevelName();
+		}
+		
+		public String getTaxonomyPath() {
+			return question.getTaxonomicPath();
+		}
+		
 		public String getFormat() {
 			return question.getFormat();
 		}
@@ -225,6 +258,18 @@ public class CreateTestOverviewController extends FormBasicController {
 		public ResourceLicense getLicense() {
 			return license;
 		}
+		
+		public QuestionStatus getQuestionStatus() {
+			return question.getQuestionStatus();
+		}
+		
+		public String getItemType() {
+			String type = question.getItemType();
+			if(type == null) {
+				return "";
+			}
+			return type;
+		}
 	
 		public QuestionItemShort getQuestion() {
 			return question;
@@ -261,7 +306,12 @@ public class CreateTestOverviewController extends FormBasicController {
 					return Boolean.FALSE;	
 				} 
 				case title: return share.getTitle();
+				case topic: return share.getTopic();
+				case taxonomyLevel: return share.getTaxonomyLevelName();
+				case taxonomyPath: return share.getTaxonomyPath();
 				case format: return share.getFormat();
+				case type: return share.getItemType();
+				case status: return share.getQuestionStatus();
 				case license: return shortenedLicense(share);
 				default : return share;
 			}
@@ -286,10 +336,15 @@ public class CreateTestOverviewController extends FormBasicController {
 		}
 	}
 	
-	private enum Cols implements FlexiColumnDef {
+	private enum Cols implements FlexiSortableColumnDef {
 		accept("export.overview.accept"),
 		title("general.title"),
+		topic("general.topic"),
+		taxonomyLevel("classification.taxonomy.level"),
+		taxonomyPath("classification.taxonomic.path"),
 		format("technical.format"),
+		status("lifecycle.status"),
+		type("question.type"),
 		license("rights.license");
 		
 		private final String i18nKey;
@@ -302,5 +357,15 @@ public class CreateTestOverviewController extends FormBasicController {
 		public String i18nHeaderKey() {
 			return i18nKey;
 		}
+
+		@Override
+		public boolean sortable() {
+			return false;
+		}
+
+		@Override
+		public String sortKey() {
+			return name();
+		}
 	}
 }
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 813f607bac57a6dd1aae31da97c8ef2520986ad3..4204cbd40b3e4fe898b68710044cb0b87f26c159 100644
--- a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java
@@ -520,10 +520,11 @@ public class QuestionListController extends AbstractItemListController implement
 			List<QuestionItemShort> items = createTestOverviewCtrl.getExportableQuestionItems();
 			String typeFormat = createTestOverviewCtrl.getResourceTypeFormat();
 			LicenseType licenseType = createTestOverviewCtrl.getLicenseType();
+			boolean groupBy = createTestOverviewCtrl.isGroupByTaxonomyLevel();
 			cmc.deactivate();
 			cleanUp();
 			if (event == Event.DONE_EVENT) {
-				doOpenCreateRepositoryTest(ureq, items, typeFormat, licenseType);
+				doOpenCreateRepositoryTest(ureq, items, typeFormat, licenseType, groupBy);
 			}
 		} else if(source == exportWizard) {
 			if(event == Event.CANCELLED_EVENT || event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
@@ -1042,7 +1043,7 @@ public class QuestionListController extends AbstractItemListController implement
 
 	private void doShowCreateTestOverview(UserRequest ureq, List<QuestionItemShort> items, ExportFormatOptions format) {
 		removeAsListenerAndDispose(createTestOverviewCtrl);
-		createTestOverviewCtrl = new CreateTestOverviewController(ureq, getWindowControl(), items, format);
+		createTestOverviewCtrl = new CreateTestOverviewController(ureq, getWindowControl(), items, format, getSecurityCallback());
 		listenTo(createTestOverviewCtrl);
 		
 		removeAsListenerAndDispose(cmc);
@@ -1052,13 +1053,13 @@ public class QuestionListController extends AbstractItemListController implement
 		listenTo(cmc);
 	}
 	
-	private void doOpenCreateRepositoryTest(UserRequest ureq, List<QuestionItemShort> items, String type, LicenseType licenseType) {
+	private void doOpenCreateRepositoryTest(UserRequest ureq, List<QuestionItemShort> items, String type, LicenseType licenseType, boolean groupBy) {
 		removeAsListenerAndDispose(cmc);
 		removeAsListenerAndDispose(addController);
 
 		RepositoryHandler handler = repositoryHandlerFactory.getRepositoryHandler(type);
 		addController = handler.createCreateRepositoryEntryController(ureq, getWindowControl());
-		addController.setCreateObject(new QItemList(items));
+		addController.setCreateObject(new QItemList(items, groupBy));
 		addController.setLicenseType(licenseType);
 		listenTo(addController);
 		cmc = new CloseableModalController(getWindowControl(), translate("close"), addController.getInitialComponent());
diff --git a/src/main/java/org/olat/modules/qpool/ui/_content/create_test.html b/src/main/java/org/olat/modules/qpool/ui/_content/create_test.html
index 5e3ebd6d6bd7cd29c81011aef16e846180caae48..c0a5f52c911a0ec8317549026b105ba5334a58e5 100644
--- a/src/main/java/org/olat/modules/qpool/ui/_content/create_test.html
+++ b/src/main/java/org/olat/modules/qpool/ui/_content/create_test.html
@@ -3,6 +3,9 @@
 	$r.translate("warning.different.licenses")</div>
 #end
 $r.render("shares")
+#if($r.visible("group.by"))
+	$r.render("group.by")
+#end
 <div class="o_button_group">
 	$r.render("cancel")
 	$r.render("create.test")
diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties
index 0960dec93169ee4fa74824082e8df62252da6d82..4cba538728e884aac7e2c49dc7c1d7cb9e8e1dc9 100644
--- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_de.properties
@@ -115,6 +115,7 @@ general.taxonomy.level=Fachbereich
 general.taxonomy.path={0}
 general.title=Titel
 general.topic=Thema
+group.by.taxonomy.level=Fragen nach Fachbereich gruppieren
 import.excellike.12=QTI 1.2 Excelimport \u00FCber Copy&Paste
 import.excellike.21=QTI 2.1 Excelimport \u00FCber Copy&Paste
 import.failed=Frage konnte nicht importiert werden.
diff --git a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties
index 11f9173265eb379b361c526cd3a315557bc7754a..f514b7bec39f10095e546d8bb10222334f9ed640 100644
--- a/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/qpool/ui/_i18n/LocalStrings_en.properties
@@ -115,6 +115,7 @@ general.taxonomy.level=Subject
 general.taxonomy.path={0}
 general.title=Title
 general.topic=Topic
+group.by.taxonomy.level=Group items by subject
 import.excellike.12=QTI 1.2 Excel import via copy&paste
 import.excellike.21=QTI 2.1 Excel import via copy&paste
 import.failed=No questions were imported
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 0000000000000000000000000000000000000000..9f4c0b046319364dbb848c99a3e441b83f7f9876
--- /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 0000000000000000000000000000000000000000..8330bdef120a97690ac280fc7b1543da4f399f4f
--- /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 684fb357496b3cac258fe969de1aea7e737df916..d35af5ae3a0087099abaedca474c7544e7efb34a 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 0000000000000000000000000000000000000000..0457946b328eb9670217fde263c104dd05111cd0
--- /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 e1984250c98d79c50cb9dd43c52e51a195b5ac47..756fb037b51ae32d7d787d74e53e389ecace59a6 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 0fd330270763b1da7651e8b30265bf7f067e2103..208a0129550c88e3adba155ee93b2d47bc044e97 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 04c90c3cbcadab9f93fd306435541cb9f6fac910..6225d9288ce2a9f82f99009a8c64ecceabbd5965 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/WikiSecurityCallbackImpl.java b/src/main/java/org/olat/modules/wiki/WikiSecurityCallbackImpl.java
index 0b9205ff4f635d2b095ff2112472ff42eaab0436..423fa17c044ca4d0555dae564ac2cb8c073f200c 100644
--- a/src/main/java/org/olat/modules/wiki/WikiSecurityCallbackImpl.java
+++ b/src/main/java/org/olat/modules/wiki/WikiSecurityCallbackImpl.java
@@ -25,7 +25,6 @@
 package org.olat.modules.wiki;
 
 import org.olat.core.commons.services.notifications.SubscriptionContext;
-import org.olat.course.run.userview.NodeEvaluation;
 import org.olat.modules.fo.ForumCallback;
 
 /**
@@ -34,24 +33,17 @@ import org.olat.modules.fo.ForumCallback;
  */
 public class WikiSecurityCallbackImpl implements WikiSecurityCallback {
 	
-	private NodeEvaluation ne;
+	private Boolean courseEditRight;
 	private boolean isAdministator;
 	private boolean isGuestOnly;
 	private boolean isGroupWiki;
 	private boolean isResourceOwner;
 	private SubscriptionContext subscriptionContext;
 
-	/**
-	 * 
-	 * @param ne
-	 * @param isOlatAdmin
-	 * @param isGuestOnly
-	 * @param isGroupWiki
-	 */
-	public WikiSecurityCallbackImpl(NodeEvaluation ne, boolean isAdministator, 
+	public WikiSecurityCallbackImpl(Boolean courseEditRight, boolean isAdministator, 
 			boolean isGuestOnly, boolean isGroupWiki, 
 			boolean isResourceOwner, SubscriptionContext subscriptionContext){
-		this.ne = ne;
+		this.courseEditRight = courseEditRight;
 		this.isAdministator = isAdministator;
 		this.isGuestOnly = isGuestOnly;
 		this.isGroupWiki  = isGroupWiki;
@@ -59,36 +51,25 @@ public class WikiSecurityCallbackImpl implements WikiSecurityCallback {
 		this.subscriptionContext = subscriptionContext;
 	}
 	
-	/**
-	 * 
-	 * @return true if administrator or allowed by preconditions
-	 */
 	@Override
 	public boolean mayEditAndCreateArticle() {
 		if(isGuestOnly) return false;
 		if(isGroupWiki || isAdministator) {
 			return true;
 		}
-		if(ne != null && ne.isCapabilityAccessible("access") && ne.isCapabilityAccessible("editarticle")) {
+		if(courseEditRight != null && courseEditRight.booleanValue()) {
 			return true;
 		}
 		//wiki is started from repo, and it's visible to this user, so creating pages is allowed
-		return ne == null; 
+		return courseEditRight == null; 
 	}
 	
-	/**
-	 * 
-	 * @return true if admin or resource owner or used in group context
-	 */
 	@Override
 	public boolean mayEditWikiMenu(){
 		if(isGuestOnly) return false;
 		return isGroupWiki || isAdministator || isResourceOwner;
 	}
 	
-	/**
-	 * @return the subscriptionContext. if null, then no subscription must be offered
-	 */
 	@Override
 	public SubscriptionContext getSubscriptionContext() {
 		return (isGuestOnly ? null : subscriptionContext);
diff --git a/src/main/java/org/olat/modules/wiki/WikiToCPExport.java b/src/main/java/org/olat/modules/wiki/WikiToCPExport.java
index 368020e51607ff2d21025888eb3581b75c1e8727..eb0633017f8ade12825d97f47adc2b0d973f444b 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/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index d982cd8a0217a137915b8e72deaacdb1c8319be5..fbbc1d3abfad590f546e8a2a6c8691ff2e0e0300 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -66,8 +66,10 @@ import org.olat.ims.cp.ui.CPContentController;
 import org.olat.ims.cp.ui.CPEditMainController;
 import org.olat.ims.cp.ui.CPPackageConfig;
 import org.olat.ims.cp.ui.CPRuntimeController;
+import org.olat.modules.cp.CPAssessmentProvider;
 import org.olat.modules.cp.CPDisplayController;
 import org.olat.modules.cp.CPOfflineReadableManager;
+import org.olat.modules.cp.PersistingAssessmentProvider;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntrySecurity;
 import org.olat.repository.RepositoryEntryStatusEnum;
@@ -221,8 +223,10 @@ public class ImsCPHandler extends FileHandler {
 		OLATResource res = re.getOlatResource();
 		File cpRoot = FileResourceManager.getInstance().unzipFileResource(res);
 		final LocalFolderImpl vfsWrapper = new LocalFolderImpl(cpRoot);
-		CPPackageConfig packageConfig = CoreSpringFactory.getImpl(CPManager.class).getCPPackageConfig(res);
+		CPManager cpManager = CoreSpringFactory.getImpl(CPManager.class);
+		CPPackageConfig packageConfig = cpManager.getCPPackageConfig(res);
 		final DeliveryOptions deliveryOptions = (packageConfig == null ? null : packageConfig.getDeliveryOptions());
+
 		return new CPRuntimeController(ureq, wControl, re, reSecurity,
 				(uureq, wwControl, toolbarPanel, entry, security, assessmentMode) -> {
 			boolean activateFirstPage = true;
@@ -231,8 +235,9 @@ public class ImsCPHandler extends FileHandler {
 			CoreSpringFactory.getImpl(UserCourseInformationsManager.class)
 				.updateUserCourseInformations(entry.getOlatResource(), uureq.getIdentity());
 			
+			CPAssessmentProvider cpAssessmentProvider = PersistingAssessmentProvider.create(re, uureq.getIdentity());
 			CPDisplayController cpCtr = new CPDisplayController(uureq, wwControl, vfsWrapper, true, true, activateFirstPage, true, deliveryOptions,
-					initialUri, entry.getOlatResource(), "", false);
+					initialUri, entry.getOlatResource(), "", false, cpAssessmentProvider);
 			LayoutMain3ColsController ctr = new LayoutMain3ColsController(uureq, wwControl, cpCtr.getMenuComponent(), cpCtr.getInitialComponent(), vfsWrapper.getName());
 			ctr.addDisposableChildController(cpCtr);
 			ctr.addActivateableDelegate(cpCtr);
@@ -254,7 +259,7 @@ public class ImsCPHandler extends FileHandler {
 		VFSSecurityCallback secCallback = new FullAccessWithQuotaCallback(quota);
 		cpRoot.setLocalSecurityCallback(secCallback);
 
-		return new CPEditMainController(ureq, wControl, toolbar, cpRoot, re.getOlatResource());
+		return new CPEditMainController(ureq, wControl, toolbar, cpRoot, re);
 	}
 	
 	@Override
@@ -262,31 +267,23 @@ public class ImsCPHandler extends FileHandler {
 		return null;
 	}
 	
+	@Override
 	protected String getDeletedFilePrefix() {
 		return "del_imscp_"; 
 	}
 	
-	/**
-	 * 
-	 * @see org.olat.repository.handlers.RepositoryHandler#acquireLock(org.olat.core.id.OLATResourceable, org.olat.core.id.Identity)
-	 */
+	@Override
 	public LockResult acquireLock(OLATResourceable ores, Identity identity) {
     //nothing to do
 		return null;
 	}
 	
-	/**
-	 * 
-	 * @see org.olat.repository.handlers.RepositoryHandler#releaseLock(org.olat.core.util.coordinate.LockResult)
-	 */
+	@Override
 	public void releaseLock(LockResult lockResult) {
 		//nothing to do since nothing locked
 	}
 	
-	/**
-	 * 
-	 * @see org.olat.repository.handlers.RepositoryHandler#isLocked(org.olat.core.id.OLATResourceable)
-	 */
+	@Override
 	public boolean isLocked(OLATResourceable ores) {
 		return false;
 	}
diff --git a/src/main/java/org/olat/repository/handlers/WikiHandler.java b/src/main/java/org/olat/repository/handlers/WikiHandler.java
index cf305098e722ea27af3f806c0c8617ded02866e6..6a582080b0a99cc03d3a9222bc294a4181b87969 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());
 				}