From a719a36ede418e89b34b790ae8e645f32558c451 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Fri, 20 Jul 2018 13:43:35 +0200
Subject: [PATCH] OO-3516: implements principal role for courses

---
 .../bps/course/nodes/ChecklistCourseNode.java |   5 +-
 .../de/bps/course/nodes/VCCourseNode.java     |   4 +-
 .../course/nodes/den/DENRunController.java    |   5 +-
 .../java/org/olat/course/CourseFactory.java   |   2 +-
 .../ui/mode/AssessmentModeListController.java |  50 ++++----
 .../mode/AssessmentModeSecurityCallback.java  |  34 ++++++
 ...AssessmentModeSecurityCallbackFactory.java |  52 +++++++++
 .../ui/mode/_content/mode_list.html           |   8 +-
 .../AssessmentCourseOverviewController.java   |   2 +-
 .../PersistingCourseGroupManager.java         |   2 +-
 .../course/member/MemberListController.java   |   6 +-
 .../MemberListWithOriginFilterController.java |   5 +-
 .../course/member/MemberSearchController.java |   5 +-
 .../MembersManagementMainController.java      |  33 ++++--
 .../member/MembersOverviewController.java     |  39 +++----
 .../course/nodes/GoToMeetingCourseNode.java   |   5 +-
 .../course/nodes/OpenMeetingsCourseNode.java  |   5 +-
 .../org/olat/course/nodes/STCourseNode.java   |   5 +-
 .../olat/course/nodes/ViteroCourseNode.java   |   4 +-
 .../nodes/basiclti/LTIRunController.java      |   6 +-
 .../nodes/bc/BCCourseNodeRunController.java   |   6 +-
 .../course/nodes/cal/CourseCalendars.java     |  30 +++--
 .../nodes/cl/manager/CheckboxManagerImpl.java |   7 +-
 .../ui/DialogCourseNodeRunController.java     |   5 +-
 .../ui/GTAAssessmentDetailsController.java    |   2 +-
 .../GTACoachedParticipantListController.java  |   2 +-
 .../course/nodes/info/InfoRunController.java  |   3 +-
 .../projectbroker/ProjectListController.java  |   2 +-
 .../olat/course/nodes/sp/SPRunController.java |   9 +-
 .../course/nodes/ta/DropboxController.java    |   4 +-
 .../ta/DropboxScoringViewController.java      |   2 +-
 .../course/run/CourseRuntimeController.java   | 108 ++++++++++--------
 .../olat/course/run/RunMainController.java    |  11 +-
 .../calendar/CourseCalendarController.java    |   7 +-
 .../run/userview/UserCourseEnvironment.java   |   4 +-
 .../group/ui/edit/MemberListController.java   |   4 +-
 .../ui/main/AbstractMemberListController.java |  34 +++---
 .../ui/main/MemberListSecurityCallback.java   |  34 ++++++
 .../MemberListSecurityCallbackFactory.java    |  59 ++++++++++
 .../coach/ui/UserDetailsController.java       |   4 +-
 .../ui/AppealListRepositoryController.java    |  16 ++-
 .../ui/EditLectureBlockController.java        |  37 +++---
 .../ui/LectureListRepositoryController.java   |  56 ++++-----
 .../ui/LectureRepositoryAdminController.java  |  32 ++++--
 .../lecture/ui/LecturesSecurityCallback.java  |  40 +++++++
 .../ui/LecturesSecurityCallbackFactory.java   |  62 ++++++++++
 .../ParticipantListRepositoryController.java  |  32 ++----
 .../_content/admin_repository_lectures.html   |   2 +
 .../olat/repository/RepositoryManager.java    |   8 +-
 .../manager/RepositoryEntryAuthorQueries.java |   4 +
 .../model/RepositoryEntrySecurity.java        |  24 +++-
 .../ui/RepositoryEntryRuntimeController.java  |   6 +-
 .../author/RepositoryMembersController.java   |   5 +-
 53 files changed, 641 insertions(+), 297 deletions(-)
 create mode 100644 src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallback.java
 create mode 100644 src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallbackFactory.java
 create mode 100644 src/main/java/org/olat/group/ui/main/MemberListSecurityCallback.java
 create mode 100644 src/main/java/org/olat/group/ui/main/MemberListSecurityCallbackFactory.java
 create mode 100644 src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallback.java
 create mode 100644 src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallbackFactory.java

diff --git a/src/main/java/de/bps/course/nodes/ChecklistCourseNode.java b/src/main/java/de/bps/course/nodes/ChecklistCourseNode.java
index f16873bae26..3341d7b8a7a 100644
--- a/src/main/java/de/bps/course/nodes/ChecklistCourseNode.java
+++ b/src/main/java/de/bps/course/nodes/ChecklistCourseNode.java
@@ -196,13 +196,12 @@ public class ChecklistCourseNode extends AbstractAccessableCourseNode {
 			UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd) {
 		ICourse course = CourseFactory.loadCourse(userCourseEnv.getCourseEnvironment().getCourseResourceableId());
 		CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
-		boolean canEdit = cgm.isIdentityCourseAdministrator(ureq.getIdentity());
+		boolean canEdit = userCourseEnv.isAdmin();
 		boolean canManage;
 		if(canEdit) {
 			canManage = true;
 		} else {
-			canManage = cgm.isIdentityCourseCoach(ureq.getIdentity())
-					|| cgm.hasRight(ureq.getIdentity(), CourseRights.RIGHT_GROUPMANAGEMENT);
+			canManage = userCourseEnv.isCoach() || cgm.hasRight(ureq.getIdentity(), CourseRights.RIGHT_GROUPMANAGEMENT);
 		}
 		Checklist checklist = loadOrCreateChecklist(userCourseEnv.getCourseEnvironment().getCoursePropertyManager());
 		ChecklistDisplayController checkController = new ChecklistDisplayController(ureq, wControl, checklist,
diff --git a/src/main/java/de/bps/course/nodes/VCCourseNode.java b/src/main/java/de/bps/course/nodes/VCCourseNode.java
index 35b5aa4f04f..5c2e0966deb 100644
--- a/src/main/java/de/bps/course/nodes/VCCourseNode.java
+++ b/src/main/java/de/bps/course/nodes/VCCourseNode.java
@@ -35,7 +35,6 @@ import org.olat.course.condition.ConditionEditController;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.editor.StatusDescription;
-import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.AbstractAccessableCourseNode;
 import org.olat.course.nodes.CourseNode;
 import org.olat.course.nodes.StatusDescriptionHelper;
@@ -134,8 +133,7 @@ public class VCCourseNode extends AbstractAccessableCourseNode {
 			UserCourseEnvironment userCourseEnv, NodeEvaluation ne, String nodecmd) {
 		updateModuleConfigDefaults(false);
 		// check if user is moderator of the virtual classroom
-		CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-		boolean moderator = cgm.isIdentityCourseAdministrator(ureq.getIdentity());
+		boolean moderator = userCourseEnv.isAdmin();
 
 		// load configuration
 		final String providerId = getModuleConfiguration().getStringValue(CONF_PROVIDER_ID);
diff --git a/src/main/java/de/bps/course/nodes/den/DENRunController.java b/src/main/java/de/bps/course/nodes/den/DENRunController.java
index bf05c7f2a7d..db92a3158f3 100644
--- a/src/main/java/de/bps/course/nodes/den/DENRunController.java
+++ b/src/main/java/de/bps/course/nodes/den/DENRunController.java
@@ -45,7 +45,6 @@ import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
-import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.ObjectivesHelper;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.modules.ModuleConfiguration;
@@ -110,9 +109,7 @@ public class DENRunController extends BasicController implements GenericEventLis
 		runVC = new VelocityContainer("dateVC", VELOCITY_ROOT + "/run.html", getTranslator(), this);
 		
 		//show only the options for managing dates and participants if user is admin or course coach
-		
-		CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
-		if(cgm.isIdentityCourseAdministrator(ureq.getIdentity()) || cgm.isIdentityCourseCoach(ureq.getIdentity())) {
+		if(userCourseEnv.isAdmin() || userCourseEnv.isCoach()) {
 			// subscription
 			subsContext = new SubscriptionContext(course, courseNode.getIdent());
 			// if sc is null, then no subscription is desired
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index 15b93c92580..32303428d76 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -635,7 +635,7 @@ public class CourseFactory {
 
 			ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(entry);
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ce, wControl);
-			RepositoryEntrySecurity reSecurity = new RepositoryEntrySecurity(false, false, false, false, false, false, false, false, false, false, true, false);
+			RepositoryEntrySecurity reSecurity = new RepositoryEntrySecurity(false, false, false, false, false, false, false, false, false, false, false, true, false);
 			return new RunMainController(ureq, bwControl, null, course, entry, reSecurity, null);
 		}
 	}
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java
index 67083d899b5..384d743abe2 100644
--- a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeListController.java
@@ -66,25 +66,28 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class AssessmentModeListController extends FormBasicController implements GenericEventListener {
 
+	private FormLink addLink;
+	private FormLink deleteLink;
 	private FlexiTableElement tableEl;
-	private FormLink addLink, deleteLink;
 	private AssessmentModeListModel model;
 	private final TooledStackedPanel toolbarPanel;
 
-	private DialogBoxController startDialogBox, stopDialogBox,deleteDialogBox;
+	private DialogBoxController startDialogBox, stopDialogBox, deleteDialogBox;
 	private AssessmentModeEditController editCtrl;
 	
 	private final RepositoryEntry entry;
+	private final AssessmentModeSecurityCallback secCallback;
 	
 	@Autowired
 	private AssessmentModeManager assessmentModeMgr;
 	@Autowired
 	private AssessmentModeCoordinationService assessmentModeCoordinationService;
 	
-	public AssessmentModeListController(UserRequest ureq, WindowControl wControl,
-			TooledStackedPanel toolbarPanel, RepositoryEntry entry) {
+	public AssessmentModeListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
+			RepositoryEntry entry, AssessmentModeSecurityCallback secCallback) {
 		super(ureq, wControl, "mode_list");
 		this.entry = entry;
+		this.secCallback = secCallback;
 		this.toolbarPanel = toolbarPanel;
 		toolbarPanel.addListener(this);
 		
@@ -105,13 +108,14 @@ public class AssessmentModeListController extends FormBasicController implements
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		addLink = uifactory.addFormLink("add", "add", "add.mode", null, formLayout, Link.BUTTON);
-		addLink.setElementCssClass("o_sel_assessment_mode_add");
-		addLink.setIconLeftCSS("o_icon o_icon_add");
-		
-		
-		deleteLink = uifactory.addFormLink("delete", "delete", "delete.mode", null, formLayout, Link.BUTTON);
-		deleteLink.setIconLeftCSS("o_icon o_icon_delete");
+		if(secCallback.canEditAssessmentMode()) {
+			addLink = uifactory.addFormLink("add", "add", "add.mode", null, formLayout, Link.BUTTON);
+			addLink.setElementCssClass("o_sel_assessment_mode_add");
+			addLink.setIconLeftCSS("o_icon o_icon_add");
+			
+			deleteLink = uifactory.addFormLink("delete", "delete", "delete.mode", null, formLayout, Link.BUTTON);
+			deleteLink.setIconLeftCSS("o_icon o_icon_delete");
+		}
 		
 		//add the table
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
@@ -126,16 +130,21 @@ public class AssessmentModeListController extends FormBasicController implements
 				true, Cols.followupTime.name(), new TimeCellRenderer(getTranslator())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.target.i18nKey(), Cols.target.ordinal(),
 				true, Cols.target.name(), new TargetAudienceCellRenderer(getTranslator())));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("start", Cols.start.ordinal(), "start",
+		
+		if(secCallback.canStartStopAssessment()) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("start", Cols.start.ordinal(), "start",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("start"), "start"), null)));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("stop", Cols.stop.ordinal(), "stop",
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("stop", Cols.stop.ordinal(), "stop",
 				new BooleanCellRenderer(new StaticFlexiCellRenderer(translate("stop"), "stop"), null)));
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit"));
+		}
+		if(secCallback.canEditAssessmentMode()) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit"));
+		}
 		
 		model = new AssessmentModeListModel(columnsModel, getTranslator(), assessmentModeCoordinationService);
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout);
-		tableEl.setMultiSelect(true);
-		tableEl.setSelectAllEnable(true);
+		tableEl.setMultiSelect(secCallback.canEditAssessmentMode());
+		tableEl.setSelectAllEnable(secCallback.canEditAssessmentMode());
 	}
 	
 	private void loadModel() {
@@ -143,9 +152,10 @@ public class AssessmentModeListController extends FormBasicController implements
 		model.setObjects(modes);
 		tableEl.reloadData();
 		// don't show table and button if there is nothing
-		tableEl.setVisible(modes.size() > 0);
-		deleteLink.setVisible(modes.size() > 0);
-
+		tableEl.setVisible(!modes.isEmpty());
+		if(deleteLink != null) {
+			deleteLink.setVisible(!modes.isEmpty());
+		}
 	}
 
 	@Override
@@ -210,7 +220,7 @@ public class AssessmentModeListController extends FormBasicController implements
 			if(index == null || index.isEmpty()) {
 				showWarning("error.atleastone");
 			} else {
-				List<AssessmentMode> rows = new ArrayList<AssessmentMode>(index.size());
+				List<AssessmentMode> rows = new ArrayList<>(index.size());
 				for(Integer i:index) {
 					rows.add(model.getObject(i.intValue()));
 				}
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallback.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallback.java
new file mode 100644
index 00000000000..c6d18ed9839
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallback.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.assessment.ui.mode;
+
+/**
+ * 
+ * Initial date: 20 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface AssessmentModeSecurityCallback {
+	
+	public boolean canStartStopAssessment();
+	
+	public boolean canEditAssessmentMode();
+
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallbackFactory.java b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallbackFactory.java
new file mode 100644
index 00000000000..c2bd2ec1f4b
--- /dev/null
+++ b/src/main/java/org/olat/course/assessment/ui/mode/AssessmentModeSecurityCallbackFactory.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.course.assessment.ui.mode;
+
+/**
+ * 
+ * Initial date: 20 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class AssessmentModeSecurityCallbackFactory {
+	
+	public static AssessmentModeSecurityCallback getSecurityCallback(boolean canModify) {
+		return new AssessmentModeSecurityCallbackImpl(canModify);
+	}
+	
+	private static class AssessmentModeSecurityCallbackImpl implements AssessmentModeSecurityCallback {
+		
+		private final boolean canModify;
+		
+		public AssessmentModeSecurityCallbackImpl(boolean canModify) {
+			this.canModify = canModify;
+		}
+
+		@Override
+		public boolean canStartStopAssessment() {
+			return canModify;
+		}
+
+		@Override
+		public boolean canEditAssessmentMode() {
+			return canModify;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/assessment/ui/mode/_content/mode_list.html b/src/main/java/org/olat/course/assessment/ui/mode/_content/mode_list.html
index 25e81e55c34..e5892a0f746 100644
--- a/src/main/java/org/olat/course/assessment/ui/mode/_content/mode_list.html
+++ b/src/main/java/org/olat/course/assessment/ui/mode/_content/mode_list.html
@@ -1,7 +1,11 @@
 <fieldset class="o_sel_assessment_mode_list">
 	<legend>$r.translate("modes.title")</legend>
 	<div class="o_info">$r.translate("modes.description")</div>
-	<div class="o_button_group o_button_group_right">$r.render("add")</div>
+	#if($r.available("add"))
+		<div class="o_button_group o_button_group_right">$r.render("add")</div>
+	#end
 	$r.render("table")
-	<div class="o_button_group">$r.render("delete")</div>
+	#if($r.available("delete"))
+		<div class="o_button_group">$r.render("delete")</div>
+	#end
 </fieldset>
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentCourseOverviewController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentCourseOverviewController.java
index bc2528f4d80..42092090f08 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/AssessmentCourseOverviewController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessmentCourseOverviewController.java
@@ -84,7 +84,7 @@ public class AssessmentCourseOverviewController extends BasicController {
 		
 		ICourse course = CourseFactory.loadCourse(courseEntry);
 		boolean hasAssessableNodes = course.hasAssessableNodes();
-		mainVC.contextPut("hasAssessableNodes", new Boolean(hasAssessableNodes));
+		mainVC.contextPut("hasAssessableNodes", Boolean.valueOf(hasAssessableNodes));
 		
 		// assessment changes subscription
 		if (hasAssessableNodes) {
diff --git a/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java b/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java
index 7c2a960ec4a..2f843be43bd 100644
--- a/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java
+++ b/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java
@@ -278,7 +278,7 @@ public class PersistingCourseGroupManager implements CourseGroupManager {
 		// not really a group management method, for your convenience we have a
 		// shortcut here...
 		return repositoryService.hasRoleExpanded(identity, getCourseEntry(), OrganisationRoles.administrator.name(),
-				OrganisationRoles.learnresourcemanager.name(), GroupRoles.owner.name());
+				OrganisationRoles.principal.name(), OrganisationRoles.learnresourcemanager.name(), GroupRoles.owner.name());
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/course/member/MemberListController.java b/src/main/java/org/olat/course/member/MemberListController.java
index c9a2f2d2d36..9975d055946 100644
--- a/src/main/java/org/olat/course/member/MemberListController.java
+++ b/src/main/java/org/olat/course/member/MemberListController.java
@@ -27,6 +27,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.course.assessment.ui.tool.AssessmentIdentityCourseController;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberListSecurityCallback;
 import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
@@ -43,8 +44,9 @@ public class MemberListController extends AbstractMemberListController {
 	private final UserCourseEnvironment coachCourseEnv;
 	
 	public MemberListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
-			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv, SearchMembersParams searchParams, String infos) {
-		super(ureq, wControl, repoEntry, "all_member_list", coachCourseEnv.isCourseReadOnly(), stackPanel);
+			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv, MemberListSecurityCallback secCallback,
+			SearchMembersParams searchParams, String infos) {
+		super(ureq, wControl, repoEntry, "all_member_list", secCallback, stackPanel);
 		this.searchParams = searchParams;
 		this.coachCourseEnv = coachCourseEnv;
 		
diff --git a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
index 6c0bb08ae71..741fe2003c4 100644
--- a/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
+++ b/src/main/java/org/olat/course/member/MemberListWithOriginFilterController.java
@@ -32,6 +32,7 @@ import org.olat.core.util.StringHelper;
 import org.olat.course.assessment.ui.tool.AssessmentIdentityCourseController;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberListSecurityCallback;
 import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.group.ui.main.SearchMembersParams.Origin;
@@ -53,8 +54,8 @@ public class MemberListWithOriginFilterController extends AbstractMemberListCont
 	private final UserCourseEnvironment coachCourseEnv;
 	
 	public MemberListWithOriginFilterController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
-			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv, SearchMembersParams searchParams, String infos) {
-		super(ureq, wControl, repoEntry, "member_list_origin_filter", coachCourseEnv.isCourseReadOnly(), toolbarPanel);
+			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv, MemberListSecurityCallback secCallback, SearchMembersParams searchParams, String infos) {
+		super(ureq, wControl, repoEntry, "member_list_origin_filter", secCallback, toolbarPanel);
 		this.searchParams = searchParams;
 		this.coachCourseEnv = coachCourseEnv;
 		
diff --git a/src/main/java/org/olat/course/member/MemberSearchController.java b/src/main/java/org/olat/course/member/MemberSearchController.java
index 1961cac5396..cf897083f68 100644
--- a/src/main/java/org/olat/course/member/MemberSearchController.java
+++ b/src/main/java/org/olat/course/member/MemberSearchController.java
@@ -29,6 +29,7 @@ import org.olat.core.id.Identity;
 import org.olat.course.assessment.ui.tool.AssessmentIdentityCourseController;
 import org.olat.course.run.userview.UserCourseEnvironment;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberListSecurityCallback;
 import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.repository.RepositoryEntry;
@@ -46,8 +47,8 @@ public class MemberSearchController extends AbstractMemberListController {
 	private AssessmentIdentityCourseController identityAssessmentController;
 	
 	public MemberSearchController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
-			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv) {
-		super(ureq, wControl, repoEntry, "all_member_list", coachCourseEnv.isCourseReadOnly(), toolbarPanel);
+			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv, MemberListSecurityCallback secCallback) {
+		super(ureq, wControl, repoEntry, "all_member_list", secCallback, toolbarPanel);
 		this.coachCourseEnv = coachCourseEnv;
 	}
 
diff --git a/src/main/java/org/olat/course/member/MembersManagementMainController.java b/src/main/java/org/olat/course/member/MembersManagementMainController.java
index 610d9e1c8f0..7974490eaac 100644
--- a/src/main/java/org/olat/course/member/MembersManagementMainController.java
+++ b/src/main/java/org/olat/course/member/MembersManagementMainController.java
@@ -47,6 +47,8 @@ import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.groupsandrights.GroupsAndRightsController;
 import org.olat.course.run.userview.UserCourseEnvironment;
+import org.olat.group.ui.main.MemberListSecurityCallback;
+import org.olat.group.ui.main.MemberListSecurityCallbackFactory;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
 import org.olat.resource.accesscontrol.ACService;
@@ -84,7 +86,11 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 	private RepositoryEntry repoEntry;
 	private final UserCourseEnvironment coachCourseEnv;
 	
-	private final boolean entryAdmin, groupManagementRight, memberManagementRight;
+	private final boolean entryAdmin;
+	private final boolean principal;
+	private final boolean groupManagementRight;
+	private final boolean memberManagementRight;
+	private final MemberListSecurityCallback secCallback;
 	
 	@Autowired
 	private ACService acService;
@@ -92,15 +98,18 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 	private AccessControlModule acModule;
 
 	public MembersManagementMainController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
-			RepositoryEntry re, UserCourseEnvironment coachCourseEnv, boolean entryAdmin,
+			RepositoryEntry re, UserCourseEnvironment coachCourseEnv, boolean entryAdmin, boolean principal,
 			boolean groupManagementRight, boolean memberManagementRight) {
 		super(ureq, wControl);
 		this.repoEntry = re;
 		this.toolbarPanel = toolbarPanel;
 		this.entryAdmin = entryAdmin;
+		this.principal = principal;
 		this.groupManagementRight = groupManagementRight;
 		this.memberManagementRight = memberManagementRight;
 		this.coachCourseEnv = coachCourseEnv;
+		secCallback = MemberListSecurityCallbackFactory.getSecurityCallback(coachCourseEnv.isCourseReadOnly(),
+				entryAdmin || groupManagementRight || memberManagementRight);
 
 		//logging
 		getUserActivityLogger().setStickyActionType(ActionType.admin);
@@ -119,7 +128,7 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 		listenTo(columnLayoutCtr);
 		putInitialPanel(columnLayoutCtr.getInitialComponent());
 		
-		if(entryAdmin || memberManagementRight) {
+		if(entryAdmin || principal || memberManagementRight) {
 			selectMenuItem(ureq, CMD_MEMBERS);
 		} else if(groupManagementRight) {
 			selectMenuItem(ureq, CMD_GROUPS);
@@ -133,21 +142,21 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 		root.setAltText(translate("menu.members.alt"));
 		gtm.setRootNode(root);
 		
-		if(entryAdmin || memberManagementRight) {
+		if(entryAdmin || principal || memberManagementRight) {
 			GenericTreeNode node = new GenericTreeNode(translate("menu.members"), CMD_MEMBERS);
 			node.setAltText(translate("menu.members.alt"));
 			node.setCssClass("o_sel_membersmgt_members");
 			root.addChild(node);
 		}
 
-		if(entryAdmin || memberManagementRight || groupManagementRight) {
+		if(entryAdmin || principal || memberManagementRight || groupManagementRight) {
 			GenericTreeNode node = new GenericTreeNode(translate("menu.groups"), CMD_GROUPS);
 			node.setAltText(translate("menu.groups.alt"));
 			node.setCssClass("o_sel_membersmgt_groups");
 			root.addChild(node);
 		}
 
-		if(acModule.isEnabled() && (entryAdmin || memberManagementRight)) {
+		if(acModule.isEnabled() && (entryAdmin || principal ||  memberManagementRight)) {
 			//check if the course is managed and/or has offers
 			if(!RepositoryEntryManagedFlag.isManaged(repoEntry, RepositoryEntryManagedFlag.bookings)
 					|| acService.isResourceAccessControled(repoEntry.getOlatResource(), null)) {
@@ -158,7 +167,7 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 			}
 		}
 
-		if(entryAdmin) {
+		if(entryAdmin || principal) {
 			GenericTreeNode node = new GenericTreeNode(translate("menu.rights"), CMD_RIGHTS);
 			node.setAltText(translate("menu.rights.alt"));
 			node.setCssClass("o_sel_membersmgt_rights");
@@ -214,9 +223,9 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 		
 		Controller selectedCtrl = null;
 		if(CMD_MEMBERS.equals(cmd)) {
-			if(entryAdmin || memberManagementRight) {
+			if(entryAdmin ||  principal || memberManagementRight) {
 				if(membersOverviewCtrl == null) {
-					membersOverviewCtrl = new MembersOverviewController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv);
+					membersOverviewCtrl = new MembersOverviewController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback);
 					listenTo(membersOverviewCtrl);
 				} else if(membersDirty) {
 					membersOverviewCtrl.reloadMembers();
@@ -225,7 +234,7 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 				selectedCtrl = membersOverviewCtrl;
 			}
 		} else if(CMD_GROUPS.equals(cmd)) {
-			if(entryAdmin || memberManagementRight || groupManagementRight) {
+			if(entryAdmin ||  principal || memberManagementRight || groupManagementRight) {
 				if(groupsCtrl == null) {
 					groupsCtrl = new CourseBusinessGroupListController(ureq, bwControl, repoEntry, entryAdmin || groupManagementRight, coachCourseEnv.isCourseReadOnly());
 					listenTo(groupsCtrl);
@@ -235,7 +244,7 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 				selectedCtrl = groupsCtrl;
 			}
 		} else if(CMD_BOOKING.equals(cmd)) {
-			if(acModule.isEnabled() && (entryAdmin || memberManagementRight)) {
+			if(acModule.isEnabled() && (entryAdmin ||  principal || memberManagementRight)) {
 				if(ordersController == null) {
 					ordersController = new OrdersAdminController(ureq, bwControl, toolbarPanel, repoEntry.getOlatResource());
 					listenTo(ordersController);
@@ -244,7 +253,7 @@ public class MembersManagementMainController extends MainLayoutBasicController i
 				selectedCtrl = ordersController;
 			}
 		} else if(CMD_RIGHTS.equals(cmd)) {
-			if(entryAdmin) {
+			if(entryAdmin ||  principal) {
 				if(rightsController == null) {
 					rightsController = new GroupsAndRightsController(ureq, bwControl, repoEntry, coachCourseEnv.isCourseReadOnly());
 					listenTo(rightsController);
diff --git a/src/main/java/org/olat/course/member/MembersOverviewController.java b/src/main/java/org/olat/course/member/MembersOverviewController.java
index e98d3631797..43522a2c71e 100644
--- a/src/main/java/org/olat/course/member/MembersOverviewController.java
+++ b/src/main/java/org/olat/course/member/MembersOverviewController.java
@@ -62,6 +62,7 @@ import org.olat.group.BusinessGroupService;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.ui.main.AbstractMemberListController;
 import org.olat.group.ui.main.DedupMembersConfirmationController;
+import org.olat.group.ui.main.MemberListSecurityCallback;
 import org.olat.group.ui.main.MemberPermissionChangeEvent;
 import org.olat.group.ui.main.SearchMembersParams;
 import org.olat.modules.curriculum.CurriculumService;
@@ -112,6 +113,7 @@ public class MembersOverviewController extends BasicController implements Activa
 	private boolean overrideManaged = false;
 	private final RepositoryEntry repoEntry;
 	private final UserCourseEnvironment coachCourseEnv;
+	private final MemberListSecurityCallback secCallback;
 	
 	@Autowired
 	private RepositoryManager repositoryManager;
@@ -123,11 +125,12 @@ public class MembersOverviewController extends BasicController implements Activa
 	private BusinessGroupService businessGroupService;
 	
 	public MembersOverviewController(UserRequest ureq, WindowControl wControl, TooledStackedPanel toolbarPanel,
-			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv) {
+			RepositoryEntry repoEntry, UserCourseEnvironment coachCourseEnv, MemberListSecurityCallback secCallback) {
 		super(ureq, wControl);
 		this.repoEntry = repoEntry;
 		this.toolbarPanel = toolbarPanel;
 		this.coachCourseEnv = coachCourseEnv;
+		this.secCallback = secCallback;
 		
 		mainVC = createVelocityContainer("members_overview");
 		segmentView = SegmentViewFactory.createSegmentView("segments", mainVC, this);
@@ -352,12 +355,9 @@ public class MembersOverviewController extends BasicController implements Activa
 		removeAsListenerAndDispose(importMembersWizard);
 
 		Step start = new ImportMember_1b_ChooseMemberStep(ureq, repoEntry, null, overrideManaged);
-		StepRunnerCallback finish = new StepRunnerCallback() {
-			@Override
-			public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
-				addMembers(uureq, runContext);
-				return StepsMainRunController.DONE_MODIFIED;
-			}
+		StepRunnerCallback finish = (uureq, wControl, runContext) -> {
+			addMembers(uureq, runContext);
+			return StepsMainRunController.DONE_MODIFIED;
 		};
 		
 		importMembersWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null,
@@ -370,15 +370,12 @@ public class MembersOverviewController extends BasicController implements Activa
 		removeAsListenerAndDispose(importMembersWizard);
 
 		Step start = new ImportMember_1a_LoginListStep(ureq, repoEntry, null, overrideManaged);
-		StepRunnerCallback finish = new StepRunnerCallback() {
-			@Override
-			public Step execute(UserRequest uureq, WindowControl wControl, StepsRunContext runContext) {
-				addMembers(uureq, runContext);
-				if(runContext.containsKey("notFounds")) {
-					showWarning("user.notfound", runContext.get("notFounds").toString());
-				}
-				return StepsMainRunController.DONE_MODIFIED;
+		StepRunnerCallback finish = (uureq, wControl, runContext) -> {
+			addMembers(uureq, runContext);
+			if(runContext.containsKey("notFounds")) {
+				showWarning("user.notfound", runContext.get("notFounds").toString());
 			}
+			return StepsMainRunController.DONE_MODIFIED;
 		};
 		
 		importMembersWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null,
@@ -457,7 +454,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(true, GroupRoles.owner, GroupRoles.coach, GroupRoles.participant);
-			allMemberListCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, null);
+			allMemberListCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback, searchParams, null);
 			listenTo(allMemberListCtrl);
 		}
 		
@@ -475,7 +472,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.owner);
 			String infos = translate("owners.infos");
-			ownersCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
+			ownersCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback, searchParams, infos);
 			listenTo(ownersCtrl);
 		}
 		
@@ -493,7 +490,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.coach);
 			String infos = translate("tutors.infos");
-			tutorsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
+			tutorsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback, searchParams, infos);
 			listenTo(tutorsCtrl);
 		}
 		
@@ -511,7 +508,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.participant);
 			String infos = translate("participants.infos");
-			participantsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
+			participantsCtrl = new MemberListWithOriginFilterController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback, searchParams, infos);
 			listenTo(participantsCtrl);
 		}
 		
@@ -529,7 +526,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			SearchMembersParams searchParams = new SearchMembersParams(false, GroupRoles.waiting);
 			String infos = translate("waiting.infos");
-			waitingCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, searchParams, infos);
+			waitingCtrl = new MemberListController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback, searchParams, infos);
 			listenTo(waitingCtrl);
 		}
 		
@@ -545,7 +542,7 @@ public class MembersOverviewController extends BasicController implements Activa
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(SEG_SEARCH_MEMBERS, 0l);
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
-			searchCtrl = new MemberSearchController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv);
+			searchCtrl = new MemberSearchController(ureq, bwControl, toolbarPanel, repoEntry, coachCourseEnv, secCallback);
 			listenTo(searchCtrl);
 		}
 	
diff --git a/src/main/java/org/olat/course/nodes/GoToMeetingCourseNode.java b/src/main/java/org/olat/course/nodes/GoToMeetingCourseNode.java
index 14c5d113eed..b04b87fbdb9 100644
--- a/src/main/java/org/olat/course/nodes/GoToMeetingCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/GoToMeetingCourseNode.java
@@ -109,9 +109,8 @@ public class GoToMeetingCourseNode extends AbstractAccessableCourseNode {
 			controller = MessageUIFactory.createInfoMessage(ureq, wControl, title, message);
 		} else {
 			// check if user is moderator of the virtual classroom
-			CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-			boolean admin = cgm.isIdentityCourseAdministrator(ureq.getIdentity());
-			boolean moderator = admin || cgm.isIdentityCourseCoach(ureq.getIdentity());
+			boolean admin = userCourseEnv.isAdmin();
+			boolean moderator = admin || userCourseEnv.isCoach();
 
 			// create run controller
 			RepositoryEntry courseEntry = userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry();
diff --git a/src/main/java/org/olat/course/nodes/OpenMeetingsCourseNode.java b/src/main/java/org/olat/course/nodes/OpenMeetingsCourseNode.java
index 95dd323a9f7..24f0153e0eb 100644
--- a/src/main/java/org/olat/course/nodes/OpenMeetingsCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/OpenMeetingsCourseNode.java
@@ -102,9 +102,8 @@ public class OpenMeetingsCourseNode extends AbstractAccessableCourseNode {
 		updateModuleConfigDefaults(false);
 
 		// check if user is moderator of the virtual classroom
-		CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-		boolean admin = cgm.isIdentityCourseAdministrator(ureq.getIdentity());
-		boolean moderator = admin || cgm.isIdentityAnyCourseCoach(ureq.getIdentity());
+		boolean admin = userCourseEnv.isAdmin();
+		boolean moderator = admin || userCourseEnv.isCoach();
 
 		// create run controller
 		OLATResourceable ores = OresHelper.clone(userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseResource());
diff --git a/src/main/java/org/olat/course/nodes/STCourseNode.java b/src/main/java/org/olat/course/nodes/STCourseNode.java
index 7e6583749c6..84667ef192b 100644
--- a/src/main/java/org/olat/course/nodes/STCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/STCourseNode.java
@@ -176,9 +176,8 @@ public class STCourseNode extends AbstractAccessableCourseNode implements Calcul
 					userCourseEnv.getCourseEnvironment().isPreview());
 			// check if user is allowed to edit the page in the run view
 			CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-			boolean hasEditRights = (cgm.isIdentityCourseAdministrator(ureq.getIdentity()) 
-					|| cgm.hasRight(ureq.getIdentity(),CourseRights.RIGHT_COURSEEDITOR))
-					|| (getModuleConfiguration().getBooleanSafe(SPEditController.CONFIG_KEY_ALLOW_COACH_EDIT, false) && cgm.isIdentityCourseCoach(ureq.getIdentity()));
+			boolean hasEditRights = userCourseEnv.isAdmin() || cgm.hasRight(ureq.getIdentity(),CourseRights.RIGHT_COURSEEDITOR)
+					|| (getModuleConfiguration().getBooleanSafe(SPEditController.CONFIG_KEY_ALLOW_COACH_EDIT, false) && userCourseEnv.isCoach());
 			
 			if (hasEditRights) {
 				spCtr.allowPageEditing();
diff --git a/src/main/java/org/olat/course/nodes/ViteroCourseNode.java b/src/main/java/org/olat/course/nodes/ViteroCourseNode.java
index 66da0fad109..bed4f7e4d41 100644
--- a/src/main/java/org/olat/course/nodes/ViteroCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/ViteroCourseNode.java
@@ -39,7 +39,6 @@ import org.olat.course.condition.ConditionEditController;
 import org.olat.course.editor.CourseEditorEnv;
 import org.olat.course.editor.NodeEditController;
 import org.olat.course.editor.StatusDescription;
-import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.nodes.vitero.ViteroEditController;
 import org.olat.course.nodes.vitero.ViteroPeekViewController;
 import org.olat.course.run.navigation.NodeRunConstructionResult;
@@ -103,8 +102,7 @@ public class ViteroCourseNode extends AbstractAccessableCourseNode {
 			runCtr = MessageUIFactory.createInfoMessage(ureq, wControl, title, message);
 		} else {
 			// check if user is moderator of the virtual classroom
-			CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-			boolean moderator = cgm.isIdentityCourseAdministrator(ureq.getIdentity());
+			boolean moderator = userCourseEnv.isAdmin();
 			// create run controller
 			Long resourceId = userCourseEnv.getCourseEnvironment().getCourseResourceableId();
 			OLATResourceable ores = OresHelper.createOLATResourceableInstance(CourseModule.class, resourceId);
diff --git a/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java b/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java
index d32bcbf7c39..b7ce93d27d6 100644
--- a/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java
+++ b/src/main/java/org/olat/course/nodes/basiclti/LTIRunController.java
@@ -53,7 +53,6 @@ import org.olat.core.util.Encoder;
 import org.olat.core.util.SortedProperties;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
-import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.highscore.ui.HighScoreRunController;
 import org.olat.course.nodes.BasicLTICourseNode;
 import org.olat.course.nodes.CourseNode;
@@ -477,8 +476,7 @@ public class LTIRunController extends BasicController {
 		if (roles.isGuestOnly()) {
 			return "Guest";
 		}
-		CourseGroupManager groupManager = courseEnv.getCourseGroupManager();
-		boolean admin = groupManager.isIdentityCourseAdministrator(getIdentity());
+		boolean admin = userCourseEnv.isAdmin();
 		if(admin) {
 			String authorRole = config.getStringValue(BasicLTICourseNode.CONFIG_KEY_AUTHORROLE);
 			if(StringHelper.containsNonWhitespace(authorRole)) {
@@ -486,7 +484,7 @@ public class LTIRunController extends BasicController {
 			}
 			return "Instructor,Administrator";
 		}
-		boolean coach = groupManager.isIdentityCourseCoach(getIdentity());
+		boolean coach = userCourseEnv.isCoach();
 		if(coach) {
 			String coachRole = config.getStringValue(BasicLTICourseNode.CONFIG_KEY_COACHROLE);
 			if(StringHelper.containsNonWhitespace(coachRole)) {
diff --git a/src/main/java/org/olat/course/nodes/bc/BCCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/bc/BCCourseNodeRunController.java
index ef7729a5694..6e8013eb189 100644
--- a/src/main/java/org/olat/course/nodes/bc/BCCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/bc/BCCourseNodeRunController.java
@@ -106,7 +106,7 @@ public class BCCourseNodeRunController extends BasicController implements Activa
 		VFSSecurityCallback scallback;
 		if(courseNode.getModuleConfiguration().getBooleanSafe(BCCourseNodeEditController.CONFIG_AUTO_FOLDER)) {
 			OlatNamedContainerImpl directory = BCCourseNode.getNodeFolderContainer(courseNode, courseEnv);
-			boolean isAdministrator = cgm.isIdentityCourseAdministrator(getIdentity());
+			boolean isAdministrator = userCourseEnv.isAdmin();
 			scallback = new FolderNodeCallback(directory.getRelPath(), ne, isAdministrator, isGuestOnly, nodefolderSubContext);
 			target = directory;
 		} else if(courseNode.isSharedFolder()) {
@@ -152,7 +152,7 @@ public class BCCourseNodeRunController extends BasicController implements Activa
 				} else {
 					relPath = VFSManager.getRelativeItemPath(target, courseContainer, null);
 				}
-				boolean isAdministrator = cgm.isIdentityCourseAdministrator(getIdentity());
+				boolean isAdministrator = userCourseEnv.isAdmin();
 				scallback = new FolderNodeCallback(relPath, ne, isAdministrator, isGuestOnly, nodefolderSubContext);
 			}
 		}
@@ -167,7 +167,7 @@ public class BCCourseNodeRunController extends BasicController implements Activa
 
 			VFSContainer courseContainer = null;
 			if(scallback.canWrite() && scallback.canCopy()) {
-				if (cgm.isIdentityCourseAdministrator(getIdentity()) || cgm.hasRight(getIdentity(), CourseRights.RIGHT_COURSEEDITOR)) {
+				if (userCourseEnv.isAdmin() || cgm.hasRight(getIdentity(), CourseRights.RIGHT_COURSEEDITOR)) {
 					// use course folder as copy source
 					courseContainer = courseEnv.getCourseFolderContainer();
 				}
diff --git a/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java b/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java
index 090ffc3e035..4e50870eb8b 100644
--- a/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java
+++ b/src/main/java/org/olat/course/nodes/cal/CourseCalendars.java
@@ -90,23 +90,21 @@ public class CourseCalendars {
 	 * @param ne
 	 * @return
 	 */
-	public static KalendarRenderWrapper getCourseCalendarWrapper(UserRequest ureq, UserCourseEnvironment courseEnv, NodeEvaluation ne) {
+	public static KalendarRenderWrapper getCourseCalendarWrapper(UserRequest ureq, UserCourseEnvironment userCourseEnv, NodeEvaluation ne) {
 		CalendarManager calendarManager = CoreSpringFactory.getImpl(CalendarManager.class);
 		// add course calendar
-		ICourse course = CourseFactory.loadCourse(courseEnv.getCourseEnvironment().getCourseResourceableId());
+		ICourse course = CourseFactory.loadCourse(userCourseEnv.getCourseEnvironment().getCourseResourceableId());
 		KalendarRenderWrapper courseKalendarWrapper = calendarManager.getCourseCalendar(course);
-		CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
-		boolean isPrivileged = !courseEnv.isCourseReadOnly() &&
-				(courseEnv.isAdmin()
-				  || (ne != null && ne.isCapabilityAccessible(CalCourseNode.EDIT_CONDITION_ID))
-				  || cgm.isIdentityCourseAdministrator(ureq.getIdentity()));
+		boolean isPrivileged = !userCourseEnv.isCourseReadOnly() &&
+				(userCourseEnv.isAdmin()
+				  || (ne != null && ne.isCapabilityAccessible(CalCourseNode.EDIT_CONDITION_ID)));
 		
 		if (isPrivileged) {
 			courseKalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_WRITE);
 			courseKalendarWrapper.setPrivateEventsVisible(true);
 		} else {
 			courseKalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_ONLY);
-			courseKalendarWrapper.setPrivateEventsVisible(courseEnv.isAdmin() || courseEnv.isCoach() || courseEnv.isParticipant());
+			courseKalendarWrapper.setPrivateEventsVisible(userCourseEnv.isAdmin() || userCourseEnv.isCoach() || userCourseEnv.isParticipant());
 		}
 		CalendarUserConfiguration config = calendarManager.findCalendarConfigForIdentity(courseKalendarWrapper.getKalendar(), ureq.getIdentity());
 		if (config != null) {
@@ -115,10 +113,10 @@ public class CourseCalendars {
 		return courseKalendarWrapper;
 	}
 
-	public static CourseCalendars createCourseCalendarsWrapper(UserRequest ureq, WindowControl wControl, UserCourseEnvironment courseEnv, NodeEvaluation ne) {
+	public static CourseCalendars createCourseCalendarsWrapper(UserRequest ureq, WindowControl wControl, UserCourseEnvironment userCourseEnv, NodeEvaluation ne) {
 		List<KalendarRenderWrapper> calendars = new ArrayList<>();
-		ICourse course = CourseFactory.loadCourse(courseEnv.getCourseEnvironment().getCourseResourceableId());
-		KalendarRenderWrapper courseKalendarWrapper = getCourseCalendarWrapper(ureq, courseEnv, ne);
+		ICourse course = CourseFactory.loadCourse(userCourseEnv.getCourseEnvironment().getCourseResourceableId());
+		KalendarRenderWrapper courseKalendarWrapper = getCourseCalendarWrapper(ureq, userCourseEnv, ne);
 		// add link provider
 		
 		CourseLinkProviderController clpc = new CourseLinkProviderController(course, Collections.singletonList(course), ureq, wControl);
@@ -130,25 +128,25 @@ public class CourseCalendars {
 
 		// add course group calendars
 		Roles roles = ureq.getUserSession().getRoles();
-		boolean isGroupManager = roles.isGroupManager() || cgm.isIdentityCourseAdministrator(identity)
+		boolean isGroupManager = roles.isGroupManager() || userCourseEnv.isAdmin()
 				|| cgm.hasRight(identity, CourseRights.RIGHT_GROUPMANAGEMENT);
-		boolean readOnly = courseEnv.isCourseReadOnly();
+		boolean readOnly = userCourseEnv.isCourseReadOnly();
 		
 		if (isGroupManager) {
 			// learning groups
 			List<BusinessGroup> allGroups = cgm.getAllBusinessGroups();
-			addCalendars(ureq, courseEnv, allGroups, !readOnly, clpc, calendars);
+			addCalendars(ureq, userCourseEnv, allGroups, !readOnly, clpc, calendars);
 		} else {
 			// learning groups
 			List<BusinessGroup> ownerGroups = cgm.getOwnedBusinessGroups(identity);
-			addCalendars(ureq, courseEnv, ownerGroups, !readOnly, clpc, calendars);
+			addCalendars(ureq, userCourseEnv, ownerGroups, !readOnly, clpc, calendars);
 			List<BusinessGroup> attendedGroups = cgm.getParticipatingBusinessGroups(identity);
 			for (BusinessGroup ownerGroup : ownerGroups) {
 				if (attendedGroups.contains(ownerGroup)) {
 					attendedGroups.remove(ownerGroup);
 				}
 			}
-			addCalendars(ureq, courseEnv, attendedGroups, false, clpc, calendars);
+			addCalendars(ureq, userCourseEnv, attendedGroups, false, clpc, calendars);
 		}
 		return new CourseCalendars(courseKalendarWrapper, calendars);
 	}
diff --git a/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java b/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java
index 36740483440..ff97eefb31a 100644
--- a/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java
+++ b/src/main/java/org/olat/course/nodes/cl/manager/CheckboxManagerImpl.java
@@ -458,13 +458,12 @@ public class CheckboxManagerImpl implements CheckboxManager {
 		
 		if(admin) {
 			sb.append(" and exists (select participant.key from bgroupmember as participant")
-	          .append("      baseGroup.key=participant.group and participant.role='").append(GroupRoles.participant.name()).append("'")
+	          .append("   where baseGroup.key=participant.group and participant.role='").append(GroupRoles.participant.name()).append("'")
 	          .append(" )");
 		} else {
 			sb.append(" and exists (select participant.key from bgroupmember as participant, bgroupmember as coach")
-	          .append("    where")
-	          .append("      baseGroup.key=coach.group and coach.role='").append(GroupRoles.coach.name()).append("' and coach.identity.key=:coachKey")
-	          .append("      and baseGroup.key=participant.group and participant.role='").append(GroupRoles.participant.name()).append("'")
+	          .append("   where baseGroup.key=coach.group and coach.role='").append(GroupRoles.coach.name()).append("' and coach.identity.key=:coachKey")
+	          .append("   and baseGroup.key=participant.group and participant.role='").append(GroupRoles.participant.name()).append("'")
 	          .append(" )");
 		}
 	
diff --git a/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java b/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java
index 661183928f7..7a66858b498 100644
--- a/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java
+++ b/src/main/java/org/olat/course/nodes/dialog/ui/DialogCourseNodeRunController.java
@@ -151,9 +151,8 @@ public class DialogCourseNodeRunController extends BasicController implements Ac
 		
 		backButton = LinkFactory.createLinkBack(mainVC, this);
 		
-		if (!userCourseEnv.isCourseReadOnly() && (isAdministrator
-					|| cgm.isIdentityCourseAdministrator(getIdentity())
-					|| cgm.hasRight(getIdentity(), CourseRights.RIGHT_COURSEEDITOR))) {
+		if (!userCourseEnv.isCourseReadOnly()
+				&& (isAdministrator || userCourseEnv.isAdmin() || cgm.hasRight(getIdentity(), CourseRights.RIGHT_COURSEEDITOR))) {
 			copyButton = LinkFactory.createButton("dialog.copy.file", mainVC, this);
 		}
 		
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java
index 298f3752ce9..8bdd3ea5030 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTAAssessmentDetailsController.java
@@ -93,7 +93,7 @@ public class GTAAssessmentDetailsController extends BasicController implements A
 			}
 			
 			CourseGroupManager cgm = courseEnv.getCourseGroupManager();
-			if(!cgm.isIdentityCourseAdministrator(getIdentity())) {
+			if(!coachCourseEnv.isAdmin()) {
 				RepositoryEntry courseRe = cgm.getCourseEntry();
 				List<String> reRoles = repositoryService.getRoles(getIdentity(), courseRe);
 				if(reRoles.contains(GroupRoles.owner.name())) {
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
index 3d500658987..fa208a9284b 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/GTACoachedParticipantListController.java
@@ -228,7 +228,7 @@ public class GTACoachedParticipantListController extends GTACoachedListControlle
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CGCols.numOfSubmissionDocs.i18nKey(), CGCols.numOfSubmissionDocs.ordinal(),
 				true, CGCols.numOfSubmissionDocs.name()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select", translate("select"), "select"));
-		if(gtaManager.isDueDateEnabled(gtaNode)) {
+		if(gtaManager.isDueDateEnabled(gtaNode) && !coachCourseEnv.isCourseReadOnly()) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.header.duedates", translate("duedates"), "duedates"));
 		}
 		tableModel = new CoachParticipantsTableModel(userPropertyHandlers, getLocale(), columnsModel);
diff --git a/src/main/java/org/olat/course/nodes/info/InfoRunController.java b/src/main/java/org/olat/course/nodes/info/InfoRunController.java
index a13c5ed76f3..0357267bb55 100644
--- a/src/main/java/org/olat/course/nodes/info/InfoRunController.java
+++ b/src/main/java/org/olat/course/nodes/info/InfoRunController.java
@@ -110,8 +110,7 @@ public class InfoRunController extends BasicController {
 			canAdd = false;
 			canAdmin = false;
 		} else {
-			Identity identity = getIdentity();
-			boolean isAdmin = cgm.isIdentityCourseAdministrator(identity);
+			boolean isAdmin = userCourseEnv.isAdmin();
 			canAdd = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.EDIT_CONDITION_ID);
 			canAdmin = isAdmin || ne.isCapabilityAccessible(InfoCourseNode.ADMIN_CONDITION_ID);
 		}
diff --git a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java
index c781f68db7d..345d24fa370 100644
--- a/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java
+++ b/src/main/java/org/olat/course/nodes/projectbroker/ProjectListController.java
@@ -155,7 +155,7 @@ public class ProjectListController extends BasicController implements GenericEve
 		mainPanel = new SimpleStackedPanel("projectlist_panel");
 		CoursePropertyManager cpm = userCourseEnv.getCourseEnvironment().getCoursePropertyManager();
 		if ((projectGroupManager.isAccountManager(ureq.getIdentity(), cpm, courseNode ) && !previewMode)
-				|| userCourseEnv.getCourseEnvironment().getCourseGroupManager().isIdentityCourseAdministrator(ureq.getIdentity())) {
+				|| userCourseEnv.isAdmin()) {
 			contentVC.contextPut("isAccountManager", true);
 			createNewProjectButton = LinkFactory.createButtonSmall("create.new.project.button", contentVC, this);
 			createNewProjectButton.setIconLeftCSS("o_icon o_icon_add");
diff --git a/src/main/java/org/olat/course/nodes/sp/SPRunController.java b/src/main/java/org/olat/course/nodes/sp/SPRunController.java
index 9d02ff49d38..2c2a2d5d61d 100644
--- a/src/main/java/org/olat/course/nodes/sp/SPRunController.java
+++ b/src/main/java/org/olat/course/nodes/sp/SPRunController.java
@@ -114,7 +114,7 @@ public class SPRunController extends BasicController implements Activateable2 {
 		if (fileName == null) throw new AssertException("bad configuration at lauchtime: fileName cannot be null in SinglePage!");
 		this.courseFolderContainer = courseFolderContainer;
 		
-		hasEditRights = hasEditRights(ureq);
+		hasEditRights = hasEditRights();
 
 		if (hasEditRights) {
 			linkTreeModel = new CourseInternalLinkTreeModel(userCourseEnv.getCourseEnvironment().getRunStructure().getRootNode());
@@ -126,7 +126,7 @@ public class SPRunController extends BasicController implements Activateable2 {
 		putInitialPanel(main);
 	}
 	
-	private boolean hasEditRights(UserRequest ureq) {
+	private boolean hasEditRights() {
 		if(userCourseEnv.isCourseReadOnly()) return false;
 		
 		if(fileName != null && fileName.startsWith("/_sharedfolder")) {
@@ -137,9 +137,8 @@ public class SPRunController extends BasicController implements Activateable2 {
 		
 		if(isFileTypeEditable(fileName)) {
 			CourseGroupManager cgm = userCourseEnv.getCourseEnvironment().getCourseGroupManager();
-			return config.getBooleanSafe(SPEditController.CONFIG_KEY_ALLOW_COACH_EDIT, false) && cgm.isIdentityCourseCoach(ureq.getIdentity())
-					|| cgm.isIdentityCourseAdministrator(getIdentity())
-					|| cgm.hasRight(getIdentity(), CourseRights.RIGHT_COURSEEDITOR);
+			return (config.getBooleanSafe(SPEditController.CONFIG_KEY_ALLOW_COACH_EDIT, false) && userCourseEnv.isCoach())
+					|| userCourseEnv.isAdmin() || cgm.hasRight(getIdentity(), CourseRights.RIGHT_COURSEEDITOR);
 
 		}
 		return false;
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxController.java b/src/main/java/org/olat/course/nodes/ta/DropboxController.java
index 08cd0d4ca9d..761733a9678 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxController.java
@@ -129,9 +129,7 @@ public class DropboxController extends BasicController {
 		this.config = config;
 		this.node = node;
 		this.userCourseEnv = userCourseEnv;
-		boolean isCourseAdmin = userCourseEnv.getCourseEnvironment().getCourseGroupManager().isIdentityCourseAdministrator(ureq.getIdentity());
-		boolean isCourseCoach = userCourseEnv.getCourseEnvironment().getCourseGroupManager().isIdentityCourseCoach(ureq.getIdentity());
-		boolean hasNotification = (isCourseAdmin || isCourseCoach);
+		boolean hasNotification = userCourseEnv.isAdmin() || userCourseEnv.isCoach();
 		init(ureq, wControl, previewMode, hasNotification);
 	}
 	
diff --git a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
index cb7693951a9..6885027bd39 100644
--- a/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
+++ b/src/main/java/org/olat/course/nodes/ta/DropboxScoringViewController.java
@@ -209,7 +209,7 @@ public class DropboxScoringViewController extends BasicController {
 
 		// insert Status Pull-Down Menu depending on user role == author
 		boolean isAuthor = ureq.getUserSession().getRoles().isAuthor();
-		boolean isTutor  = userCourseEnv.getCourseEnvironment().getCourseGroupManager().isIdentityCourseCoach(ureq.getIdentity());
+		boolean isTutor  = userCourseEnv.isCoach();
 		if ( ((AssessableCourseNode)node).hasStatusConfigured() && (isAuthor || isTutor)) {
 			myContent.contextPut("hasStatusPullDown", Boolean.TRUE);
 			statusForm = new StatusForm(ureq, getWindowControl(), userCourseEnv.isCourseReadOnly());
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index 1eb82378a68..b1a8a60acb8 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -90,6 +90,8 @@ import org.olat.course.area.CourseAreasController;
 import org.olat.course.assessment.AssessmentChangedEvent;
 import org.olat.course.assessment.AssessmentModule;
 import org.olat.course.assessment.ui.mode.AssessmentModeListController;
+import org.olat.course.assessment.ui.mode.AssessmentModeSecurityCallback;
+import org.olat.course.assessment.ui.mode.AssessmentModeSecurityCallbackFactory;
 import org.olat.course.assessment.ui.tool.AssessmentToolController;
 import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementController;
 import org.olat.course.certificate.ui.CertificatesOptionsController;
@@ -126,6 +128,8 @@ import org.olat.modules.assessment.ui.AssessmentToolSecurityCallback;
 import org.olat.modules.lecture.LectureModule;
 import org.olat.modules.lecture.LectureService;
 import org.olat.modules.lecture.ui.LectureRepositoryAdminController;
+import org.olat.modules.lecture.ui.LecturesSecurityCallback;
+import org.olat.modules.lecture.ui.LecturesSecurityCallbackFactory;
 import org.olat.modules.lecture.ui.TeacherOverviewController;
 import org.olat.modules.reminder.ReminderModule;
 import org.olat.note.NoteController;
@@ -271,8 +275,10 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		// group rights
 		UserCourseEnvironmentImpl uce = getUserCourseEnvironment();
 		if(uce != null) {
-			uce.setUserRoles(security.isEntryAdmin(), security.isCoach(), security.isParticipant());
-			if(security.isReadOnly()) {
+			uce.setUserRoles(security.isEntryAdmin() || security.isPrincipal(), security.isCoach(), security.isParticipant());
+			if(security.isOnlyPrincipal()) {
+				uce.setCourseReadOnly(Boolean.TRUE);
+			} else if(security.isReadOnly()) {
 				if(overrideReadOnly) {
 					uce.setCourseReadOnly(Boolean.FALSE);
 				} else {
@@ -300,7 +306,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 
 	private boolean hasCourseRight(String right) {
 		Boolean bool = courseRightsCache.get(right);
-		return bool == null ? false : bool.booleanValue();
+		return bool != null && bool.booleanValue();
 	}
 	
 	private UserCourseEnvironmentImpl getUserCourseEnvironment() {
@@ -447,7 +453,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	}
 	
 	private void setCourseClosedMessage(UserCourseEnvironment uce) {
-		if(uce != null && uce.isCourseReadOnly()) {
+		if(uce != null &&  getRepositoryEntry().getRepositoryEntryStatus().isClosed()) {
 			toolbarPanel.setMessage(translate("course.closed"));
 			toolbarPanel.setMessageCssClass("o_warning");
 		} else {
@@ -457,7 +463,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	
 	private void initTools(Dropdown tools, ICourse course, final UserCourseEnvironmentImpl uce) {
 		// 1) administrative tools
-		if (reSecurity.isEntryAdmin() || reSecurity.isCoach()
+		if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach()
 				|| hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)
 				|| hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_ARCHIVING)
 				|| hasCourseRight(CourseRights.RIGHT_STATISTICS) || hasCourseRight(CourseRights.RIGHT_DB)
@@ -474,19 +480,21 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				editLink.setEnabled(!corrupted && !managed);
 				editLink.setVisible(!readOnly);
 				tools.addComponent(editLink);
+			}
 				
+			if (uce != null && (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR))) {
 				folderLink = LinkFactory.createToolLink("cfd", translate("command.coursefolder"), this, "o_icon_coursefolder");
 				folderLink.setElementCssClass("o_sel_course_folder");
 				tools.addComponent(folderLink);
 				tools.addComponent(new Spacer(""));
 			}
 			
-			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)) {
 				membersLink = LinkFactory.createToolLink("unifiedusermngt", translate("command.opensimplegroupmngt"), this, "o_icon_membersmanagement");
 				membersLink.setElementCssClass("o_sel_course_members");
 				tools.addComponent(membersLink);
 			}
-			if (reSecurity.isEntryAdmin() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
 				assessmentLink = LinkFactory.createToolLink("assessment", translate("command.openassessment"), this, "o_icon_assessment_tool");
 				assessmentLink.setElementCssClass("o_sel_course_assessment_tool");
 				tools.addComponent(assessmentLink);
@@ -498,11 +506,11 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			
 			tools.addComponent(new Spacer(""));
 			
-			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) {
 				courseStatisticLink = LinkFactory.createToolLink("statistic",translate("command.openstatistic"), this, "o_icon_statistics_tool");
 				tools.addComponent(courseStatisticLink);
 			}
-			if (uce != null && (reSecurity.isEntryAdmin() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS))) {
+			if (uce != null && (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS))) {
 				final AtomicInteger testNodes = new AtomicInteger();
 				final AtomicInteger surveyNodes = new AtomicInteger();
 				new TreeVisitor(new Visitor() {
@@ -549,7 +557,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	@Override
 	protected void initSettingsTools(Dropdown settings) {
 		boolean courseAuthorRight = reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR);
-		if (courseAuthorRight || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) {
+		if (courseAuthorRight || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) {
 			boolean managed = RepositoryEntryManagedFlag.isManaged(getRepositoryEntry(), RepositoryEntryManagedFlag.editcontent);
 			UserCourseEnvironment uce = getUserCourseEnvironment();
 			if(uce == null) {
@@ -611,7 +619,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				settings.addComponent(reminderLink);
 			}
 			
-			if(courseAuthorRight && lectureModule.isEnabled()) {
+			if((courseAuthorRight || reSecurity.isPrincipal()) && lectureModule.isEnabled()) {
 				lecturesAdminLink = LinkFactory.createToolLink("lectures.admin.cmd", translate("command.options.lectures.admin"), this, "o_icon_lecture");
 				lecturesAdminLink.setElementCssClass("o_sel_course_lectures_admin");
 				lecturesAdminLink.setVisible(!uce.isCourseReadOnly());
@@ -781,6 +789,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	
 	private void initGeneralTools(ICourse course) {
 		boolean assessmentLock = isAssessmentLock();
+		UserCourseEnvironment userCourseEnv = getUserCourseEnvironment();
 
 		CourseConfig cc = course.getCourseConfig();
 		if (!assessmentLock && showInfos) {
@@ -790,7 +799,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		
 		boolean calendarIsEnabled =  !assessmentLock && !isGuestOnly && calendarModule.isEnabled()
 				&& calendarModule.isEnableCourseToolCalendar() && reSecurity.canLaunch();
-		if (calendarIsEnabled && getUserCourseEnvironment() != null) {
+		if (calendarIsEnabled && userCourseEnv != null) {
 			calendarLink = LinkFactory.createToolLink("calendar",translate("command.calendar"), this, "o_icon_calendar");
 			calendarLink.setPopup(new LinkPopupSettings(950, 750, "cal"));
 			calendarLink.setVisible(cc.isCalendarEnabled());
@@ -819,7 +828,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		//add group chat to toolbox
 		boolean chatIsEnabled = !assessmentLock && !isGuestOnly && imModule.isEnabled()
 				&& imModule.isCourseEnabled() && reSecurity.canLaunch();
-		if(chatIsEnabled && getUserCourseEnvironment() != null && !getUserCourseEnvironment().isCourseReadOnly()) {
+		if(chatIsEnabled && userCourseEnv != null && !userCourseEnv.isCourseReadOnly()) {
 			chatLink = LinkFactory.createToolLink("chat",translate("command.coursechat"), this, "o_icon_chat");
 			chatLink.setVisible(imModule.isCourseEnabled() && cc.isChatEnabled());
 			toolbarPanel.addTool(chatLink);
@@ -1113,7 +1122,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		}
 
 		entries = removeRepositoryEntry(entries);
-		if(entries != null && entries.size() > 0) {
+		if(entries != null && !entries.isEmpty()) {
 			String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
 			if("Payment".equalsIgnoreCase(type)) {
 				doPostSuccessfullAccess(ureq);
@@ -1164,7 +1173,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				}	
 			} else if ("assessmentTool".equalsIgnoreCase(type) || "assessmentToolv2".equalsIgnoreCase(type)) {
 				//check the security before, the link is perhaps in the wrong hands
-				if(reSecurity.isEntryAdmin() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
+				if(reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
 					try {
 						Activateable2 assessmentCtrl = doAssessmentTool(ureq);
 						if(assessmentCtrl != null) {
@@ -1182,7 +1191,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				}
 			} else if ("TestStatistics".equalsIgnoreCase(type) || "SurveyStatistics".equalsIgnoreCase(type)) {
 				//check the security before, the link is perhaps in the wrong hands
-				if(reSecurity.isEntryAdmin() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
+				if(reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) {
 					try {
 						Activateable2 assessmentCtrl = null;
 						if("TestStatistics".equalsIgnoreCase(type)) {
@@ -1268,15 +1277,15 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	@Override
 	protected Activateable2 doMembers(UserRequest ureq) {
 		if(delayedClose == Delayed.members || requestForClose(ureq)) {
-			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)) {
 				removeCustomCSS();
 				if(currentToolCtr instanceof MembersManagementMainController) {
 					((MembersManagementMainController)currentToolCtr).activate(ureq, null, null);
 				} else {
 					WindowControl bwControl = getSubWindowControl("MembersMgmt");
 					MembersManagementMainController ctrl = new MembersManagementMainController(ureq, addToHistory(ureq, bwControl), toolbarPanel,
-							getRepositoryEntry(), getUserCourseEnvironment(), reSecurity.isEntryAdmin(), hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT),
-							hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT));
+							getRepositoryEntry(), getUserCourseEnvironment(), reSecurity.isEntryAdmin(), reSecurity.isPrincipal(),
+							hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT), hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT));
 					listenTo(ctrl);
 					membersCtrl = pushController(ureq, translate("command.opensimplegroupmngt"), ctrl);
 					setActiveTool(membersLink);
@@ -1303,7 +1312,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	private void doConfirmLeave(UserRequest ureq) {
 		String title = translate("sign.out");
 
-		leaveDialogBox = new ConfirmLeaveController(ureq, getWindowControl(), this.getRepositoryEntry());
+		leaveDialogBox = new ConfirmLeaveController(ureq, getWindowControl(), getRepositoryEntry());
 		listenTo(leaveDialogBox);
 		cmc = new CloseableModalController(getWindowControl(), "close", leaveDialogBox.getInitialComponent(), true, title);
 		listenTo(cmc);
@@ -1339,7 +1348,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	private void doLifeCycleChange(UserRequest ureq) {
 		List<Link> breadCrumbs = toolbarPanel.getBreadCrumbs();
 		BreadCrumb lastCrumb = null;
-		if (breadCrumbs.size() > 0) {
+		if (!breadCrumbs.isEmpty()) {
 			lastCrumb = (BreadCrumb) breadCrumbs.get(breadCrumbs.size()-1).getUserObject();
 		}
 		if (lastCrumb == null || lastCrumb.getController() != lifeCycleChangeCtr) {
@@ -1389,10 +1398,13 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	
 	private void doAssessmentMode(UserRequest ureq) {
 		if(delayedClose == Delayed.assessmentMode || requestForClose(ureq)) {
-			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) {
 				removeCustomCSS();
+				
+				boolean canManage = reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE);
+				AssessmentModeSecurityCallback secCallback = AssessmentModeSecurityCallbackFactory.getSecurityCallback(canManage);
 				AssessmentModeListController ctrl = new AssessmentModeListController(ureq, getWindowControl(),
-						toolbarPanel, getRepositoryEntry());
+						toolbarPanel, getRepositoryEntry(), secCallback);
 				assessmentModeCtrl = pushController(ureq, translate("command.assessment.mode"), ctrl);
 				setActiveTool(assessmentModeLink);
 				currentToolCtr = assessmentModeCtrl;
@@ -1437,12 +1449,14 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	
 	private LectureRepositoryAdminController doLecturesAdmin(UserRequest ureq) {
 		if(delayedClose == Delayed.lecturesAdmin || requestForClose(ureq)) {
-			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) {
 				removeCustomCSS();
 
 				OLATResourceable ores = OresHelper.createOLATResourceableType("LecturesAdmin");
 				WindowControl swControl = addToHistory(ureq, ores, null);
-				LectureRepositoryAdminController ctrl = new LectureRepositoryAdminController(ureq, swControl, toolbarPanel, getRepositoryEntry());
+				LecturesSecurityCallback secCallback = LecturesSecurityCallbackFactory
+						.getSecurityCallback(reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR));
+				LectureRepositoryAdminController ctrl = new LectureRepositoryAdminController(ureq, swControl, toolbarPanel, getRepositoryEntry(), secCallback);
 				listenTo(ctrl);
 				lecturesAdminCtrl = pushController(ureq, translate("command.options.lectures.admin"), ctrl);
 				setActiveTool(lecturesAdminLink);
@@ -1550,7 +1564,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	
 	private void doCourseStatistics(UserRequest ureq) {
 		if(delayedClose == Delayed.courseStatistics || requestForClose(ureq)) {
-			if (reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) {
+			if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal()|| hasCourseRight(CourseRights.RIGHT_STATISTICS)) {
 				removeCustomCSS();
 				ICourse course = CourseFactory.loadCourse(getRepositoryEntry());
 				StatisticMainController ctrl = new StatisticMainController(ureq, getWindowControl(), course);
@@ -1598,7 +1612,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		OLATResourceable ores = OresHelper.createOLATResourceableType(typeName);
 		ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 		WindowControl swControl = addToHistory(ureq, ores, null);
-		if (reSecurity.isEntryAdmin() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) {
+		if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) {
 			removeCustomCSS();
 			UserCourseEnvironmentImpl uce = getUserCourseEnvironment();
 			StatisticCourseNodesController ctrl = new StatisticCourseNodesController(ureq, swControl, toolbarPanel,  reSecurity, uce, type);
@@ -1617,17 +1631,18 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl swControl = addToHistory(ureq, ores, null);
 			
-			boolean admin = reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT);
+			boolean admin = reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT);
 			boolean nonMembers = reSecurity.isEntryAdmin();
 			List<BusinessGroup> coachedGroups = null;
+			UserCourseEnvironment userCourseEnv = getUserCourseEnvironment();
 			if(reSecurity.isGroupCoach()) {
-				coachedGroups = getUserCourseEnvironment().getCoachedGroups();
+				coachedGroups = userCourseEnv.getCoachedGroups();
 			}
 			AssessmentToolSecurityCallback secCallBack
 				= new AssessmentToolSecurityCallback(admin, nonMembers, reSecurity.isCourseCoach(), reSecurity.isGroupCoach(), reSecurity.isCurriculumCoach(), coachedGroups);
 
 			removeCustomCSS();
-			AssessmentToolController ctrl = new AssessmentToolController(ureq, swControl, toolbarPanel, getRepositoryEntry(), getUserCourseEnvironment(), secCallBack);
+			AssessmentToolController ctrl = new AssessmentToolController(ureq, swControl, toolbarPanel, getRepositoryEntry(), userCourseEnv, secCallBack);
 			ctrl.activate(ureq, null, null);
 			listenTo(ctrl);
 			assessmentToolCtr = pushController(ureq, translate("command.openassessment"), ctrl);
@@ -1795,30 +1810,27 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			List<ContextEntry> entries = BusinessControlFactory.getInstance().createCEListFromResourceType(allowGlossaryEditing ? "true" : "false");
 			dts.activate(ureq, dt, entries);
 		} else {
-			ControllerCreator ctrlCreator = new ControllerCreator() {
-				public Controller createController(UserRequest lureq, WindowControl lwControl) {
-					GlossaryMainController glossaryController = CourseGlossaryFactory.createCourseGlossaryMainRunController(lwControl, lureq, cc, allowGlossaryEditing);
-					listenTo(glossaryController);
-					if (glossaryController == null) {
-						// happens in the unlikely event of a user who is in a course and
-						// now
-						// tries to access the glossary
-						String text = translate("error.noglossary");
-						return MessageUIFactory.createInfoMessage(lureq, lwControl, null, text);
-					} else {
-						// use a one-column main layout
-						LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, glossaryController);
-						// dispose glossary on layout dispose
-						layoutCtr.addDisposableChildController(glossaryController);
-						return layoutCtr;
-					}
+			ControllerCreator ctrlCreator = (lureq, lwControl) -> {
+				GlossaryMainController glossaryController = CourseGlossaryFactory.createCourseGlossaryMainRunController(lwControl, lureq, cc, allowGlossaryEditing);
+				listenTo(glossaryController);
+				if (glossaryController == null) {
+					// happens in the unlikely event of a user who is in a course and
+					// now
+					// tries to access the glossary
+					String text = translate("error.noglossary");
+					return MessageUIFactory.createInfoMessage(lureq, lwControl, null, text);
+				} else {
+					// use a one-column main layout
+					LayoutMain3ColsController layoutCtr = new LayoutMain3ColsController(lureq, lwControl, glossaryController);
+					// dispose glossary on layout dispose
+					layoutCtr.addDisposableChildController(glossaryController);
+					return layoutCtr;
 				}
 			};
 
 			ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createAuthMinimalPopupLayout(ureq, ctrlCreator);
 			// open in new browser window
 			openInNewBrowserWindow(ureq, layoutCtrlr);
-			return;// immediate return after opening new browser window!
 		}
 	}
 	
diff --git a/src/main/java/org/olat/course/run/RunMainController.java b/src/main/java/org/olat/course/run/RunMainController.java
index 40b43c56026..19fb3aadf27 100644
--- a/src/main/java/org/olat/course/run/RunMainController.java
+++ b/src/main/java/org/olat/course/run/RunMainController.java
@@ -94,7 +94,6 @@ import org.olat.group.BusinessGroup;
 import org.olat.group.ui.edit.BusinessGroupModifiedEvent;
 import org.olat.modules.cp.TreeNodeEvent;
 import org.olat.repository.RepositoryEntry;
-import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.util.logging.activity.LoggingResourceable;
@@ -137,9 +136,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 	private String courseTitle;
 	private Link nextLink, previousLink;
 	private GlossaryMarkupItemController glossaryMarkerCtr;
-	
-	@Autowired
-	private RepositoryManager repositoryManager;
+
 	@Autowired
 	private RepositoryService repositoryService;
 	
@@ -206,7 +203,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 
 		currentCourseNode = updateTreeAndContent(ureq, currentCourseNode, null);
 
-		if (courseRepositoryEntry != null && repositoryManager.createRepositoryEntryStatus(courseRepositoryEntry.getStatusCode()).isClosed()) {
+		if (courseRepositoryEntry != null && courseRepositoryEntry.getRepositoryEntryStatus().isClosed()) {
 			wControl.setWarning(translate("course.closed"));
 		}
 
@@ -319,8 +316,8 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 
 		return new UserCourseEnvironmentImpl(ureq.getUserSession().getIdentityEnvironment(), course.getCourseEnvironment(), getWindowControl(),
 				coachedGroups, participatedGroups, waitingLists,
-				reSecurity.isCoach(), reSecurity.isEntryAdmin(), reSecurity.isParticipant(),
-				reSecurity.isReadOnly());
+				reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal(), reSecurity.isParticipant(),
+				reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal());
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java b/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
index 8318e999ffd..3dc4ccb89f6 100644
--- a/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
+++ b/src/main/java/org/olat/course/run/calendar/CourseCalendarController.java
@@ -88,7 +88,7 @@ public class CourseCalendarController extends BasicController {
 		ICourse course = CourseFactory.loadCourse(userCourseEnv.getCourseEnvironment().getCourseGroupManager().getCourseEntry());
 		KalendarRenderWrapper courseKalendarWrapper = calendarManager.getCourseCalendar(course);
 		CourseGroupManager cgm = course.getCourseEnvironment().getCourseGroupManager();
-		boolean isPrivileged = isPrivileged(cgm);
+		boolean isPrivileged = isPrivileged();
 		if (isPrivileged) {
 			courseKalendarWrapper.setAccess(KalendarRenderWrapper.ACCESS_READ_WRITE);
 			courseKalendarWrapper.setPrivateEventsVisible(true);
@@ -121,9 +121,8 @@ public class CourseCalendarController extends BasicController {
 		return calendars;
 	}
 	
-	private boolean isPrivileged(CourseGroupManager cgm) {
-		return !userCourseEnv.isCourseReadOnly()
-				&& (userCourseEnv.isAdmin() || cgm.isIdentityCourseAdministrator(getIdentity()));
+	private boolean isPrivileged() {
+		return !userCourseEnv.isCourseReadOnly() && userCourseEnv.isAdmin();
 	}
 	
 	private void addCalendars(List<BusinessGroup> groups, boolean isOwner, LinkProvider linkProvider,
diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
index 8e20e55f14a..4d05f0d429e 100644
--- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
+++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironment.java
@@ -67,8 +67,8 @@ public interface UserCourseEnvironment {
 	public ScoreAccounting getScoreAccounting();
 	
 	/**
-	 * Is admin of the course, as administrator in OpenOLAT, resource manager
-	 * or owner of the course.
+	 * Is admin of a course an administrator, learn resource manager or principal
+	 * of an organization linked to the course or an owner of the course.
 	 * @return
 	 */
 	public boolean isAdmin();
diff --git a/src/main/java/org/olat/group/ui/edit/MemberListController.java b/src/main/java/org/olat/group/ui/edit/MemberListController.java
index 472a6ed9423..3edde1ce6e7 100644
--- a/src/main/java/org/olat/group/ui/edit/MemberListController.java
+++ b/src/main/java/org/olat/group/ui/edit/MemberListController.java
@@ -24,10 +24,12 @@ import org.olat.core.gui.components.stack.TooledStackedPanel;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.group.BusinessGroup;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberListSecurityCallbackFactory;
 import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
 
 /**
+ * The list of members specific to the business groups.
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
@@ -37,7 +39,7 @@ public class MemberListController extends AbstractMemberListController {
 	
 	public MemberListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
 			BusinessGroup group, SearchMembersParams searchParams) {
-		super(ureq, wControl, group, "all_member_list", false, stackPanel);
+		super(ureq, wControl, group, "all_member_list", MemberListSecurityCallbackFactory.adminRights(), stackPanel);
 		this.searchParams = searchParams;
 	}
 	
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index 41c022a784e..7b96bb073f8 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -151,9 +151,9 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	private final boolean isAdministrativeUser;
 	private final boolean chatEnabled;
 	
-	private final boolean readOnly;
 	private boolean overrideManaged = false;
 	private final boolean globallyManaged;
+	private final MemberListSecurityCallback secCallback;
 	
 	@Autowired
 	private MemberViewQueries memberQueries;
@@ -183,28 +183,28 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	private UserSessionManager sessionManager;
 
 	public AbstractMemberListController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry,
-			String page,boolean readOnly,  TooledStackedPanel stackPanel) {
-		this(ureq, wControl, repoEntry, null, page, readOnly, stackPanel, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
+			String page, MemberListSecurityCallback secCallback,  TooledStackedPanel stackPanel) {
+		this(ureq, wControl, repoEntry, null, page, secCallback, stackPanel, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
 	}
 	
 	public AbstractMemberListController(UserRequest ureq, WindowControl wControl, BusinessGroup group,
-			String page, boolean readOnly, TooledStackedPanel stackPanel) {
-		this(ureq, wControl, null, group, page, readOnly, stackPanel, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
+			String page, MemberListSecurityCallback secCallback, TooledStackedPanel stackPanel) {
+		this(ureq, wControl, null, group, page, secCallback, stackPanel, Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale()));
 	}
 	
 	protected AbstractMemberListController(UserRequest ureq, WindowControl wControl, RepositoryEntry repoEntry, BusinessGroup group,
-			String page, boolean readOnly, TooledStackedPanel stackPanel, Translator translator) {
+			String page, MemberListSecurityCallback secCallback, TooledStackedPanel stackPanel, Translator translator) {
 		super(ureq, wControl, page, Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale(), translator));
 		
 		this.businessGroup = group;
 		this.repoEntry = repoEntry;
 		this.toolbarPanel = stackPanel;
-		this.readOnly = readOnly;
+		this.secCallback = secCallback;
 
 		globallyManaged = calcGloballyManaged();
 		
 		Roles roles = ureq.getUserSession().getRoles();
-		chatEnabled = imModule.isEnabled() && imModule.isPrivateEnabled() && !readOnly;
+		chatEnabled = imModule.isEnabled() && imModule.isPrivateEnabled() && !secCallback.isReadonly();
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles);
 		isLastVisitVisible = securityModule.isUserLastVisitVisible(roles);
 		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, isAdministrativeUser);
@@ -215,8 +215,8 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	public void overrideManaged(UserRequest ureq, boolean override) {
 		if(isAllowedToOverrideManaged(ureq)) {
 			overrideManaged = override;
-			editButton.setVisible((!globallyManaged || overrideManaged) && !readOnly);
-			removeButton.setVisible((!globallyManaged || overrideManaged) && !readOnly);
+			editButton.setVisible((!globallyManaged || overrideManaged) && !secCallback.isReadonly());
+			removeButton.setVisible((!globallyManaged || overrideManaged) && !secCallback.isReadonly());
 			flc.setDirty(true);
 		}
 	}
@@ -253,10 +253,10 @@ public abstract class AbstractMemberListController extends FormBasicController i
 		}
 
 		editButton = uifactory.addFormLink("edit.members", formLayout, Link.BUTTON);
-		editButton.setVisible((!globallyManaged || overrideManaged) && !readOnly);
+		editButton.setVisible((!globallyManaged || overrideManaged) && !secCallback.isReadonly());
 		mailButton = uifactory.addFormLink("table.header.mail", formLayout, Link.BUTTON);
 		removeButton = uifactory.addFormLink("table.header.remove", formLayout, Link.BUTTON);
-		removeButton.setVisible((!globallyManaged || overrideManaged) && !readOnly);
+		removeButton.setVisible((!globallyManaged || overrideManaged) && !secCallback.isReadonly());
 	}
 	
 	private boolean calcGloballyManaged() {
@@ -288,7 +288,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 	
 	private SortKey initColumns(FlexiTableColumnModel columnsModel) {
 		SortKey defaultSortKey = null;
-		String editAction = readOnly ? null : TABLE_ACTION_EDIT;
+		String editAction = secCallback.isReadonly() ? null : TABLE_ACTION_EDIT;
 		
 		if(chatEnabled) {
 			DefaultFlexiColumnModel chatCol = new DefaultFlexiColumnModel(Cols.online.i18n(), Cols.online.ordinal());
@@ -691,7 +691,7 @@ public abstract class AbstractMemberListController extends FormBasicController i
 			Map<BusinessGroup, List<Identity>> graduatesMap = new HashMap<>();
 			for(MemberRow member:members) {
 				List<BusinessGroupShort> groups = member.getGroups();
-				if(groups != null && groups.size() > 0) {
+				if(groups != null && !groups.isEmpty()) {
 					Identity memberIdentity = securityManager.loadIdentityByKey(member.getIdentityKey());
 					for(BusinessGroupShort group:groups) {
 						if(businessGroupService.hasRoles(memberIdentity, group, GroupRoles.waiting.name())) {
@@ -881,15 +881,15 @@ public abstract class AbstractMemberListController extends FormBasicController i
 			
 			links.add("-");
 			
-			if(row.getMembership().isBusinessGroupWaiting() && !readOnly) {
+			if(row.getMembership().isBusinessGroupWaiting() && !secCallback.isReadonly()) {
 				addLink("table.header.graduate", TABLE_ACTION_GRADUATE, "o_icon o_icon_graduate", links);
 			}
 
-			if(!readOnly) {
+			if(!secCallback.isReadonly()) {
 				addLink("edit.member", TABLE_ACTION_EDIT, "o_icon o_icon_edit", links);
 			}
 			
-			if(!globallyManaged || overrideManaged) {
+			if((!globallyManaged || overrideManaged) && secCallback.canRemoveMembers()) {
 				addLink("table.header.remove", TABLE_ACTION_REMOVE, "o_icon o_icon_remove", links);
 			}
 			cleanSeparator(links);
diff --git a/src/main/java/org/olat/group/ui/main/MemberListSecurityCallback.java b/src/main/java/org/olat/group/ui/main/MemberListSecurityCallback.java
new file mode 100644
index 00000000000..2a24d2676ce
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/MemberListSecurityCallback.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.group.ui.main;
+
+/**
+ * 
+ * Initial date: 20 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface MemberListSecurityCallback {
+	
+	public boolean isReadonly();
+	
+	public boolean canRemoveMembers();
+
+}
diff --git a/src/main/java/org/olat/group/ui/main/MemberListSecurityCallbackFactory.java b/src/main/java/org/olat/group/ui/main/MemberListSecurityCallbackFactory.java
new file mode 100644
index 00000000000..127ea10393a
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/MemberListSecurityCallbackFactory.java
@@ -0,0 +1,59 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.group.ui.main;
+
+/**
+ * 
+ * Initial date: 20 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MemberListSecurityCallbackFactory {
+	
+	public static MemberListSecurityCallback adminRights() {
+		return new MemberListSecurityCallbackImpl(false, true);
+	}
+	
+	public static MemberListSecurityCallback getSecurityCallback(boolean readOnly, boolean canRemoveMembers) {
+		return new MemberListSecurityCallbackImpl(readOnly, canRemoveMembers);
+	}
+	
+	private static class MemberListSecurityCallbackImpl implements MemberListSecurityCallback {
+		
+		private final boolean readOnly;
+		private final boolean canRemoveMembers;
+		
+		public MemberListSecurityCallbackImpl(boolean readOnly, boolean canRemoveMembers) {
+			this.readOnly = readOnly;
+			this.canRemoveMembers = canRemoveMembers;
+		}
+
+		@Override
+		public boolean isReadonly() {
+			return readOnly;
+		}
+
+		@Override
+		public boolean canRemoveMembers() {
+			return canRemoveMembers;
+		}
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/coach/ui/UserDetailsController.java b/src/main/java/org/olat/modules/coach/ui/UserDetailsController.java
index 40d42a2a71a..e85982c001b 100644
--- a/src/main/java/org/olat/modules/coach/ui/UserDetailsController.java
+++ b/src/main/java/org/olat/modules/coach/ui/UserDetailsController.java
@@ -159,8 +159,8 @@ public class UserDetailsController extends BasicController implements Activateab
 		RepositoryEntrySecurity reSecurity = repositoryManager.isAllowed(ureq, entry);
 		return new UserCourseEnvironmentImpl(ureq.getUserSession().getIdentityEnvironment(), null, getWindowControl(),
 				null, null, null,
-				reSecurity.isCoach(), reSecurity.isEntryAdmin(), reSecurity.isParticipant(),
-				reSecurity.isReadOnly());
+				reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal(), reSecurity.isParticipant(),
+				reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal());
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/lecture/ui/AppealListRepositoryController.java b/src/main/java/org/olat/modules/lecture/ui/AppealListRepositoryController.java
index ae32c92df87..7b1ebd81c46 100644
--- a/src/main/java/org/olat/modules/lecture/ui/AppealListRepositoryController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/AppealListRepositoryController.java
@@ -77,6 +77,7 @@ public class AppealListRepositoryController extends FormBasicController {
 	private final boolean absenceDefaultAuthorized;
 	
 	private final RepositoryEntry entry;
+	private final LecturesSecurityCallback secCallback;
 	private final boolean isAdministrativeUser;
 	private List<UserPropertyHandler> userPropertyHandlers;
 	
@@ -89,9 +90,11 @@ public class AppealListRepositoryController extends FormBasicController {
 	@Autowired
 	private BaseSecurityModule securityModule;
 	
-	public AppealListRepositoryController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) {
+	public AppealListRepositoryController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry,
+			LecturesSecurityCallback secCallback) {
 		super(ureq, wControl, "appeal_table");
 		this.entry = entry;
+		this.secCallback = secCallback;
 		setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));
 		
 		Roles roles = ureq.getUserSession().getRoles();
@@ -140,9 +143,12 @@ public class AppealListRepositoryController extends FormBasicController {
 				new LectureBlockRollCallStatusCellRenderer(authorizedAbsenceEnabled, absenceDefaultAuthorized, getTranslator())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(AppealCols.appealStatus,
 				new LectureBlockAppealStatusCellRenderer(getTranslator())));
-		DefaultFlexiColumnModel editColumn = new DefaultFlexiColumnModel("table.header.edit", translate("table.header.edit"), "edit");
-		editColumn.setExportable(false);
-		columnsModel.addFlexiColumnModel(editColumn);
+		
+		if(secCallback.canApproveAppeal()) {
+			DefaultFlexiColumnModel editColumn = new DefaultFlexiColumnModel("table.header.edit", translate("table.header.edit"), "edit");
+			editColumn.setExportable(false);
+			columnsModel.addFlexiColumnModel(editColumn);
+		}
 		
 		tableModel = new AppealListRepositoryDataModel(columnsModel,authorizedAbsenceEnabled, absenceDefaultAuthorized, getLocale()); 
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
@@ -225,7 +231,7 @@ public class AppealListRepositoryController extends FormBasicController {
 	}
 	
 	private void doEditAppeal(UserRequest ureq, LectureBlockRollCall rollCall) {
-		if(appealCtrl != null) return;
+		if(appealCtrl != null || !secCallback.canApproveAppeal()) return;
 		
 		appealCtrl = new EditAppealController(ureq, getWindowControl(), rollCall);
 		listenTo(appealCtrl);
diff --git a/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java b/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java
index 9797e259187..0aa76fb4952 100644
--- a/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/EditLectureBlockController.java
@@ -93,6 +93,7 @@ public class EditLectureBlockController extends FormBasicController {
 	private TextElement startHourEl, startMinuteEl;
 	private MultipleSelectionElement groupsEl, teacherEl, compulsoryEl;
 	
+	private final boolean readOnly;
 	private RepositoryEntry entry;
 	private LectureBlock lectureBlock;
 	
@@ -116,12 +117,14 @@ public class EditLectureBlockController extends FormBasicController {
 	private BusinessGroupService businessGroupService;
 
 	public EditLectureBlockController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) {
-		this(ureq, wControl, entry, null);
+		this(ureq, wControl, entry, null, false);
 	}
 	
-	public EditLectureBlockController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, LectureBlock lectureBlock) {
+	public EditLectureBlockController(UserRequest ureq, WindowControl wControl,
+			RepositoryEntry entry, LectureBlock lectureBlock, boolean readOnly) {
 		super(ureq, wControl);
 		this.entry = entry;
+		this.readOnly = readOnly;
 		this.lectureBlock = lectureBlock;
 		locations = getLocations(ureq);
 		lectureManagementManaged = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.lecturemanagement);
@@ -144,7 +147,7 @@ public class EditLectureBlockController extends FormBasicController {
 		String title = lectureBlock == null ? null : lectureBlock.getTitle();
 		titleEl = uifactory.addTextElement("title", "lecture.title", 128, title, formLayout);
 		titleEl.setElementCssClass("o_sel_repo_lecture_title");
-		titleEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.title));
+		titleEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.title));
 		titleEl.setMandatory(true);
 
 		plannedLecturesEl = uifactory.addDropdownSingleselect("planned.lectures", "planned.lectures", formLayout,
@@ -164,12 +167,12 @@ public class EditLectureBlockController extends FormBasicController {
 					&& lectureBlock.getRollCallStatus() != LectureRollCallStatus.autoclosed))
 			&& !lectureManagementManaged
 			&& !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.plannedLectures);
-		plannedLecturesEl.setEnabled(plannedLecturesEditable);
+		plannedLecturesEl.setEnabled(!readOnly && plannedLecturesEditable);
 		
 		String[] onValues = new String[]{ "" };
 		boolean compulsory = lectureBlock == null ? true : lectureBlock.isCompulsory();
 		compulsoryEl = uifactory.addCheckboxesVertical("compulsory", "lecture.compulsory", formLayout, onKeys, onValues, 1);
-		compulsoryEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.compulsory));
+		compulsoryEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.compulsory));
 		compulsoryEl.addActionListener(FormEvent.ONCHANGE);
 		if(compulsory) {
 			compulsoryEl.select(onKeys[0], true);
@@ -188,7 +191,7 @@ public class EditLectureBlockController extends FormBasicController {
 		teacherEl = uifactory.addCheckboxesVertical("teacher", "lecture.teacher", formLayout, teacherKeys, teacherValues, 2);
 		teacherEl.setElementCssClass("o_sel_repo_lecture_teachers");
 		teacherEl.setMandatory(true);
-		teacherEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.teachers));
+		teacherEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.teachers));
 		
 		boolean found = false;
 		if(teachers != null && teachers.size() > 0) {
@@ -221,7 +224,7 @@ public class EditLectureBlockController extends FormBasicController {
 			groupValues[i] = groupBox.get(i).getName();
 		}
 		groupsEl = uifactory.addCheckboxesVertical("lecture.groups", "lecture.groups", formLayout, groupKeys, groupValues, 2);
-		groupsEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.groups));
+		groupsEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.groups));
 		groupsEl.setMandatory(true);
 		if(lectureBlock != null) {
 			List<Group> selectedGroups = lectureService.getLectureBlockToGroups(lectureBlock);
@@ -247,22 +250,22 @@ public class EditLectureBlockController extends FormBasicController {
 		String description = lectureBlock == null ? "" : lectureBlock.getDescription();
 		descriptionEl = uifactory.addTextAreaElement("lecture.descr", 4, 72, description, formLayout);
 		descriptionEl.setElementCssClass("o_sel_repo_lecture_description");
-		descriptionEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.description));
+		descriptionEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.description));
 		String preparation = lectureBlock == null ? "" : lectureBlock.getPreparation();
 		preparationEl = uifactory.addTextAreaElement("lecture.preparation", 4, 72, preparation, formLayout);
 		preparationEl.setElementCssClass("o_sel_repo_lecture_preparation");
-		preparationEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.preparation));
+		preparationEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.preparation));
 		String location = lectureBlock == null ? "" : lectureBlock.getLocation();
 		locationEl = uifactory.addTextElementWithAutoCompleter("location", "lecture.location", 128, location, formLayout);
 		locationEl.setElementCssClass("o_sel_repo_lecture_location");
-		locationEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.location));
+		locationEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.location));
 		locationEl.setListProvider(new LocationListProvider(), ureq.getUserSession());
 		locationEl.setMinLength(1);
 
 		Date startDate = lectureBlock == null ? null : lectureBlock.getStartDate();
 		dateEl = uifactory.addDateChooser("lecture.date", startDate, formLayout);
 		dateEl.setElementCssClass("o_sel_repo_lecture_date");
-		dateEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
+		dateEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
 		dateEl.setDomReplacementWrapperRequired(false);
 		dateEl.setMandatory(true);
 		
@@ -272,22 +275,22 @@ public class EditLectureBlockController extends FormBasicController {
 		formLayout.add(dateCont);
 		
 		startHourEl = uifactory.addTextElement("lecture.start.hour", null, 2, "", dateCont);
-		startHourEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
+		startHourEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
 		startHourEl.setDomReplacementWrapperRequired(false);
 		startHourEl.setDisplaySize(2);
 		startHourEl.setMandatory(true);
 		startMinuteEl = uifactory.addTextElement("lecture.start.minute", null, 2, "", dateCont);
-		startMinuteEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
+		startMinuteEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
 		startMinuteEl.setDomReplacementWrapperRequired(false);
 		startMinuteEl.setDisplaySize(2);
 		
 		endHourEl = uifactory.addTextElement("lecture.end.hour", null, 2, "", dateCont);
-		endHourEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
+		endHourEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
 		endHourEl.setDomReplacementWrapperRequired(false);
 		endHourEl.setDisplaySize(2);
 		endHourEl.setMandatory(true);
 		endMinuteEl = uifactory.addTextElement("lecture.end.minute", null, 2, "", dateCont);
-		endMinuteEl.setEnabled(!lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
+		endMinuteEl.setEnabled(!readOnly && !lectureManagementManaged && !LectureBlockManagedFlag.isManaged(lectureBlock, LectureBlockManagedFlag.dates));
 		endMinuteEl.setDomReplacementWrapperRequired(false);
 		endMinuteEl.setDisplaySize(2);
 
@@ -312,7 +315,9 @@ public class EditLectureBlockController extends FormBasicController {
 		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
 		formLayout.add(buttonsCont);
 		uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
-		uifactory.addFormSubmitButton("save", buttonsCont);
+		if(!readOnly) {
+			uifactory.addFormSubmitButton("save", buttonsCont);
+		}
 	}
 	
 	private String formatMinute(int minute) {
diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java b/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java
index cc87b8ff5ff..c0a9b291235 100644
--- a/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/LectureListRepositoryController.java
@@ -91,9 +91,9 @@ public class LectureListRepositoryController extends FormBasicController {
 	private CloseableCalloutWindowController toolsCalloutCtrl;
 
 	private int counter = 0;
-	private RepositoryEntry entry;
-	
+	private final RepositoryEntry entry;
 	private final boolean lectureManagementManaged;
+	private final LecturesSecurityCallback secCallback;
 	
 	@Autowired
 	private UserManager userManager;
@@ -102,9 +102,10 @@ public class LectureListRepositoryController extends FormBasicController {
 	@Autowired
 	private LectureService lectureService;
 	
-	public LectureListRepositoryController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) {
+	public LectureListRepositoryController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry, LecturesSecurityCallback secCallback) {
 		super(ureq, wControl, "admin_repository_lectures");
 		this.entry = entry;
+		this.secCallback = secCallback;
 		lectureManagementManaged = RepositoryEntryManagedFlag.isManaged(entry, RepositoryEntryManagedFlag.lecturemanagement);
 		
 		initForm(ureq);
@@ -113,7 +114,7 @@ public class LectureListRepositoryController extends FormBasicController {
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		if(!lectureManagementManaged) {
+		if(!lectureManagementManaged && secCallback.canNewLectureBlock()) {
 			addLectureButton = uifactory.addFormLink("add.lecture", formLayout, Link.BUTTON);
 			addLectureButton.setIconLeftCSS("o_icon o_icon_add");
 			addLectureButton.setElementCssClass("o_sel_repo_add_lecture");
@@ -129,21 +130,17 @@ public class LectureListRepositoryController extends FormBasicController {
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BlockCols.startTime, new TimeFlexiCellRenderer(getLocale())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BlockCols.endTime, new TimeFlexiCellRenderer(getLocale())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BlockCols.teachers));
-		
-		if(lectureManagementManaged) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel("details", translate("details"), "edit"));//edit check it
-		} else {
-			DefaultFlexiColumnModel editColumn = new DefaultFlexiColumnModel("table.header.edit", -1, "edit",
-					new StaticFlexiCellRenderer("", "edit", "o_icon o_icon-lg o_icon_edit", translate("edit"), null));
-			editColumn.setExportable(false);
-			editColumn.setAlwaysVisible(true);
-			columnsModel.addFlexiColumnModel(editColumn);
+
+		DefaultFlexiColumnModel editColumn = new DefaultFlexiColumnModel("table.header.edit", -1, "edit",
+				new StaticFlexiCellRenderer("", "edit", "o_icon o_icon-lg o_icon_edit", translate("edit"), null));
+		editColumn.setExportable(false);
+		editColumn.setAlwaysVisible(true);
+		columnsModel.addFlexiColumnModel(editColumn);
 			
-			DefaultFlexiColumnModel toolsColumn = new DefaultFlexiColumnModel(BlockCols.tools);
-			toolsColumn.setExportable(false);
-			toolsColumn.setAlwaysVisible(true);
-			columnsModel.addFlexiColumnModel(toolsColumn);
-		}
+		DefaultFlexiColumnModel toolsColumn = new DefaultFlexiColumnModel(BlockCols.tools);
+		toolsColumn.setExportable(false);
+		toolsColumn.setAlwaysVisible(true);
+		columnsModel.addFlexiColumnModel(toolsColumn);
 		
 		tableModel = new LectureListRepositoryDataModel(columnsModel, getLocale()); 
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
@@ -182,8 +179,10 @@ public class LectureListRepositoryController extends FormBasicController {
 		}
 		tableModel.setObjects(rows);
 		tableEl.reset(true, true, true);
-		
-		deleteLecturesButton.setVisible(!rows.isEmpty());
+
+		if(deleteLecturesButton != null) {
+			deleteLecturesButton.setVisible(!rows.isEmpty());
+		}
 	}
 	
 	@Override
@@ -279,7 +278,8 @@ public class LectureListRepositoryController extends FormBasicController {
 		if(editLectureCtrl != null) return;
 		
 		LectureBlock block = lectureService.getLectureBlock(row);
-		editLectureCtrl = new EditLectureBlockController(ureq, getWindowControl(), entry, block);
+		boolean readOnly = lectureManagementManaged || !secCallback.canNewLectureBlock();
+		editLectureCtrl = new EditLectureBlockController(ureq, getWindowControl(), entry, block, readOnly);
 		listenTo(editLectureCtrl);
 
 		cmc = new CloseableModalController(getWindowControl(), "close", editLectureCtrl.getInitialComponent(), true, translate("add.lecture"));
@@ -288,7 +288,7 @@ public class LectureListRepositoryController extends FormBasicController {
 	}
 
 	private void doAddLectureBlock(UserRequest ureq) {
-		if(editLectureCtrl != null) return;
+		if(editLectureCtrl != null || !secCallback.canNewLectureBlock()) return;
 		
 		editLectureCtrl = new EditLectureBlockController(ureq, getWindowControl(), entry);
 		listenTo(editLectureCtrl);
@@ -392,11 +392,13 @@ public class LectureListRepositoryController extends FormBasicController {
 			
 			VelocityContainer mainVC = createVelocityContainer("lectures_tools");
 			
-			copyLink = LinkFactory.createLink("copy", "copy", getTranslator(), mainVC, this, Link.LINK);
-			copyLink.setIconLeftCSS("o_icon o_icon-fw o_icon_copy");
-			if(!LectureBlockManagedFlag.isManaged(row.getLectureBlock(), LectureBlockManagedFlag.delete)) {
-				deleteLink = LinkFactory.createLink("delete", "delete", getTranslator(), mainVC, this, Link.LINK);
-				deleteLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item");
+			if(secCallback.canNewLectureBlock()) {
+				copyLink = LinkFactory.createLink("copy", "copy", getTranslator(), mainVC, this, Link.LINK);
+				copyLink.setIconLeftCSS("o_icon o_icon-fw o_icon_copy");
+				if(!LectureBlockManagedFlag.isManaged(row.getLectureBlock(), LectureBlockManagedFlag.delete)) {
+					deleteLink = LinkFactory.createLink("delete", "delete", getTranslator(), mainVC, this, Link.LINK);
+					deleteLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item");
+				}
 			}
 			logLink = LinkFactory.createLink("log", "log", getTranslator(), mainVC, this, Link.LINK);
 			logLink.setIconLeftCSS("o_icon o_icon-fw o_icon_log"); 
diff --git a/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java b/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java
index 3a95ee690a5..0ff1265d8cf 100644
--- a/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/LectureRepositoryAdminController.java
@@ -59,12 +59,16 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class LectureRepositoryAdminController extends BasicController implements TooledController, Activateable2 {
 	
-	private Link archiveLink, logLink;
+	private Link logLink;
+	private Link archiveLink;
+	private Link settingsLink;
+	private final Link appealsLink;
+	private final Link lecturesLink;
+	private final Link participantsLink;
 	private final VelocityContainer mainVC;
 	private final SegmentViewComponent segmentView;
 	private final TooledStackedPanel stackPanel;
-	private final Link lecturesLink, appealsLink, settingsLink, participantsLink;
-	
+
 	private AppealListRepositoryController appealsCtrl;
 	private LectureListRepositoryController lecturesCtrl;
 	private final LectureRepositorySettingsController settingsCtrl;
@@ -74,6 +78,7 @@ public class LectureRepositoryAdminController extends BasicController implements
 	private boolean configurationChanges = false;
 	private final boolean isAdministrativeUser;
 	private final boolean authorizedAbsenceEnabled;
+	private final LecturesSecurityCallback secCallback;
 	
 	@Autowired
 	private LectureModule lectureModule;
@@ -83,10 +88,11 @@ public class LectureRepositoryAdminController extends BasicController implements
 	private BaseSecurityModule securityModule;
 	
 	public LectureRepositoryAdminController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel,
-			RepositoryEntry entry) {
+			RepositoryEntry entry, LecturesSecurityCallback secCallback) {
 		super(ureq, wControl);
 		this.entry = entry;
 		this.stackPanel = stackPanel;
+		this.secCallback = secCallback;
 		
 		Roles roles = ureq.getUserSession().getRoles();
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles);
@@ -100,12 +106,10 @@ public class LectureRepositoryAdminController extends BasicController implements
 		lecturesLink = LinkFactory.createLink("repo.lectures.block", mainVC, this);
 		participantsLink = LinkFactory.createLink("repo.participants", mainVC, this);
 		appealsLink = LinkFactory.createLink("repo.lectures.appeals", mainVC, this);
-		settingsLink = LinkFactory.createLink("repo.settings", mainVC, this);
-		
+
 		WindowControl swControl = addToHistory(ureq, OresHelper.createOLATResourceableType("Settings"), null);
 		settingsCtrl = new LectureRepositorySettingsController(ureq, swControl, entry);
 		listenTo(settingsCtrl);
-		
 		if(settingsCtrl.isLectureEnabled()) {
 			segmentView.addSegment(lecturesLink, true);
 			segmentView.addSegment(participantsLink, false);
@@ -116,7 +120,11 @@ public class LectureRepositoryAdminController extends BasicController implements
 		} else {
 			doOpenSettings(ureq);
 		}
-		segmentView.addSegment(settingsLink, !settingsCtrl.isLectureEnabled());
+		
+		if(secCallback.canEditConfiguration()) {
+			settingsLink = LinkFactory.createLink("repo.settings", mainVC, this);
+			segmentView.addSegment(settingsLink, !settingsCtrl.isLectureEnabled());
+		}
 
 		putInitialPanel(mainVC);
 	}
@@ -158,7 +166,7 @@ public class LectureRepositoryAdminController extends BasicController implements
 		} else if("Participants".equalsIgnoreCase(name)) {
 			doOpenParticipants(ureq);
 			segmentView.select(participantsLink);
-		} else if("Settings".equalsIgnoreCase(name)) {
+		} else if("Settings".equalsIgnoreCase(name) && settingsLink != null) {
 			doOpenSettings(ureq);
 			segmentView.select(settingsLink);
 		} else if("Appeals".equalsIgnoreCase(name)) {
@@ -227,7 +235,7 @@ public class LectureRepositoryAdminController extends BasicController implements
 		if(lecturesCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableType("LectureBlocks");
 			WindowControl swControl = addToHistory(ureq, ores, null);
-			lecturesCtrl = new LectureListRepositoryController(ureq, swControl, entry);
+			lecturesCtrl = new LectureListRepositoryController(ureq, swControl, entry, secCallback);
 			listenTo(lecturesCtrl);
 		} else {
 			addToHistory(ureq, lecturesCtrl);
@@ -244,7 +252,7 @@ public class LectureRepositoryAdminController extends BasicController implements
 		if(participantsCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableType("Participants");
 			WindowControl swControl = addToHistory(ureq, ores, null);
-			participantsCtrl = new ParticipantListRepositoryController(ureq, swControl, entry, false, true);
+			participantsCtrl = new ParticipantListRepositoryController(ureq, swControl, entry, secCallback, false);
 			listenTo(participantsCtrl);
 		} else {
 			addToHistory(ureq, participantsCtrl);
@@ -256,7 +264,7 @@ public class LectureRepositoryAdminController extends BasicController implements
 		if(appealsCtrl == null) {
 			OLATResourceable ores = OresHelper.createOLATResourceableType("Appeals");
 			WindowControl swControl = addToHistory(ureq, ores, null);
-			appealsCtrl = new AppealListRepositoryController(ureq, swControl, entry);
+			appealsCtrl = new AppealListRepositoryController(ureq, swControl, entry, secCallback);
 			listenTo(appealsCtrl);
 		} else {
 			addToHistory(ureq, appealsCtrl);
diff --git a/src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallback.java b/src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallback.java
new file mode 100644
index 00000000000..902ec3c5d04
--- /dev/null
+++ b/src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallback.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.modules.lecture.ui;
+
+/**
+ * Very simple security callback for the principals
+ * 
+ * 
+ * Initial date: 20 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public interface LecturesSecurityCallback {
+	
+	public boolean canNewLectureBlock();
+	
+	public boolean canChangeRates();
+	
+	public boolean canApproveAppeal();
+	
+	public boolean canEditConfiguration();
+
+}
diff --git a/src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallbackFactory.java b/src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallbackFactory.java
new file mode 100644
index 00000000000..e008072d850
--- /dev/null
+++ b/src/main/java/org/olat/modules/lecture/ui/LecturesSecurityCallbackFactory.java
@@ -0,0 +1,62 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.lecture.ui;
+
+/**
+ * 
+ * Initial date: 20 juil. 2018<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class LecturesSecurityCallbackFactory {
+	
+	public static LecturesSecurityCallback getSecurityCallback(boolean canModify) {
+		return new LecturesSecurityCallbackImpl(canModify);
+	}
+	
+	private static class LecturesSecurityCallbackImpl implements LecturesSecurityCallback {
+		
+		private final boolean canModify;
+		
+		public LecturesSecurityCallbackImpl(boolean canModify) {
+			this.canModify = canModify;
+		}
+
+		@Override
+		public boolean canNewLectureBlock() {
+			return canModify;
+		}
+
+		@Override
+		public boolean canChangeRates() {
+			return canModify;
+		}
+
+		@Override
+		public boolean canApproveAppeal() {
+			return canModify;
+		}
+
+		@Override
+		public boolean canEditConfiguration() {
+			return canModify;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java b/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java
index 0000b5986f7..9e1701b1301 100644
--- a/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/ParticipantListRepositoryController.java
@@ -94,9 +94,9 @@ public class ParticipantListRepositoryController extends FormBasicController {
 	private final boolean rollCallEnabled;
 	private final boolean authorizedAbsenceEnabled;
 	
-	private final boolean admin;
 	private final boolean printView;
 	private final RepositoryEntry entry;
+	private final LecturesSecurityCallback secCallback;
 	private RepositoryEntryLectureConfiguration lectureConfig;
 	
 	@Autowired
@@ -111,13 +111,13 @@ public class ParticipantListRepositoryController extends FormBasicController {
 	private BaseSecurity securityManager;
 	
 	public ParticipantListRepositoryController(UserRequest ureq, WindowControl wControl,
-			RepositoryEntry entry, boolean printView, boolean admin) {
+			RepositoryEntry entry, LecturesSecurityCallback secCallback, boolean printView) {
 		super(ureq, wControl, "participant_list_overview");
 		this.entry = entry;
 		setTranslator(userManager.getPropertyHandlerTranslator(getTranslator()));
 		
-		this.admin = admin;
 		this.printView = printView;
+		this.secCallback = secCallback;
 		
 		Roles roles = ureq.getUserSession().getRoles();
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles);
@@ -200,7 +200,7 @@ public class ParticipantListRepositoryController extends FormBasicController {
 		infoCol.setExportable(false);
 		columnsModel.addFlexiColumnModel(infoCol);
 		
-		if(!printView) {
+		if(!printView && secCallback.canChangeRates()) {
 			DefaultFlexiColumnModel editColumn = new DefaultFlexiColumnModel("table.header.edit", -1, "edit",
 					new StaticFlexiCellRenderer("", "edit", "o_icon o_icon-lg o_icon_edit", translate("edit"), null));
 			editColumn.setExportable(false);
@@ -217,15 +217,10 @@ public class ParticipantListRepositoryController extends FormBasicController {
 	}
 	
 	private void loadModel() {
-		List<Identity> participants;
-		if(admin) {
-			participants = lectureService.getParticipants(entry);
-		} else {
-			participants = lectureService.getParticipants(entry, getIdentity());
-		}
-		
+		List<Identity> participants = lectureService.getParticipants(entry);
 		List<LectureBlockStatistics> statistics = lectureService.getParticipantsLecturesStatistics(entry);
-		Map<Long, LectureBlockStatistics> identityToStatisticsMap = statistics.stream().collect(Collectors.toMap(s -> s.getIdentityKey(), s -> s));
+		Map<Long, LectureBlockStatistics> identityToStatisticsMap = statistics.stream()
+				.collect(Collectors.toMap(LectureBlockStatistics::getIdentityKey, s -> s));
 		
 		List<ParticipantRow> rows = new ArrayList<>(participants.size());
 		for(Identity participant:participants) {
@@ -304,14 +299,11 @@ public class ParticipantListRepositoryController extends FormBasicController {
 	}
 	
 	private void doPrint(UserRequest ureq) {
-		ControllerCreator printControllerCreator = new ControllerCreator() {
-			@Override
-			public Controller createController(UserRequest lureq, WindowControl lwControl) {
-				lwControl.getWindowBackOffice().getChiefController().addBodyCssClass("o_lectures_print");
-				Controller printCtrl = new ParticipantListRepositoryController(lureq, lwControl, entry, true, admin);
-				listenTo(printCtrl);
-				return printCtrl;
-			}					
+		ControllerCreator printControllerCreator = (lureq, lwControl) -> {
+			lwControl.getWindowBackOffice().getChiefController().addBodyCssClass("o_lectures_print");
+			Controller printCtrl = new ParticipantListRepositoryController(lureq, lwControl, entry, secCallback, true);
+			listenTo(printCtrl);
+			return printCtrl;
 		};
 		ControllerCreator layoutCtrlr = BaseFullWebappPopupLayoutFactory.createPrintPopupLayout(printControllerCreator);
 		openInNewBrowserWindow(ureq, layoutCtrlr);
diff --git a/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html b/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html
index 0d70ba3886d..c3fb1d715d8 100644
--- a/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html
+++ b/src/main/java/org/olat/modules/lecture/ui/_content/admin_repository_lectures.html
@@ -1,10 +1,12 @@
 <div class="o_sel_repo_lectures_list">
+#if($r.available("add.lecture"))
 <div class="o_button_group o_button_group_right">
 	#if($r.available("add.lecture"))
 		$r.render("add.lecture")
 	#end
 	$r.contextHelpWithWrapper("Lectures and absences")
 </div>
+#end
 $r.render("table")
 #if($r.available("delete"))
 <div class="o_button_group">
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index c2332be2d41..e09a76f9503 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -575,6 +575,7 @@ public class RepositoryManager {
 
 		boolean isAuthor = false;
 		boolean isEntryAdmin = false;
+		boolean isPrincipal = false;
 		boolean isAdministrator = false;
 		boolean isLearnRessourceManager = false;
 		
@@ -638,6 +639,9 @@ public class RepositoryManager {
 						case learnresourcemanager:
 							isLearnRessourceManager = true;
 							break;
+						case principal:
+							isPrincipal = true;
+							break;
 						default: break;
 					}
 				}
@@ -649,6 +653,8 @@ public class RepositoryManager {
 			if(isOwner || isAdministrator || isLearnRessourceManager) {
 				canLaunch = true;
 				isEntryAdmin = true;
+			} else if(isPrincipal) {
+				canLaunch = true;
 			}
 			if (isAuthor && re.getAccess() >= RepositoryEntry.ACC_OWNERS_AUTHORS) {
 				// allow for authors if access granted at least for authors
@@ -670,7 +676,7 @@ public class RepositoryManager {
 				isCourseParticipant, isCourseCoach,
 				isGroupParticipant, isGroupCoach, isGroupWaiting,
 				isCurriculumParticipant, isCurriculumCoach,
-				isAuthor, canLaunch, readOnly);
+				isAuthor, isPrincipal, canLaunch, readOnly);
 	}
 
 	public RepositoryEntry setAccess(final RepositoryEntry re, int access, boolean membersOnly) {
diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java b/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java
index 25c08c17075..8961dc3afb1 100644
--- a/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java
+++ b/src/main/java/org/olat/repository/manager/RepositoryEntryAuthorQueries.java
@@ -340,6 +340,10 @@ public class RepositoryEntryAuthorQueries {
 			}
 			return false;
 		}
+		if(roles.isPrincipal()) {//TODO roles repo
+			sb.append(" v.access>=").append(RepositoryEntry.ACC_OWNERS);
+			return false;
+		}
 		
 		sb.append(" (v.access>=").append(RepositoryEntry.ACC_USERS);
 		if(roles.isAuthor()) {
diff --git a/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java b/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java
index 3800e01284b..68f9bb262a0 100644
--- a/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java
+++ b/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java
@@ -32,6 +32,7 @@ public class RepositoryEntrySecurity {
 	private final boolean entryAdmin;
 	private final boolean readOnly;
 	private final boolean author;
+	private final boolean principal;
 	
 	private final boolean courseParticipant;
 	private final boolean courseCoach;
@@ -46,12 +47,13 @@ public class RepositoryEntrySecurity {
 			boolean courseParticipant, boolean courseCoach,
 			boolean groupParticipant, boolean groupCoach, boolean groupWaiting,
 			boolean curriculumParticipant, boolean curriculumCoach,
-			boolean author,
+			boolean author, boolean principal,
 			boolean canLaunch, boolean readOnly) {
 		this.owner = owner;
 		this.canLaunch = canLaunch;
 		this.entryAdmin = entryAdmin;
 		this.author = author;
+		this.principal = principal;
 		
 		this.courseParticipant = courseParticipant;
 		this.courseCoach = courseCoach;
@@ -129,7 +131,27 @@ public class RepositoryEntrySecurity {
 		return owner || courseParticipant || courseCoach || groupParticipant || groupCoach || curriculumParticipant || curriculumCoach;
 	}
 	
+	/**
+	 * @return true if the user has the role author in an organization
+	 * 		linked by the repository entry
+	 */
 	public boolean isAuthor() {
 		return author;
 	}
+	
+	/**
+	 * @return true if the user has the role principal
+	 */
+	public boolean isPrincipal() {
+		return principal;
+	}
+	
+	/**
+	 * @return true if the user has the role principal but
+	 * 		is not a member or an administrator of the repository
+	 * 		entry.
+	 */
+	public boolean isOnlyPrincipal() {
+		return principal && !isMember() && !isEntryAdmin();
+	}
 }
diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
index 752a5328a70..0a096dc2a30 100644
--- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
+++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
@@ -770,7 +770,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		if(!reSecurity.isEntryAdmin()) return null;
 
 		WindowControl bwControl = getSubWindowControl("MembersMgmt");
-		RepositoryMembersController ctrl = new RepositoryMembersController(ureq, addToHistory(ureq, bwControl), toolbarPanel ,re);
+		RepositoryMembersController ctrl = new RepositoryMembersController(ureq, addToHistory(ureq, bwControl), toolbarPanel, re);
 		listenTo(ctrl);
 		membersEditController = pushController(ureq, translate("details.members"), ctrl);
 		currentToolCtr = membersEditController;
@@ -790,7 +790,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	}
 	
 	private void doRun(UserRequest ureq, RepositoryEntrySecurity security) {
-		if(security.isEntryAdmin()) {
+		if(security.isEntryAdmin() || security.isPrincipal()) {
 			launchContent(ureq, security);
 		} else {
 			// guest are allowed to see resource with BARG 
@@ -803,7 +803,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 				} else if (re != null
 						&& !re.getRepositoryEntryStatus().isUnpublished()
 						&& !re.getRepositoryEntryStatus().isClosed()
-						&& acResult.getAvailableMethods().size() > 0) {
+						&& !acResult.getAvailableMethods().isEmpty()) {
 					//try auto booking
 					ACResultAndSecurity autoResult = tryAutoBooking(ureq, acResult, security);
 					acResult = autoResult.getAcResult();
diff --git a/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java b/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
index 7da44088c15..8b7be9bf8b2 100644
--- a/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
+++ b/src/main/java/org/olat/repository/ui/author/RepositoryMembersController.java
@@ -48,6 +48,7 @@ import org.olat.course.member.wizard.ImportMember_1b_ChooseMemberStep;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.model.BusinessGroupMembershipChange;
 import org.olat.group.ui.main.AbstractMemberListController;
+import org.olat.group.ui.main.MemberListSecurityCallbackFactory;
 import org.olat.group.ui.main.MemberPermissionChangeEvent;
 import org.olat.group.ui.main.MemberRow;
 import org.olat.group.ui.main.SearchMembersParams;
@@ -61,6 +62,8 @@ import org.olat.repository.model.RepositoryEntryPermissionChangeEvent;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
+ * The members list specific to the repository entries (except courses which
+ * have a specialized one).
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
@@ -79,7 +82,7 @@ public class RepositoryMembersController extends AbstractMemberListController {
 	private BusinessGroupService businessGroupService;
 
 	public RepositoryMembersController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RepositoryEntry repoEntry) {
-		super(ureq, wControl, repoEntry, null, "all_member_list", false, stackPanel,
+		super(ureq, wControl, repoEntry, null, "all_member_list", MemberListSecurityCallbackFactory.adminRights(), stackPanel,
 				Util.createPackageTranslator(RepositoryService.class, ureq.getLocale(),
 						Util.createPackageTranslator(AbstractMemberListController.class, ureq.getLocale())));
 
-- 
GitLab