diff --git a/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java b/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java index 837abe9a8347fcf6ba5f20d63bbd0c5b1be108ab..62606cac7b8bf55c13eb564459fbdabeae6e7c15 100644 --- a/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java +++ b/src/main/java/org/olat/basesecurity/manager/OrganisationServiceImpl.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.logging.log4j.Logger; import org.olat.basesecurity.Group; import org.olat.basesecurity.GroupMembership; import org.olat.basesecurity.GroupMembershipInheritance; @@ -39,6 +40,7 @@ import org.olat.basesecurity.OrganisationService; import org.olat.basesecurity.OrganisationStatus; import org.olat.basesecurity.OrganisationType; import org.olat.basesecurity.OrganisationTypeRef; +import org.olat.basesecurity.model.IdentityToRoleKey; import org.olat.basesecurity.model.OrganisationImpl; import org.olat.basesecurity.model.OrganisationMember; import org.olat.basesecurity.model.OrganisationNode; @@ -50,7 +52,6 @@ import org.olat.core.id.Organisation; import org.olat.core.id.OrganisationRef; import org.olat.core.id.Roles; import org.olat.core.logging.AssertException; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -229,13 +230,13 @@ public class OrganisationServiceImpl implements OrganisationService, Initializin private void propagateMembership(OrganisationNode node, List<GroupMembership> membershipsToPropagate) { Group group = node.getOrganisation().getGroup(); List<GroupMembership> nodeMemberships = groupDao.getMemberships(group); - Map<IdentityRoleKey,GroupMembership> identityRoleToMembership = new HashMap<>(); + Map<IdentityToRoleKey,GroupMembership> identityRoleToMembership = new HashMap<>(); for(GroupMembership nodeMembership:nodeMemberships) { - identityRoleToMembership.put(new IdentityRoleKey(nodeMembership), nodeMembership); + identityRoleToMembership.put(new IdentityToRoleKey(nodeMembership), nodeMembership); } for(GroupMembership membershipToPropagate:membershipsToPropagate) { - GroupMembership nodeMembership = identityRoleToMembership.get(new IdentityRoleKey(membershipToPropagate)); + GroupMembership nodeMembership = identityRoleToMembership.get(new IdentityToRoleKey(membershipToPropagate)); if(nodeMembership == null) { groupDao.addMembershipOneWay(group, membershipToPropagate.getIdentity(), membershipToPropagate.getRole(), GroupMembershipInheritance.inherited); } else if(nodeMembership.getInheritanceMode() != GroupMembershipInheritance.inherited) { @@ -251,15 +252,15 @@ public class OrganisationServiceImpl implements OrganisationService, Initializin } } - private void cleanMembership(OrganisationNode node, Set<IdentityRoleKey> inheritance) { + private void cleanMembership(OrganisationNode node, Set<IdentityToRoleKey> inheritance) { List<GroupMembership> memberships = groupDao.getMemberships(node.getOrganisation().getGroup()); for(GroupMembership membership:memberships) { if(membership.getInheritanceMode() == GroupMembershipInheritance.inherited) { - if(!inheritance.contains(new IdentityRoleKey(membership))) { + if(!inheritance.contains(new IdentityToRoleKey(membership))) { groupDao.removeMembership(node.getOrganisation().getGroup(), membership.getIdentity(), membership.getRole()); } } else if(membership.getInheritanceMode() == GroupMembershipInheritance.root) { - inheritance.add(new IdentityRoleKey(membership)); + inheritance.add(new IdentityToRoleKey(membership)); } } @@ -270,34 +271,6 @@ public class OrganisationServiceImpl implements OrganisationService, Initializin } } } - - private static class IdentityRoleKey { - - private final Long identityKey; - private final String role; - - public IdentityRoleKey(GroupMembership membership) { - identityKey = membership.getIdentity().getKey(); - role = membership.getRole(); - } - - @Override - public int hashCode() { - return identityKey.hashCode() + role.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if(this == obj) { - return true; - } - if(obj instanceof IdentityRoleKey) { - IdentityRoleKey m = (IdentityRoleKey)obj; - return identityKey.equals(m.identityKey) && role.equals(m.role); - } - return false; - } - } @Override public Organisation getDefaultOrganisation() { diff --git a/src/main/java/org/olat/basesecurity/model/GroupMembershipImpl.java b/src/main/java/org/olat/basesecurity/model/GroupMembershipImpl.java index 5f40f1cc9eb5d78a89bbc1978dd79b54b6bd806b..5e58a5abadde24ddedc607dfedc6527296d5dbda 100644 --- a/src/main/java/org/olat/basesecurity/model/GroupMembershipImpl.java +++ b/src/main/java/org/olat/basesecurity/model/GroupMembershipImpl.java @@ -94,7 +94,7 @@ public class GroupMembershipImpl implements GroupMembership, ModifiedInfo, Persi @Column(name="g_role", nullable=false, insertable=true, updatable=false) private String role; - @Column(name="g_inheritance_mode", nullable=false, insertable=true, updatable=false) + @Column(name="g_inheritance_mode", nullable=false, insertable=true, updatable=true) private String inheritanceModeString; @ManyToOne(targetEntity=GroupImpl.class,fetch=FetchType.LAZY,optional=false) diff --git a/src/main/java/org/olat/basesecurity/model/IdentityToRoleKey.java b/src/main/java/org/olat/basesecurity/model/IdentityToRoleKey.java new file mode 100644 index 0000000000000000000000000000000000000000..9842879397cfa72360b09ab33be1069d829874d2 --- /dev/null +++ b/src/main/java/org/olat/basesecurity/model/IdentityToRoleKey.java @@ -0,0 +1,61 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.basesecurity.model; + +import org.olat.basesecurity.GroupMembership; + +/** + * + * Initial date: 20 mai 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class IdentityToRoleKey { + + private final Long identityKey; + private final String role; + + public IdentityToRoleKey(GroupMembership membership) { + identityKey = membership.getIdentity().getKey(); + role = membership.getRole(); + } + + public IdentityToRoleKey(Long identityKey, String role) { + this.identityKey = identityKey; + this.role = role; + } + + @Override + public int hashCode() { + return identityKey.hashCode() + role.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof IdentityToRoleKey) { + IdentityToRoleKey m = (IdentityToRoleKey)obj; + return identityKey.equals(m.identityKey) && role.equals(m.role); + } + return false; + } +} diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java index 4d1e75ae6fc5ec8c08ee14d8978ae4fd1bf2d1fa..2c749c57f57e623a127a5d49d44ccf21c3dfdb15 100644 --- a/src/main/java/org/olat/course/CourseFactory.java +++ b/src/main/java/org/olat/course/CourseFactory.java @@ -650,7 +650,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, false, true, false); + RepositoryEntrySecurity reSecurity = new RepositoryEntrySecurity(false, 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/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java index 1708321b2ce3e7f8770f5c280c27d0f9d3d563cb..16535f4e970b03a4223f281a13aa6250b89d2fc7 100644 --- a/src/main/java/org/olat/course/run/CourseRuntimeController.java +++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java @@ -268,8 +268,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im // group rights UserCourseEnvironmentImpl uce = getUserCourseEnvironment(); if(uce != null) { - uce.setUserRoles(security.isEntryAdmin() || security.isPrincipal(), security.isCoach(), security.isParticipant()); - if(security.isOnlyPrincipal()) { + uce.setUserRoles(security.isEntryAdmin() || security.isPrincipal() || security.isMasterCoach(), security.isCoach(), security.isParticipant()); + if(security.isOnlyPrincipal() || security.isOnlyMasterCoach()) { uce.setCourseReadOnly(Boolean.TRUE); } else if(security.isReadOnly()) { if(overrideReadOnly) { @@ -470,7 +470,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im @Override protected void initToolsMenuSettings(Dropdown tools) { // 1) administrative tools - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT)) { @@ -484,7 +484,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im tools.addComponent(settingsLink); } - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || 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); @@ -506,7 +506,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im tools.addComponent(editLink); } - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) { folderLink = LinkFactory.createToolLink("cfd", translate("command.coursefolder"), this, "o_icon_coursefolder"); folderLink.setElementCssClass("o_sel_course_folder"); tools.addComponent(folderLink); @@ -516,19 +516,19 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private void initToolsMenuRuntime(Dropdown tools, final UserCourseEnvironmentImpl uce) { boolean courseAuthorRight = reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR); - if (courseAuthorRight || reSecurity.isPrincipal() || reSecurity.isCoach() + if (courseAuthorRight || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_DB) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) { tools.addComponent(new Spacer("")); - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || 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); } - if(lectureModule.isEnabled() && (courseAuthorRight || reSecurity.isPrincipal()) && isLectureEnabled()) { + if(lectureModule.isEnabled() && (courseAuthorRight || reSecurity.isPrincipal() || reSecurity.isMasterCoach()) && isLectureEnabled()) { 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()); @@ -542,7 +542,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im tools.addComponent(reminderLink); } - if (courseAuthorRight || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) { + if (courseAuthorRight || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) { //course author right or the assessment mode access right boolean managed = RepositoryEntryManagedFlag.isManaged(getRepositoryEntry(), RepositoryEntryManagedFlag.editcontent); assessmentModeLink = LinkFactory.createToolLink("assessment.mode.cmd", translate("command.assessment.mode"), this, "o_icon_assessment_mode"); @@ -571,17 +571,17 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im } private void initToolsMenuStatistics(Dropdown tools, ICourse course, final UserCourseEnvironmentImpl uce) { - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isCoach() + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ARCHIVING) || hasCourseRight(CourseRights.RIGHT_STATISTICS)) { tools.addComponent(new Spacer("")); - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || 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.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS))) { + if (uce != null && (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS))) { final AtomicInteger testNodes = new AtomicInteger(); final AtomicInteger surveyNodes = new AtomicInteger(); new TreeVisitor(node -> { @@ -1122,7 +1122,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.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { + if(reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { try { Activateable2 assessmentCtrl = doAssessmentTool(ureq); if(assessmentCtrl != null) { @@ -1140,7 +1140,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.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { + if(reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT)) { try { Activateable2 assessmentCtrl = null; if("TestStatistics".equalsIgnoreCase(type)) { @@ -1226,14 +1226,14 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im @Override protected Activateable2 doMembers(UserRequest ureq) { if(delayedClose == Delayed.members || requestForClose(ureq)) { - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT) || hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || 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(), reSecurity.isPrincipal(), + getRepositoryEntry(), getUserCourseEnvironment(), reSecurity.isEntryAdmin(), reSecurity.isPrincipal() || reSecurity.isMasterCoach(), hasCourseRight(CourseRights.RIGHT_GROUPMANAGEMENT), hasCourseRight(CourseRights.RIGHT_MEMBERMANAGEMENT)); listenTo(ctrl); membersCtrl = pushController(ureq, translate("command.opensimplegroupmngt"), ctrl); @@ -1301,7 +1301,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private void doAssessmentMode(UserRequest ureq) { if(delayedClose == Delayed.assessmentMode || requestForClose(ureq)) { - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() + || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE)) { removeCustomCSS(); boolean canManage = reSecurity.isEntryAdmin() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR) || hasCourseRight(CourseRights.RIGHT_ASSESSMENT_MODE); @@ -1334,7 +1335,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private LectureRepositoryAdminController doLecturesAdmin(UserRequest ureq) { if(delayedClose == Delayed.lecturesAdmin || requestForClose(ureq)) { - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || hasCourseRight(CourseRights.RIGHT_COURSEEDITOR)) { removeCustomCSS(); OLATResourceable ores = OresHelper.createOLATResourceableType("LecturesAdmin"); @@ -1450,7 +1451,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im private void doCourseStatistics(UserRequest ureq) { if(delayedClose == Delayed.courseStatistics || requestForClose(ureq)) { - if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal()|| hasCourseRight(CourseRights.RIGHT_STATISTICS)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() + || hasCourseRight(CourseRights.RIGHT_STATISTICS)) { removeCustomCSS(); ICourse course = CourseFactory.loadCourse(getRepositoryEntry()); StatisticMainController ctrl = new StatisticMainController(ureq, getWindowControl(), course); @@ -1498,7 +1500,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.isPrincipal() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) { + if (reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || reSecurity.isCoach() || hasCourseRight(CourseRights.RIGHT_STATISTICS)) { removeCustomCSS(); UserCourseEnvironmentImpl uce = getUserCourseEnvironment(); StatisticCourseNodesController ctrl = new StatisticCourseNodesController(ureq, swControl, toolbarPanel, reSecurity, uce, type); @@ -1517,7 +1519,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); WindowControl swControl = addToHistory(ureq, ores, null); - boolean admin = reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT); + boolean admin = reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() || hasCourseRight(CourseRights.RIGHT_ASSESSMENT); boolean nonMembers = reSecurity.isEntryAdmin(); List<BusinessGroup> coachedGroups = null; UserCourseEnvironment userCourseEnv = getUserCourseEnvironment(); diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java index 75087fcd01b2d3b8e49bc728986d7ed3036b9510..0dadf7345730a039f4c35c323d14feae5239f79a 100644 --- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java +++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java @@ -125,8 +125,8 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment { return new UserCourseEnvironmentImpl(ureq.getUserSession().getIdentityEnvironment(), course.getCourseEnvironment(), wControl, coachedGroups, participatedGroups, waitingLists, - reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal(), reSecurity.isParticipant(), - reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal()); + reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach() , reSecurity.isParticipant(), + reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal() || reSecurity.isOnlyMasterCoach()); } /** diff --git a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java index 1b6e4cadedec051d37c576818695945025163374..72ce6eb18166e732b89405d0981f767243274b39 100644 --- a/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java +++ b/src/main/java/org/olat/modules/adobeconnect/ui/AdobeConnectMeetingDefaultConfiguration.java @@ -1,3 +1,22 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ package org.olat.modules.adobeconnect.ui; /** diff --git a/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java b/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java index d13a058e74c6a4b9d8e49947f161cbe24a42c3b9..d1532fd9d44d496dc51b001a3cbd3b93cb1f1657 100644 --- a/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java +++ b/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java @@ -388,7 +388,7 @@ public class CoachingDAO { .append(" inner join v.groups as relGroup") .append(" inner join relGroup.group as baseGroup") .append(" inner join baseGroup.members as coach on coach.role ") - .in(GroupRoles.coach, GroupRoles.owner.name()) + .in(GroupRoles.coach, GroupRoles.owner) .append(" where coach.identity.key=:coachKey and res.resName='CourseModule'") .append(" and v.status ").in(RepositoryEntryStatusEnum.coachPublishedToClosed()); 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 e85982c001bcbe480543a5695b32ca36a14f9b2c..6573953ed04653ba37f5cd2ccf90d8468d64bd88 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.isPrincipal(), reSecurity.isParticipant(), - reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal()); + reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach(), reSecurity.isParticipant(), + reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal() || reSecurity.isOnlyMasterCoach()); } @Override diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java b/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java index a251b9131f0b7c9583bd83375e1499a58358856f..80a99939dc8d6d4033ae1ba18d8f352e7cf9f971 100644 --- a/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java +++ b/src/main/java/org/olat/modules/curriculum/CurriculumRoles.java @@ -37,6 +37,7 @@ public enum CurriculumRoles { curriculumowner,// own a piece of a curriculum curriculumelementowner,// own a piece of curriculum owner, //same as GroupRoles + mastercoach, coach, //same as GroupRoles participant; //same as GroupRoles @@ -62,4 +63,12 @@ public enum CurriculumRoles { } return false; } + + /** + * @param role The role to check + * @return true if the role is by default inherited in the curriculum tree + */ + public static boolean isInheritedByDefault(CurriculumRoles role) { + return role == CurriculumRoles.mastercoach; + } } diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java index 1dc5277223deb3b08066d4812b0da709840318f3..9665ad2c8a7cd5e5de4204f8d597717e91466ddd 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java @@ -60,6 +60,7 @@ import org.olat.modules.curriculum.CurriculumRoles; import org.olat.modules.curriculum.model.CurriculumElementImpl; import org.olat.modules.curriculum.model.CurriculumElementInfos; import org.olat.modules.curriculum.model.CurriculumElementMembershipImpl; +import org.olat.modules.curriculum.model.CurriculumElementNode; import org.olat.modules.curriculum.model.CurriculumElementSearchInfos; import org.olat.modules.curriculum.model.CurriculumElementSearchParams; import org.olat.modules.curriculum.model.CurriculumImpl; @@ -745,7 +746,34 @@ public class CurriculumElementDAO { .getResultList(); } - + public CurriculumElementNode getDescendantTree(CurriculumElement rootElement) { + List<CurriculumElement> descendants = getChildren(rootElement); + CurriculumElementNode rootNode = new CurriculumElementNode(rootElement); + + Map<Long,CurriculumElementNode> keyToOrganisations = new HashMap<>(); + for(CurriculumElement descendant:descendants) { + keyToOrganisations.put(descendant.getKey(), new CurriculumElementNode(descendant)); + } + + for(CurriculumElement descendant:descendants) { + Long key = descendant.getKey(); + if(key.equals(rootElement.getKey())) { + continue; + } + + CurriculumElementNode node = keyToOrganisations.get(key); + CurriculumElement parentOrganisation = descendant.getParent(); + Long parentKey = parentOrganisation.getKey(); + if(parentKey.equals(rootElement.getKey())) { + //this is a root, or the user has not access to parent + rootNode.addChild(node); + } else { + CurriculumElementNode parentNode = keyToOrganisations.get(parentKey); + parentNode.addChild(node); + } + } + return rootNode; + } public List<Identity> getMembersIdentity(CurriculumElementRef element, String role) { StringBuilder sb = new StringBuilder(256); diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumMemberQueries.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumMemberQueries.java index 949600910af388a9d46634e2ca46e3fd3b0fc842..cf13b36b3bdb75b803aaeb69bdde3232091c6070 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumMemberQueries.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumMemberQueries.java @@ -52,7 +52,7 @@ public class CurriculumMemberQueries { public List<CurriculumMember> getMembers(CurriculumRef curriculum, SearchMemberParameters params) { StringBuilder sb = new StringBuilder(256); - sb.append("select ident, membership.role from curriculum cur") + sb.append("select ident, membership.role, membership.inheritanceModeString from curriculum cur") .append(" inner join cur.group baseGroup") .append(" inner join baseGroup.members membership") .append(" inner join membership.identity ident") @@ -70,7 +70,12 @@ public class CurriculumMemberQueries { for(Object[] object:rawObjects) { Identity identity = (Identity)object[0]; String role = (String)object[1]; - members.add(new CurriculumMember(identity, role)); + String inheritanceModeString = (String)object[2]; + GroupMembershipInheritance inheritanceMode = GroupMembershipInheritance.none; + if(StringHelper.containsNonWhitespace(inheritanceModeString)) { + inheritanceMode = GroupMembershipInheritance.valueOf(inheritanceModeString); + } + members.add(new CurriculumMember(identity, role, inheritanceMode)); } return members; } diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java index f8ba5b3ac81308a9c14d117fe4887e09e2128fe5..d476d86de754ae3caf1236c21086b258916bcc57 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java @@ -30,18 +30,22 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.olat.basesecurity.Group; +import org.olat.basesecurity.GroupMembership; import org.olat.basesecurity.GroupMembershipInheritance; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.OrganisationDataDeletable; import org.olat.basesecurity.OrganisationRoles; import org.olat.basesecurity.manager.GroupDAO; +import org.olat.basesecurity.model.IdentityToRoleKey; import org.olat.core.CoreSpringFactory; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; import org.olat.core.id.Organisation; import org.olat.core.id.OrganisationRef; import org.olat.core.id.Roles; +import org.olat.core.logging.AssertException; import org.olat.modules.curriculum.Curriculum; import org.olat.modules.curriculum.CurriculumCalendars; import org.olat.modules.curriculum.CurriculumDataDeletable; @@ -63,6 +67,7 @@ import org.olat.modules.curriculum.model.CurriculumCopySettings.CopyResources; import org.olat.modules.curriculum.model.CurriculumElementImpl; import org.olat.modules.curriculum.model.CurriculumElementInfos; import org.olat.modules.curriculum.model.CurriculumElementMembershipChange; +import org.olat.modules.curriculum.model.CurriculumElementNode; import org.olat.modules.curriculum.model.CurriculumElementRepositoryEntryViews; import org.olat.modules.curriculum.model.CurriculumElementSearchInfos; import org.olat.modules.curriculum.model.CurriculumElementSearchParams; @@ -272,8 +277,19 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat if(parentRef == null) { curriculum = getCurriculum(curriculum); } - return curriculumElementDao.createCurriculumElement(identifier, displayName, status, + CurriculumElement element = curriculumElementDao.createCurriculumElement(identifier, displayName, status, beginDate, endDate, parentRef, elementType, calendars, lectures, curriculum); + if(element.getParent() != null) { + Group organisationGroup = element.getGroup(); + List<GroupMembership> memberships = groupDao.getMemberships(element.getParent().getGroup()); + for(GroupMembership membership:memberships) { + if(membership.getInheritanceMode() == GroupMembershipInheritance.inherited + || membership.getInheritanceMode() == GroupMembershipInheritance.root) { + groupDao.addMembershipOneWay(organisationGroup, membership.getIdentity(), membership.getRole(), GroupMembershipInheritance.inherited); + } + } + } + return element; } @Override @@ -388,11 +404,65 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat @Override public CurriculumElement moveCurriculumElement(CurriculumElement elementToMove, CurriculumElement newParent, CurriculumElement siblingBefore) { - return curriculumElementDao.move(elementToMove, newParent, siblingBefore); + CurriculumElement element = curriculumElementDao.move(elementToMove, newParent, siblingBefore); + + // propagate inheritance of the new parent + List<GroupMembership> memberships = groupDao.getMemberships(newParent.getGroup()); + List<GroupMembership> membershipsToPropagate = new ArrayList<>(); + Map<IdentityToRoleKey,GroupMembership> identityRoleToNewParentMembership = new HashMap<>(); + for(GroupMembership membership:memberships) { + if(membership.getInheritanceMode() == GroupMembershipInheritance.inherited || membership.getInheritanceMode() == GroupMembershipInheritance.root) { + membershipsToPropagate.add(membership); + identityRoleToNewParentMembership.put(new IdentityToRoleKey(membership), membership); + } + } + + // inherited of the moved element eventuel -> root + List<GroupMembership> movedElementMemberships = groupDao.getMemberships(element.getGroup()); + for(GroupMembership movedElementMembership:movedElementMemberships) { + if(movedElementMembership.getInheritanceMode() == GroupMembershipInheritance.inherited) { + GroupMembership newParentMembership = identityRoleToNewParentMembership.get(new IdentityToRoleKey(movedElementMembership)); + if(newParentMembership == null || newParentMembership.getInheritanceMode() == GroupMembershipInheritance.none) { + groupDao.updateInheritanceMode(movedElementMembership, GroupMembershipInheritance.root); + } + } + } + + CurriculumElementNode treeToMove = curriculumElementDao.getDescendantTree(element); + if(!membershipsToPropagate.isEmpty()) { + propagateMembership(treeToMove, membershipsToPropagate); + } + return element; + } + + private void propagateMembership(CurriculumElementNode node, List<GroupMembership> membershipsToPropagate) { + Group group = node.getElement().getGroup(); + List<GroupMembership> nodeMemberships = groupDao.getMemberships(group); + Map<IdentityToRoleKey,GroupMembership> identityRoleToMembership = new HashMap<>(); + for(GroupMembership nodeMembership:nodeMemberships) { + identityRoleToMembership.put(new IdentityToRoleKey(nodeMembership), nodeMembership); + } + + for(GroupMembership membershipToPropagate:membershipsToPropagate) { + GroupMembership nodeMembership = identityRoleToMembership.get(new IdentityToRoleKey(membershipToPropagate)); + if(nodeMembership == null) { + groupDao.addMembershipOneWay(group, membershipToPropagate.getIdentity(), membershipToPropagate.getRole(), GroupMembershipInheritance.inherited); + } else if(nodeMembership.getInheritanceMode() != GroupMembershipInheritance.inherited) { + groupDao.updateInheritanceMode(nodeMembership, GroupMembershipInheritance.inherited); + } + } + + List<CurriculumElementNode> children = node.getChildrenNode(); + if(children != null && !children.isEmpty()) { + for(CurriculumElementNode child:children) { + propagateMembership(child, membershipsToPropagate); + } + } } @Override public CurriculumElement moveCurriculumElement(CurriculumElement rootElement, Curriculum curriculum) { + // root element move they entire memberships with, don't need to change them CurriculumElement element = curriculumElementDao.move(rootElement, curriculum); dbInstance.commit(); return element; @@ -525,14 +595,81 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat @Override public void addMember(CurriculumElement element, Identity member, CurriculumRoles role) { - if(!groupDao.hasRole(element.getGroup(), member, role.name())) { - groupDao.addMembershipOneWay(element.getGroup(), member, role.name(), GroupMembershipInheritance.none); - } + GroupMembershipInheritance inheritanceMode; + if(CurriculumRoles.isInheritedByDefault(role)) { + inheritanceMode = GroupMembershipInheritance.root; + } else { + inheritanceMode = GroupMembershipInheritance.none; + } + addMember(element, member, role, inheritanceMode); + } + + public void addMember(CurriculumElement element, Identity member, CurriculumRoles role, GroupMembershipInheritance inheritanceMode) { + if(inheritanceMode == GroupMembershipInheritance.inherited) { + throw new AssertException("Inherited are automatic"); + } + + GroupMembership membership = groupDao.getMembership(element.getGroup(), member, role.name()); + if(membership == null) { + groupDao.addMembershipOneWay(element.getGroup(), member, role.name(), inheritanceMode); + } else if(membership.getInheritanceMode() != inheritanceMode) { + groupDao.updateInheritanceMode(membership, inheritanceMode); + } + + if(inheritanceMode == GroupMembershipInheritance.root) { + List<CurriculumElement> descendants = curriculumElementDao.getDescendants(element); + for(CurriculumElement descendant:descendants) { + GroupMembership inheritedMembership = groupDao.getMembership(descendant.getGroup(), member, role.name()); + if(inheritedMembership == null) { + groupDao.addMembershipOneWay(descendant.getGroup(), member, role.name(), GroupMembershipInheritance.inherited); + } else if(inheritedMembership.getInheritanceMode() == GroupMembershipInheritance.none) { + groupDao.updateInheritanceMode(inheritedMembership, GroupMembershipInheritance.inherited); + } + } + } } @Override public void removeMember(CurriculumElement element, IdentityRef member) { groupDao.removeMembership(element.getGroup(), member); + + List<GroupMembership> memberships = groupDao.getMemberships(element.getGroup(), member); + + CurriculumElementNode elementNode = null; + for(GroupMembership membership:memberships) { + if(membership.getInheritanceMode() == GroupMembershipInheritance.none) { + groupDao.removeMembership(membership); + } else if(membership.getInheritanceMode() == GroupMembershipInheritance.root) { + String role = membership.getRole(); + groupDao.removeMembership(membership); + + if(elementNode == null) { + elementNode = curriculumElementDao.getDescendantTree(element); + } + for(CurriculumElementNode child:elementNode.getChildrenNode()) { + removeInherithedMembership(child, member, role); + } + } + } + } + + /** + * The method will recursively delete the inherithed membership. If it + * found a mebership marked as "root" or "none". It will stop. + * + * @param elementNode The organization node + * @param member The user to remove + * @param role The role + */ + private void removeInherithedMembership(CurriculumElementNode elementNode, IdentityRef member, String role) { + GroupMembership membership = groupDao + .getMembership(elementNode.getElement().getGroup(), member, role); + if(membership != null && membership.getInheritanceMode() == GroupMembershipInheritance.inherited) { + groupDao.removeMembership(membership); + for(CurriculumElementNode child:elementNode.getChildrenNode()) { + removeInherithedMembership(child, member, role); + } + } } @Override diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumElementNode.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumElementNode.java new file mode 100644 index 0000000000000000000000000000000000000000..6a8b59d2aa525f949a4327e81628b9a7d12d3608 --- /dev/null +++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumElementNode.java @@ -0,0 +1,57 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.curriculum.model; + +import java.util.ArrayList; +import java.util.List; + +import org.olat.modules.curriculum.CurriculumElement; + +/** + * + * Initial date: 20 mai 2019<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CurriculumElementNode { + + private final CurriculumElement element; + private final List<CurriculumElementNode> children = new ArrayList<>(); + + public CurriculumElementNode(CurriculumElement element) { + this.element = element; + } + + public CurriculumElement getElement() { + return element; + } + + /** + * @return A copy of the list of direct children. + */ + public List<CurriculumElementNode> getChildrenNode() { + return new ArrayList<>(children); + } + + public void addChild(CurriculumElementNode node) { + children.add(node); + } + +} diff --git a/src/main/java/org/olat/modules/curriculum/model/CurriculumMember.java b/src/main/java/org/olat/modules/curriculum/model/CurriculumMember.java index 4cd8bb7e28ae87f75788a525a21b68dc2d2b21ef..4070439047ce3a9053310ac5c9aac09513f948b5 100644 --- a/src/main/java/org/olat/modules/curriculum/model/CurriculumMember.java +++ b/src/main/java/org/olat/modules/curriculum/model/CurriculumMember.java @@ -34,10 +34,6 @@ public class CurriculumMember { private final String role; private final GroupMembershipInheritance inheritanceMode; - public CurriculumMember(Identity identity, String role) { - this(identity, role, GroupMembershipInheritance.none); - } - public CurriculumMember(Identity identity, String role, GroupMembershipInheritance inheritanceMode) { this.identity = identity; this.role = role; diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java index a102a9332d121b83cf32bdcab1ad0504287484a0..734df439eb4f49d35ea12c3922f8c83d7550c771 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java +++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumElementUserManagementController.java @@ -27,6 +27,7 @@ import java.util.Set; import org.olat.admin.user.UserSearchController; import org.olat.admin.user.UserTableDataModel; import org.olat.basesecurity.BaseSecurityModule; +import org.olat.basesecurity.GroupMembershipInheritance; import org.olat.basesecurity.events.MultiIdentityChosenEvent; import org.olat.basesecurity.events.SingleIdentityChosenEvent; import org.olat.basesecurity.model.IdentityRefImpl; @@ -238,13 +239,17 @@ public class CurriculumElementUserManagementController extends FormBasicControll private void doConfirmRemoveAllMemberships(UserRequest ureq) { Set<Integer> selectedRows = tableEl.getMultiSelectedIndex(); - if(selectedRows.isEmpty()) { + List<CurriculumMemberRow> rows = new ArrayList<>(selectedRows.size()); + for(Integer selectedRow:selectedRows) { + CurriculumMemberRow row = tableModel.getObject(selectedRow.intValue()); + if(row.getInheritanceMode() == GroupMembershipInheritance.root || row.getInheritanceMode() == GroupMembershipInheritance.none) { + rows.add(row); + } + } + + if(rows.isEmpty()) { showWarning("warning.atleastone.member"); } else { - List<CurriculumMemberRow> rows = new ArrayList<>(selectedRows.size()); - for(Integer selectedRow:selectedRows) { - rows.add(tableModel.getObject(selectedRow.intValue())); - } String title = translate("confirm.remove.member.title"); confirmRemoveCtrl = activateYesNoDialog(ureq, title, translate("confirm.remove.member.text", ""), confirmRemoveCtrl); confirmRemoveCtrl.setUserObject(rows); @@ -267,7 +272,7 @@ public class CurriculumElementUserManagementController extends FormBasicControll String title = translate("add.member"); CurriculumRoles[] roles = new CurriculumRoles[] { - CurriculumRoles.curriculumelementowner, + CurriculumRoles.curriculumelementowner, CurriculumRoles.mastercoach, CurriculumRoles.owner, CurriculumRoles.coach, CurriculumRoles.participant }; roleListCtrl = new RoleListController(ureq, getWindowControl(), roles); diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumUserManagementTableModel.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumUserManagementTableModel.java index 5a1d73db8f017ecd0b285cc85c274f0072519ddf..c16c54229d501278ab7fd044a20c4681ef9b8bb3 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumUserManagementTableModel.java +++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumUserManagementTableModel.java @@ -21,6 +21,7 @@ package org.olat.modules.curriculum.ui; import java.util.Locale; +import org.olat.basesecurity.GroupMembershipInheritance; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; @@ -50,6 +51,13 @@ implements SortableFlexiTableDataModel<CurriculumMemberRow> { super.setObjects(sort.sort()); } } + + @Override + public boolean isSelectable(int row) { + CurriculumMemberRow member = getObject(row); + return member.getInheritanceMode() == GroupMembershipInheritance.root + || member.getInheritanceMode() == GroupMembershipInheritance.none; + } @Override public Object getValueAt(int row, int col) { diff --git a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties index c0ce34ff1424e6318b4fbe334c36e8f52ee3bdd1..440d5cca7eb2f520c11ae7bc9703e9766922721f 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_de.properties @@ -76,6 +76,7 @@ role.coach=Betreuer role.curriculumelementowner=Elementbesitzer role.curriculummanager=Curriculumverwalter role.curriculumowner=Curriculumbesitzer +role.mastercoach=Klassenlehrer role.owner=Kursbesitzer role.participant=Teilnehmer search.element.id=Element ID diff --git a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties index 5a9b288cd2d65d5ad653d9b68e5b5080f7d69099..d66b8c97e91abd392485ff27896ce584ccce3457 100644 --- a/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/curriculum/ui/_i18n/LocalStrings_en.properties @@ -76,6 +76,7 @@ role.coach=Coach role.curriculumelementowner=Element owner role.curriculummanager=Curriculum manager role.curriculumowner=Curriculum owner +role.mastercoach=Master coach role.owner=Course owner role.participant=Participant search.element.begin=From diff --git a/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java b/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java index e1afe86ba52039ac00096559bd245d11071fe2b0..49067eb5458ceb07e03a83269b883365e579e60c 100644 --- a/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java +++ b/src/main/java/org/olat/modules/vitero/manager/ViteroManager.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.StringWriter; import java.math.BigInteger; import java.net.ConnectException; +import java.net.SocketTimeoutException; import java.net.URI; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -48,7 +49,7 @@ import javax.xml.ws.handler.HandlerResolver; import javax.xml.ws.handler.PortInfo; import javax.xml.ws.soap.SOAPFaultException; -import org.apache.commons.httpclient.ConnectTimeoutException; +import org.apache.logging.log4j.Logger; import org.olat.basesecurity.Authentication; import org.olat.basesecurity.BaseSecurity; import org.olat.core.commons.persistence.DB; @@ -56,7 +57,6 @@ import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; import org.olat.core.id.User; import org.olat.core.id.UserConstants; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.util.StringHelper; import org.olat.core.util.WebappHelper; @@ -1490,7 +1490,7 @@ public class ViteroManager implements UserDataDeletable { return ErrorCode.find(code); } return ErrorCode.unkown; - } else if (f.getCause() instanceof ConnectTimeoutException) { + } else if (f.getCause() instanceof SocketTimeoutException) { throw new VmsNotAvailableException(f); } return ErrorCode.unkown; diff --git a/src/main/java/org/olat/note/NoteController.java b/src/main/java/org/olat/note/NoteController.java index 8428ceefe7c3fe39d5de2a8a7087867eef29a077..52503418aa42052de39ac507c304ab1ec443084f 100644 --- a/src/main/java/org/olat/note/NoteController.java +++ b/src/main/java/org/olat/note/NoteController.java @@ -25,6 +25,7 @@ package org.olat.note; +import org.olat.core.commons.persistence.DB; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -65,6 +66,8 @@ public class NoteController extends FormBasicController implements GenericEventL private FormLink editButton; private FormSubmit submitButton; + @Autowired + private DB dbInstance; @Autowired private NoteManager noteManager; @@ -129,7 +132,11 @@ public class NoteController extends FormBasicController implements GenericEventL noteField = uifactory.addRichTextElementForStringData("noteField", null, n.getNoteText(), 20, -1, false, null, null, formLayout, ureq.getUserSession(), getWindowControl()); noteField.setEnabled(false); - noteField.setMaxLength(4000); + if(dbInstance.isOracle()) { + noteField.setMaxLength(4000); + } else { + noteField.setMaxLength(400000); + } submitButton = uifactory.addFormSubmitButton("submit", formLayout); submitButton.setVisible(false); diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java index cf93395e67e77589e62dde9fb2109353e01ecfdd..3fb56fc3c237d33ff97eefe14cd92a6b5712e170 100644 --- a/src/main/java/org/olat/repository/RepositoryManager.java +++ b/src/main/java/org/olat/repository/RepositoryManager.java @@ -39,6 +39,7 @@ import java.util.Set; import javax.persistence.TypedQuery; +import org.apache.logging.log4j.Logger; import org.olat.admin.securitygroup.gui.IdentitiesAddEvent; import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityImpl; @@ -57,7 +58,6 @@ import org.olat.core.id.OLATResourceable; import org.olat.core.id.Organisation; import org.olat.core.id.Roles; import org.olat.core.logging.AssertException; -import org.apache.logging.log4j.Logger; import org.olat.core.logging.Tracing; import org.olat.core.logging.activity.ActionType; import org.olat.core.logging.activity.OlatResourceableType; @@ -77,6 +77,7 @@ import org.olat.core.util.vfs.VFSManager; import org.olat.course.PersistingCourseImpl; import org.olat.fileresource.FileResourceManager; import org.olat.group.GroupLoggingAction; +import org.olat.modules.curriculum.CurriculumRoles; import org.olat.modules.taxonomy.TaxonomyLevel; import org.olat.repository.manager.RepositoryEntryDAO; import org.olat.repository.manager.RepositoryEntryQueries; @@ -527,6 +528,7 @@ public class RepositoryManager { boolean isPrincipal = false; boolean isAdministrator = false; boolean isLearnRessourceManager = false; + boolean isMasterCoach = false; boolean canLaunch = false; RepositoryEntryStatusEnum status = re.getEntryStatus(); @@ -592,6 +594,13 @@ public class RepositoryManager { break; default: break; } + } else if(CurriculumRoles.isValueOf(role)) { + switch(CurriculumRoles.valueOf(role)) { + case mastercoach: + isMasterCoach = true; + break; + default: break; + } } } @@ -617,7 +626,7 @@ public class RepositoryManager { } } - if(!canLaunch && (isGroupCoach || isCourseCoach || isCurriculumCoach)) { + if(!canLaunch && (isGroupCoach || isCourseCoach || isCurriculumCoach || isMasterCoach)) { canLaunch = status == RepositoryEntryStatusEnum.coachpublished || status == RepositoryEntryStatusEnum.published || status == RepositoryEntryStatusEnum.closed; @@ -636,7 +645,7 @@ public class RepositoryManager { return new RepositoryEntrySecurity(isEntryAdmin, isOwner, isCourseParticipant, isCourseCoach, isGroupParticipant, isGroupCoach, isGroupWaiting, - isCurriculumParticipant, isCurriculumCoach, + isCurriculumParticipant, isCurriculumCoach, isMasterCoach, isAuthor, isPrincipal, canLaunch, readOnly); } diff --git a/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java b/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java index 68f9bb262a0f73651fe430259a044b11aac2fbd2..3f4486f967ef5d00231a6f8eb345460b1940e033 100644 --- a/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java +++ b/src/main/java/org/olat/repository/model/RepositoryEntrySecurity.java @@ -33,6 +33,7 @@ public class RepositoryEntrySecurity { private final boolean readOnly; private final boolean author; private final boolean principal; + private final boolean masterCoach; private final boolean courseParticipant; private final boolean courseCoach; @@ -46,7 +47,7 @@ public class RepositoryEntrySecurity { public RepositoryEntrySecurity(boolean entryAdmin, boolean owner, boolean courseParticipant, boolean courseCoach, boolean groupParticipant, boolean groupCoach, boolean groupWaiting, - boolean curriculumParticipant, boolean curriculumCoach, + boolean curriculumParticipant, boolean curriculumCoach, boolean masterCoach, boolean author, boolean principal, boolean canLaunch, boolean readOnly) { this.owner = owner; @@ -54,6 +55,7 @@ public class RepositoryEntrySecurity { this.entryAdmin = entryAdmin; this.author = author; this.principal = principal; + this.masterCoach = masterCoach; this.courseParticipant = courseParticipant; this.courseCoach = courseCoach; @@ -87,6 +89,10 @@ public class RepositoryEntrySecurity { return courseParticipant || groupParticipant || curriculumParticipant; } + public boolean isMasterCoach() { + return masterCoach; + } + public boolean isEntryAdmin() { return entryAdmin; } @@ -154,4 +160,8 @@ public class RepositoryEntrySecurity { public boolean isOnlyPrincipal() { return principal && !isMember() && !isEntryAdmin(); } + + public boolean isOnlyMasterCoach() { + return masterCoach && !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 1006254e1c75c476a9f8083f2f2cad30aabd64e1..63d5536076316c10fd7fcdfd3d722e03d5f04766 100644 --- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java +++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java @@ -883,7 +883,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController } private void doRun(UserRequest ureq, RepositoryEntrySecurity security) { - if(security.isEntryAdmin() || security.isPrincipal()) { + if(security.isEntryAdmin() || security.isPrincipal() || reSecurity.isMasterCoach()) { launchContent(ureq, security); } else { // guest are allowed to see resource with BARG diff --git a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java index 7d33201d949cf1d12f6c8a981d204887a4428319..a0590a225ef8b1ca63426ad72f117cbe242c66a5 100644 --- a/src/main/java/org/olat/restapi/repository/course/CourseWebService.java +++ b/src/main/java/org/olat/restapi/repository/course/CourseWebService.java @@ -187,8 +187,8 @@ public class CourseWebService { UserCourseEnvironment userCourseEnv = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment(), null, null, null, null, - reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal(), reSecurity.isParticipant(), - reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal()); + reSecurity.isCoach(), reSecurity.isEntryAdmin() || reSecurity.isPrincipal() || reSecurity.isMasterCoach(), reSecurity.isParticipant(), + reSecurity.isReadOnly() || reSecurity.isOnlyPrincipal() || reSecurity.isOnlyMasterCoach()); KalendarRenderWrapper wrapper = CourseCalendars.getCourseCalendarWrapper(ureq, userCourseEnv, null); return new CalWebService(wrapper); }