diff --git a/pom.xml b/pom.xml index d39983fb3cecb1ae57af71f557b0bef0e160b568..f9822ea424c3c9196440563de550e3c061ff2933 100644 --- a/pom.xml +++ b/pom.xml @@ -1350,7 +1350,15 @@ </execution> </executions> </plugin> - </plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>10</source> + <target>10</target> + </configuration> + </plugin> + </plugins> <pluginManagement> <plugins> <!-- OLAT requires JDK 1.8 or later ! --> diff --git a/src/main/java/org/olat/admin/user/UserShortDescription.java b/src/main/java/org/olat/admin/user/UserShortDescription.java index 9bf49ef1f358d612525ac7f7e7200df75296300a..88525271a4c086afa2bb6158ad652543c9f99955 100644 --- a/src/main/java/org/olat/admin/user/UserShortDescription.java +++ b/src/main/java/org/olat/admin/user/UserShortDescription.java @@ -38,7 +38,7 @@ import org.olat.core.gui.control.controller.BasicController; import org.olat.core.id.Identity; import org.olat.core.id.Roles; import org.olat.core.id.UserConstants; -import org.olat.modules.coach.ui.UserRelationOverviewController; +import org.olat.modules.coach.ui.UserOverviewController; import org.olat.user.UserManager; import org.olat.user.propertyhandlers.UserPropertyHandler; import org.springframework.beans.factory.annotation.Autowired; @@ -79,7 +79,7 @@ public class UserShortDescription extends BasicController { public UserShortDescription(UserRequest ureq, WindowControl wControl, Identity identity, boolean isAdministrativeUser) { super(ureq, wControl); - initProperties(UserRelationOverviewController.usageIdentifier, identity, isAdministrativeUser, true, null); + initProperties(UserOverviewController.usageIdentifier, identity, isAdministrativeUser, true, null); } private void initProperties(String identifier, Identity identity, boolean isAdministrativeUser, boolean usernameOnTop, Rows additionalRows) { diff --git a/src/main/java/org/olat/admin/user/_content/userShortDescription.html b/src/main/java/org/olat/admin/user/_content/userShortDescription.html index e609ce260c73f9475bec13d08628e635394d9231..51d34dafa2efa9b63dfe4431b7ce8948a143af0e 100644 --- a/src/main/java/org/olat/admin/user/_content/userShortDescription.html +++ b/src/main/java/org/olat/admin/user/_content/userShortDescription.html @@ -1,6 +1,6 @@ <div class="o_userShortDescription" id="$r.getCId()"> <table class="table table-bordered table-condensed table-striped"> - #if($r.isNotNull($usernamePosition) && $usernamePosition == "top") + #if($r.isNotNull($identityKey) && $r.isNotNull($usernamePosition) && $usernamePosition == "top") #if($r.isNotNull($username)) <tr class="o_prop o_username"> <th scope="row">$usernameLabel</th> @@ -20,7 +20,7 @@ </tr> #end #end - #if($r.isNotNull($usernamePosition) && $usernamePosition == "bottom") + #if($r.isNotNull($identityKey) && $r.isNotNull($usernamePosition) && $usernamePosition == "bottom") #if($r.isNotNull($username)) <tr class="o_prop o_username"> <th scope="row">$usernameLabel</th> diff --git a/src/main/java/org/olat/basesecurity/IdentityRelationshipService.java b/src/main/java/org/olat/basesecurity/IdentityRelationshipService.java index a5f3509c97c1208fe8be6d871288df9dd5a259c4..b774b17845c37760e56d16ae9bd75f180ce67acd 100644 --- a/src/main/java/org/olat/basesecurity/IdentityRelationshipService.java +++ b/src/main/java/org/olat/basesecurity/IdentityRelationshipService.java @@ -50,7 +50,9 @@ public interface IdentityRelationshipService { public List<RelationRight> getAvailableRights(); - public RelationRightProvider getRelationRightProvider(RelationRight right); + public RightProvider getRelationRightProvider(RelationRight right); + + public List<RightProvider> getAvailableRightProviders(); public boolean isInUse(RelationRole relationRole); diff --git a/src/main/java/org/olat/basesecurity/RelationRight.java b/src/main/java/org/olat/basesecurity/RelationRight.java index af49991d30e7bd2162ee7def96fa97ab432dbf32..e32720bf178c67ace549c230b1c0e36182ac4722 100644 --- a/src/main/java/org/olat/basesecurity/RelationRight.java +++ b/src/main/java/org/olat/basesecurity/RelationRight.java @@ -32,5 +32,4 @@ public interface RelationRight extends CreateInfo { public Long getKey(); public String getRight(); - } diff --git a/src/main/java/org/olat/basesecurity/manager/IdentityRelationshipServiceImpl.java b/src/main/java/org/olat/basesecurity/manager/IdentityRelationshipServiceImpl.java index d07057ee72293eec94fc18f6c79fd49cadb1d5d7..25ec20d6fd2120ff9f544683c2425a7c08c6c8a7 100644 --- a/src/main/java/org/olat/basesecurity/manager/IdentityRelationshipServiceImpl.java +++ b/src/main/java/org/olat/basesecurity/manager/IdentityRelationshipServiceImpl.java @@ -20,7 +20,10 @@ package org.olat.basesecurity.manager; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import javax.annotation.PostConstruct; @@ -29,7 +32,7 @@ import org.olat.basesecurity.IdentityRelationshipService; import org.olat.basesecurity.IdentityToIdentityRelation; import org.olat.basesecurity.IdentityToIdentityRelationManagedFlag; import org.olat.basesecurity.RelationRight; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.basesecurity.RelationRole; import org.olat.basesecurity.RelationRoleManagedFlag; import org.olat.basesecurity.RelationSearchParams; @@ -54,11 +57,11 @@ public class IdentityRelationshipServiceImpl implements IdentityRelationshipServ private IdentityToIdentityRelationDAO identityRelationshipDao; @Autowired - private List<RelationRightProvider> relationRightProviders; + private List<RightProvider> allRights; @PostConstruct void ensureRightsExists() { - for (RelationRightProvider relationRightProvider : relationRightProviders) { + for (RightProvider relationRightProvider : allRights) { relationRightDao.ensureRightExists(relationRightProvider.getRight()); } } @@ -70,7 +73,7 @@ public class IdentityRelationshipServiceImpl implements IdentityRelationshipServ @Override public RelationRole createRole(String role, List<RelationRight> rights) { - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); if(rights != null && !rights.isEmpty()) { relationRoleDao.setRights(relationRole, rights); } @@ -80,7 +83,7 @@ public class IdentityRelationshipServiceImpl implements IdentityRelationshipServ @Override public RelationRole createRole(String role, String externalId, String externalRef, RelationRoleManagedFlag[] managedFlags, List<RelationRight> rights) { - RelationRole relationRole = relationRoleDao.createRelationRole(role, externalId, externalRef, managedFlags); + RelationRole relationRole = relationRoleDao.createRelationRole(role, externalId, externalRef, managedFlags, true); if(rights != null && !rights.isEmpty()) { relationRoleDao.setRights(relationRole, rights); } @@ -112,12 +115,15 @@ public class IdentityRelationshipServiceImpl implements IdentityRelationshipServ @Override public List<RelationRight> getAvailableRights() { - return relationRightDao.loadRelationRights(); + List<RelationRight> relationRights = relationRightDao.loadRelationRights(); + List<String> relationRightStrings = allRights.stream().filter(RightProvider::isUserRelationsRight).map(RightProvider::getRight).collect(Collectors.toList()); + + return relationRights.stream().filter(right -> relationRightStrings.contains(right.getRight())).collect(Collectors.toList()); } @Override - public RelationRightProvider getRelationRightProvider(RelationRight right) { - for (RelationRightProvider provider : relationRightProviders) { + public RightProvider getRelationRightProvider(RelationRight right) { + for (RightProvider provider : allRights) { if (provider.getRight().equals(right.getRight())) { return provider; } @@ -125,6 +131,14 @@ public class IdentityRelationshipServiceImpl implements IdentityRelationshipServ return null; } + @Override + public List<RightProvider> getAvailableRightProviders() { + return getAvailableRights().stream().map(this::getRelationRightProvider) + .filter(Objects::nonNull) + .sorted(Comparator.comparing(RightProvider::getUserRelationsPosition)) + .collect(Collectors.toList()); + } + @Override public boolean isInUse(RelationRole relationRole) { return identityRelationshipDao.isUsed(relationRole); diff --git a/src/main/java/org/olat/basesecurity/manager/RelationRightDAO.java b/src/main/java/org/olat/basesecurity/manager/RelationRightDAO.java index 3736d0fb5d56b9826f28ba9b05bde719cd8d29cf..4ecb404be53b4a32676664291fc222d21dbbcf7e 100644 --- a/src/main/java/org/olat/basesecurity/manager/RelationRightDAO.java +++ b/src/main/java/org/olat/basesecurity/manager/RelationRightDAO.java @@ -89,5 +89,4 @@ public class RelationRightDAO { dbInstance.commitAndCloseSession(); } - } diff --git a/src/main/java/org/olat/basesecurity/manager/RelationRoleDAO.java b/src/main/java/org/olat/basesecurity/manager/RelationRoleDAO.java index 7deb2be55642570f76f6b06eeb739b792aefef9e..99728433f6b07dd02f388feae49ba9932d831011 100644 --- a/src/main/java/org/olat/basesecurity/manager/RelationRoleDAO.java +++ b/src/main/java/org/olat/basesecurity/manager/RelationRoleDAO.java @@ -47,7 +47,7 @@ public class RelationRoleDAO { @Autowired private DB dbInstance; - public RelationRole createRelationRole(String role, String externalId, String externalRef, RelationRoleManagedFlag[] flags) { + public RelationRole createRelationRole(String role, String externalId, String externalRef, RelationRoleManagedFlag[] flags, boolean userToUserRoleOnly) { RelationRoleImpl relationRole = new RelationRoleImpl(); relationRole.setCreationDate(new Date()); relationRole.setLastModified(relationRole.getCreationDate()); diff --git a/src/main/java/org/olat/course/certificate/CertificateEmailRightProvider.java b/src/main/java/org/olat/course/certificate/CertificateEmailRightProvider.java index 46d572f41b9334292e10a9a35ae56defa892108a..65e0c23ce36ef772776bd6eff34db3253ae3e9fa 100644 --- a/src/main/java/org/olat/course/certificate/CertificateEmailRightProvider.java +++ b/src/main/java/org/olat/course/certificate/CertificateEmailRightProvider.java @@ -19,9 +19,12 @@ */ package org.olat.course.certificate; +import java.util.Collection; +import java.util.Collections; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.OrganisationRoles; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.course.certificate.ui.CertificateController; @@ -34,7 +37,7 @@ import org.springframework.stereotype.Component; * */ @Component -public class CertificateEmailRightProvider implements RelationRightProvider { +public class CertificateEmailRightProvider implements RightProvider { public static final String RELATION_RIGHT = "certificateEmail"; @@ -44,13 +47,28 @@ public class CertificateEmailRightProvider implements RelationRightProvider { } @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.CertificateEmailRight.ordinal(); + public boolean isUserRelationsRight() { + return true; + } + + @Override + public int getUserRelationsPosition() { + return UserRelationRightsOrder.CertificateEmailRight.ordinal(); + } + + @Override + public Collection<OrganisationRoles> getOrganisationRoles() { + return Collections.emptyList(); + } + + @Override + public int getOrganisationPosition() { + return -1; } @Override diff --git a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java index 3835740f88578fadf23fac122ebb1d1ae6bbf53e..9802dd02c7b49b377e651f896a44baacbbc04074 100644 --- a/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java +++ b/src/main/java/org/olat/course/certificate/ui/CertificateAndEfficiencyStatementListController.java @@ -49,6 +49,7 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.gui.control.generic.modal.DialogBoxController; import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory; import org.olat.core.gui.render.Renderer; @@ -56,6 +57,8 @@ import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.id.Identity; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; import org.olat.core.util.coordinate.CoordinatorManager; @@ -87,14 +90,13 @@ import org.springframework.beans.factory.annotation.Autowired; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class CertificateAndEfficiencyStatementListController extends FormBasicController - implements BreadcrumbPanelAware, GenericEventListener { +public class CertificateAndEfficiencyStatementListController extends FormBasicController implements BreadcrumbPanelAware, GenericEventListener, Activateable2 { private static final String CMD_SHOW = "cmd.show"; private static final String CMD_LAUNCH_COURSE = "cmd.launch.course"; private static final String CMD_DELETE = "cmd.delete"; private static final String CMD_MEDIA = "cmd.MEDIA"; - + private FlexiTableElement tableEl; private BreadcrumbPanel stackPanel; private FormLink coachingToolButton; @@ -128,27 +130,35 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo this(ureq, wControl, ureq.getUserSession().getIdentity(), false, true, true); } - public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl, - Identity assessedIdentity, boolean linkToCoachingTool, boolean canModify, boolean canLaunchCourse) { + public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, boolean linkToCoachingTool, boolean canModify, boolean canLaunchCourse) { super(ureq, wControl, "cert_statement_list"); setTranslator(Util.createPackageTranslator(AssessmentModule.class, getLocale(), getTranslator())); this.canModify = canModify; this.assessedIdentity = assessedIdentity; this.linkToCoachingTool = linkToCoachingTool; this.canLaunchCourse = canLaunchCourse; + + // Show heading + flc.contextPut("showHeading", true); initForm(ureq); CoordinatorManager.getInstance().getCoordinator().getEventBus() .registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT); } + + public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, boolean linkToCoachingTool, boolean canModify, boolean canLaunchCourse, boolean showHeading) { + this(ureq, wControl, assessedIdentity, linkToCoachingTool, canModify, canLaunchCourse); + + // Set visibility of heading + flc.contextPut("showHeading", showHeading); + } - public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl, - Identity assessedIdentity, boolean useFieldSet) { - this(ureq, wControl, assessedIdentity, false, false, false); + public CertificateAndEfficiencyStatementListController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, boolean withFieldSet) { + this(ureq, wControl, assessedIdentity, false, false, true); - // Show different header in user relations - flc.contextPut("withFieldSet", useFieldSet); + // Show different header in user management + flc.contextPut("withFieldSet", withFieldSet); } @Override @@ -226,6 +236,7 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo loadModel(); tableEl = uifactory.addTableElement(getWindowControl(), "certificates", tableModel, getTranslator(), formLayout); tableEl.setElementCssClass("o_sel_certificates_table"); + tableEl.setEmtpyTableMessageKey("table.statements.empty"); } private void loadModel() { @@ -406,6 +417,11 @@ public class CertificateAndEfficiencyStatementListController extends FormBasicCo cmc.activate(); } + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + + } + public class AsArtefactCellRenderer implements FlexiCellRenderer { @Override diff --git a/src/main/java/org/olat/course/certificate/ui/_content/cert_statement_list.html b/src/main/java/org/olat/course/certificate/ui/_content/cert_statement_list.html index c8ef2cc50d0f533e13924899e9cf002c8c19f08b..9512505f70c5657fcd107471704248a54a970934 100644 --- a/src/main/java/org/olat/course/certificate/ui/_content/cert_statement_list.html +++ b/src/main/java/org/olat/course/certificate/ui/_content/cert_statement_list.html @@ -14,6 +14,8 @@ </fieldset> #else ## in users home -<h2 ><i class="o_icon o_icon o_icon-fw o_icon_certificate"> </i>$r.translate("certificates.and.statements.title")</h2> -$r.render("certificates") + #if($showHeading) + <h2 ><i class="o_icon o_icon o_icon-fw o_icon_certificate"> </i>$r.translate("certificates.and.statements.title")</h2> + #end + $r.render("certificates") #end diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties index 6110cbf6578423df74b493138bb2111b1610f825..f480834870a4a851f45c45d58ba85a08da5eb8c4 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_de.properties @@ -19,6 +19,7 @@ completion=$org.olat.modules.assessment.ui\:learning.progress confirm.delete.title=Zertifikate l\u00F6schen confirm.delete.text=Wollen Sie dieses Zertifikat wirklich l\u00F6schen? table.header.certificate=Zertifikat +table.statements.empty=Keine Leistungsnachweise oder Zertifikate vorhanden choose.title=Vorlage ausw\u00E4hlen default.template=Standardvorlage details.certificate=Zertifikat @@ -73,4 +74,4 @@ confirm.certificate.deleted=Das Zertifikat vom {0} wurde gel\u00F6scht. certificates.wizard.title=Zertifikate erstellen certificates.wizard.select=Benutzer ausw\u00E4hlen certificates.wizard.overview=\u00DCbersicht -msg.certificate.pending=Das Zertifikat wird in ein paar Sekunden erstellt. \ No newline at end of file +msg.certificate.pending=Das Zertifikat wird in ein paar Sekunden erstellt. diff --git a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties index 8af006992d2ee1ca797eba2daca4a13d9c7f92a0..3519f38d1ebda8a01e42c6d0e897e897beff2659 100644 --- a/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/certificate/ui/_i18n/LocalStrings_en.properties @@ -64,6 +64,7 @@ recertification.week=Week recertification.year=Year replace=Replace relation.right.email=Copy of certificates per E-Mail +table.statements.empty=No statements or certificates available table.header.certificate=Certificate template.file=File template.name=Name diff --git a/src/main/java/org/olat/course/groupsandrights/ViewCourseCalendarRightProvider.java b/src/main/java/org/olat/course/groupsandrights/ViewCourseCalendarRightProvider.java index f23efb1570e27608c0d36031a6666282631f5a44..d5eaffca4f0f21a5097c585c5c27dd5f078b46a1 100644 --- a/src/main/java/org/olat/course/groupsandrights/ViewCourseCalendarRightProvider.java +++ b/src/main/java/org/olat/course/groupsandrights/ViewCourseCalendarRightProvider.java @@ -21,7 +21,7 @@ package org.olat.course.groupsandrights; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.springframework.stereotype.Component; @@ -33,23 +33,33 @@ import org.springframework.stereotype.Component; * */ @Component -public class ViewCourseCalendarRightProvider implements RelationRightProvider { +public class ViewCourseCalendarRightProvider implements RightProvider { public static final String RELATION_RIGHT = CourseRightsEnum.viewCourseCalendar.name(); @Override - public RelationRightProvider getParent() { + public String getRight() { + return RELATION_RIGHT; + } + + @Override + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.ViewCourseCalendarRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ViewCourseCalendarRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ViewCourseCalendarRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/course/groupsandrights/ViewEfficiencyStatementRightProvider.java b/src/main/java/org/olat/course/groupsandrights/ViewEfficiencyStatementRightProvider.java index c96f32c705c26afda982160044e4d73fe841f9f2..93504300c22b0de3d83e7311d46187ea73084c53 100644 --- a/src/main/java/org/olat/course/groupsandrights/ViewEfficiencyStatementRightProvider.java +++ b/src/main/java/org/olat/course/groupsandrights/ViewEfficiencyStatementRightProvider.java @@ -21,7 +21,7 @@ package org.olat.course.groupsandrights; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.security.CoursesAndCurriculumRightProvider; @@ -35,7 +35,7 @@ import org.springframework.stereotype.Component; * */ @Component -public class ViewEfficiencyStatementRightProvider implements RelationRightProvider { +public class ViewEfficiencyStatementRightProvider implements RightProvider { @Autowired private CoursesAndCurriculumRightProvider parentRight; @@ -43,18 +43,28 @@ public class ViewEfficiencyStatementRightProvider implements RelationRightProvid public static final String RELATION_RIGHT = CourseRightsEnum.viewEfficiencyStatement.name(); @Override - public RelationRightProvider getParent() { + public String getRight() { + return RELATION_RIGHT; + } + + @Override + public RightProvider getParent() { return parentRight; } @Override - public int getPosition() { - return Order.ViewEfficiencyStatementRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ViewEfficiencyStatementRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ViewEfficiencyStatementRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/AdministrativePropertiesRightProvider.java b/src/main/java/org/olat/modules/coach/security/AdministrativePropertiesRightProvider.java index 6bfcc013a2d669abaed0c259d0a0d7ac4a6d4d20..d2c56b56ba0482a0b569176cafeb7fa20cc9e7e7 100644 --- a/src/main/java/org/olat/modules/coach/security/AdministrativePropertiesRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/AdministrativePropertiesRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,23 +32,33 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class AdministrativePropertiesRightProvider implements RelationRightProvider { +public class AdministrativePropertiesRightProvider implements RightProvider { public static final String RELATION_RIGHT = "showAdministrativeProperties"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.AdministrativePropertiesRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.AdministrativePropertiesRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.AdministrativePropertiesRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/ContactFormRightProvider.java b/src/main/java/org/olat/modules/coach/security/ContactFormRightProvider.java index 50bc0db872f5b8465b799d149a2fd2da5ed44c31..912c94ebdf3c65ecdd5bd78fa3b2b4a025deeca9 100644 --- a/src/main/java/org/olat/modules/coach/security/ContactFormRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/ContactFormRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,7 +32,7 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class ContactFormRightProvider implements RelationRightProvider { +public class ContactFormRightProvider implements RightProvider { public static final String RELATION_RIGHT = "showContactform"; @@ -42,13 +42,23 @@ public class ContactFormRightProvider implements RelationRightProvider { } @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.ContactFormRight.ordinal(); + public boolean isUserRelationsRight() { + return true; + } + + @Override + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ContactFormRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ContactFormRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/CourseProgressAndStatusRightProvider.java b/src/main/java/org/olat/modules/coach/security/CourseProgressAndStatusRightProvider.java index 4993acac66f01c5cd8c6399df64804df4e1d8d43..fcefcca2fcbc99261c1b35d0e4a5df9034624ff9 100644 --- a/src/main/java/org/olat/modules/coach/security/CourseProgressAndStatusRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/CourseProgressAndStatusRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -33,26 +33,36 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class CourseProgressAndStatusRightProvider implements RelationRightProvider { +public class CourseProgressAndStatusRightProvider implements RightProvider { @Autowired private CoursesAndCurriculumRightProvider parentRight; public static final String RELATION_RIGHT = "showCourseProgressAndStatus"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return parentRight; } - + @Override - public int getPosition() { - return Order.CourseProgressAndStatusRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.CourseProgressAndStatusRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.CourseProgressAndStatusRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/CoursesAndCurriculumRightProvider.java b/src/main/java/org/olat/modules/coach/security/CoursesAndCurriculumRightProvider.java index 7b82212fafbd4c71421a35924a3476bb2a1685ec..4e96510dc074febd10dc5f1b1079749ac59a4a38 100644 --- a/src/main/java/org/olat/modules/coach/security/CoursesAndCurriculumRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/CoursesAndCurriculumRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,23 +32,33 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class CoursesAndCurriculumRightProvider implements RelationRightProvider{ +public class CoursesAndCurriculumRightProvider implements RightProvider { public static final String RELATION_RIGHT = "showCoursesAndCurriculum"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.CourseAndCurriculumRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.CourseAndCurriculumRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.CourseAndCurriculumRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/LecturesAndAbsencesRightProvider.java b/src/main/java/org/olat/modules/coach/security/LecturesAndAbsencesRightProvider.java index 942b43b0be21c583a0953576b6871555405bc6a3..a353446e12d3380c9b910d4248ed4198402d6516 100644 --- a/src/main/java/org/olat/modules/coach/security/LecturesAndAbsencesRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/LecturesAndAbsencesRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -33,26 +33,36 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class LecturesAndAbsencesRightProvider implements RelationRightProvider { +public class LecturesAndAbsencesRightProvider implements RightProvider { @Autowired private CoursesAndCurriculumRightProvider parentRight; public static final String RELATION_RIGHT = "showLecturesAndAbsences"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return parentRight; } @Override - public int getPosition() { - return Order.LecturesAndAbsencesRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.LecturesAndAbsencesRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.LecturesAndAbsencesRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/ResetPasswordRightProvider.java b/src/main/java/org/olat/modules/coach/security/ResetPasswordRightProvider.java index fbb340f23a5882f5403f1833951c545fb2c08284..9b3beff8a8bc8e0db31518eab2b066ff0ae35fce 100644 --- a/src/main/java/org/olat/modules/coach/security/ResetPasswordRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/ResetPasswordRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,23 +32,33 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class ResetPasswordRightProvider implements RelationRightProvider { +public class ResetPasswordRightProvider implements RightProvider { public static final String RELATION_RIGHT = "resetPassword"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.ResetPasswordRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ResetPasswordRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ResetPasswordRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/ResourcesAndBookingsRightProvider.java b/src/main/java/org/olat/modules/coach/security/ResourcesAndBookingsRightProvider.java index 2ac034f4f5f6946770e04549fc8e7a4c3ce5cc54..7054393bcf996bb73ddf158e9546a703ac792494 100644 --- a/src/main/java/org/olat/modules/coach/security/ResourcesAndBookingsRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/ResourcesAndBookingsRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,23 +32,33 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class ResourcesAndBookingsRightProvider implements RelationRightProvider { +public class ResourcesAndBookingsRightProvider implements RightProvider { public static final String RELATION_RIGHT = "showResourcesAndBookings"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.ResourceAndBookinsRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ResourceAndBookinsRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ResourceAndBookinsRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/ViewAndEditProfileRightProvider.java b/src/main/java/org/olat/modules/coach/security/ViewAndEditProfileRightProvider.java index 14063d0a62e95f6d3167a8139f8f2e6117b299cc..58ea916e2f5a2d8d22ee113f3dc8c1ebea767fdb 100644 --- a/src/main/java/org/olat/modules/coach/security/ViewAndEditProfileRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/ViewAndEditProfileRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,23 +32,33 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class ViewAndEditProfileRightProvider implements RelationRightProvider { +public class ViewAndEditProfileRightProvider implements RightProvider { public static final String RELATION_RIGHT = "viewAndEditProfile"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.ViewAndEditProfileRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ViewAndEditProfileRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ViewAndEditProfileRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/security/ViewGroupMembershipsRightProvider.java b/src/main/java/org/olat/modules/coach/security/ViewGroupMembershipsRightProvider.java index ce83521b542f9a1c53f04902917e86eb4bd6e14c..da596d594508b4ed28880cb773df261058ee8dc7 100644 --- a/src/main/java/org/olat/modules/coach/security/ViewGroupMembershipsRightProvider.java +++ b/src/main/java/org/olat/modules/coach/security/ViewGroupMembershipsRightProvider.java @@ -21,7 +21,7 @@ package org.olat.modules.coach.security; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.coach.ui.CoachMainController; @@ -32,23 +32,33 @@ import org.springframework.stereotype.Component; * @author aboeckle, alexander.boeckle@frentix.com */ @Component -public class ViewGroupMembershipsRightProvider implements RelationRightProvider { +public class ViewGroupMembershipsRightProvider implements RightProvider { public static final String RELATION_RIGHT = "showGroupMemberships"; - + + @Override + public String getRight() { + return RELATION_RIGHT; + } + @Override - public RelationRightProvider getParent() { + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.ViewGroupMemebershipsRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.ViewGroupMemebershipsRight.ordinal(); + } + + @Override + public int getOrganisationPosition() { + return OrganisationRightsOrder.ViewGroupMemebershipsRight.ordinal(); } @Override diff --git a/src/main/java/org/olat/modules/coach/ui/CoachMainController.java b/src/main/java/org/olat/modules/coach/ui/CoachMainController.java index 3625992e411720f7879e0546eb48feb2dee080a9..4c1dcfe18705f6778a177b09068aa56c070ce96d 100644 --- a/src/main/java/org/olat/modules/coach/ui/CoachMainController.java +++ b/src/main/java/org/olat/modules/coach/ui/CoachMainController.java @@ -19,17 +19,24 @@ */ package org.olat.modules.coach.ui; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import org.olat.admin.privacy.PrivacyAdminController; import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.IdentityRelationshipService; import org.olat.basesecurity.IdentityToIdentityRelation; +import org.olat.basesecurity.OrganisationModule; +import org.olat.basesecurity.OrganisationRoles; +import org.olat.basesecurity.OrganisationService; import org.olat.basesecurity.RelationRole; import org.olat.core.commons.fullWebApp.LayoutMain3ColsController; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.stack.PopEvent; import org.olat.core.gui.components.stack.TooledStackedPanel; import org.olat.core.gui.components.tree.GenericTreeModel; import org.olat.core.gui.components.tree.GenericTreeNode; @@ -42,11 +49,13 @@ import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.MainLayoutBasicController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.OLATResourceable; +import org.olat.core.id.Organisation; import org.olat.core.id.Roles; import org.olat.core.id.context.BusinessControlFactory; import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; +import org.olat.core.util.Util; import org.olat.core.util.nodes.INode; import org.olat.core.util.resource.OresHelper; import org.olat.core.util.tree.TreeHelper; @@ -80,6 +89,7 @@ public class CoachMainController extends MainLayoutBasicController implements Ac private final TooledStackedPanel content; private final boolean userSearchAllowed; + private final boolean showLineManagerView; private final GradingSecurity gradingSec; private final CoachingSecurity coachingSec; @@ -93,6 +103,8 @@ public class CoachMainController extends MainLayoutBasicController implements Ac private LecturesCoachingController lecturesMasterCoachCtrl; private Map<String, RelationRole> userRelationRolesMap; + private Map<String, Organisation> organisationMap; + private List<Organisation> organisations; @Autowired private GradingModule gradingModule; @@ -102,15 +114,26 @@ public class CoachMainController extends MainLayoutBasicController implements Ac private BaseSecurityModule securityModule; @Autowired private IdentityRelationshipService identityRelationsService; + @Autowired + private OrganisationService organisationService; + @Autowired + private OrganisationModule organisationModule; public CoachMainController(UserRequest ureq, WindowControl control, CoachingSecurity coachingSec, GradingSecurity gradingSec) { super(ureq, control); + setTranslator(Util.createPackageTranslator(PrivacyAdminController.class, getLocale(), getTranslator())); + this.gradingSec = gradingSec; this.coachingSec = coachingSec; this.userRelationRolesMap = listAvailableRoles(identityRelationsService.getRelationsAsSource(ureq.getIdentity())); Roles roles = ureq.getUserSession().getRoles(); userSearchAllowed = roles.isAdministrator() || roles.isLearnResourceManager() || roles.isPrincipal(); + showLineManagerView = organisationModule.isEnabled() && roles.isLineManager(); + if (showLineManagerView) { + organisations = organisationService.getOrganisations(getIdentity(), OrganisationRoles.linemanager); + organisationMap = organisations.stream().collect(Collectors.toMap(org -> org.getKey().toString(), org -> org)); + } menu = new MenuTree(null, "coachMenu", this); menu.setExpandSelectedNode(false); @@ -141,17 +164,45 @@ public class CoachMainController extends MainLayoutBasicController implements Ac if (event.getCommand().equals(MenuTree.COMMAND_TREENODE_CLICKED)) { TreeNode selTreeNode = menu.getSelectedNode(); - if (selTreeNode.getDelegate() != null) { - String cmd = (String) selTreeNode.getDelegate().getUserObject(); - selectMenuItem(ureq,cmd); - } else if (selTreeNode.getUserObject() instanceof String) { - String cmd = (String)selTreeNode.getUserObject(); - selectMenuItem(ureq, cmd); + selectMenuItem(ureq, selTreeNode); + } + } else if (source == content) { + if (event instanceof PopEvent) { + PopEvent popEvent = (PopEvent) event; + + if (popEvent.getController() instanceof AbstactCoachListController) { + TreeNode selTreeNode = menu.getSelectedNode(); + selectMenuItem(ureq, selTreeNode); + if (selTreeNode.getUserObject() instanceof Organisation) { + selectMenuItem(ureq, selTreeNode); + } else if (selTreeNode.getUserObject() instanceof RelationRole) { + selectMenuItem(ureq, selTreeNode); + } } } } } + private Activateable2 selectMenuItem(UserRequest ureq, TreeNode treeNode) { + if (treeNode.getDelegate() != null) { + return selectMenuItem(ureq, treeNode.getDelegate()); + } else if (treeNode.getUserObject() instanceof String) { + String cmd = (String) treeNode.getUserObject(); + return selectMenuItem(ureq, cmd); + } else if (treeNode.getUserObject() instanceof Long) { + Long cmd = (Long) treeNode.getUserObject(); + return selectMenuItem(ureq, treeNode.toString()); + } else if (treeNode.getUserObject() instanceof Organisation) { + Organisation organisation = (Organisation) treeNode.getUserObject(); + return selectMenuItem(ureq, organisation); + } else if (treeNode.getUserObject() instanceof RelationRole) { + RelationRole relationRole = (RelationRole) treeNode.getUserObject(); + return selectMenuItem(ureq, relationRole); + } + + return null; + } + @Override protected void doDispose() { // @@ -196,6 +247,9 @@ public class CoachMainController extends MainLayoutBasicController implements Ac if (coachingSec.isUserRelationSource()) { return userRelationRolesMap.keySet().stream().findFirst().get(); } + if (organisationModule.isEnabled()) { + return organisationMap.keySet().stream().findFirst().get(); + } return "Members"; } @@ -267,16 +321,7 @@ public class CoachMainController extends MainLayoutBasicController implements Ac listenTo(gradingCtrl); } selectedCtrl = gradingCtrl; - } else if(userRelationRolesMap.containsKey(cmd) && securityModule.isRelationRoleEnabled()) { - OLATResourceable ores = OresHelper.createOLATResourceableInstance(cmd, 0l); - ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); - WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); - UserRelationListController userRelationsListController = new UserRelationListController(ureq, bwControl, content, userRelationRolesMap.get(cmd)); - listenTo(userRelationsListController); - - selectedCtrl = userRelationsListController; } - if(selectedCtrl != null) { String title = "Root"; TreeNode selTreeNode = TreeHelper.findNodeByUserObject(cmd, menu.getTreeModel().getRootNode()); @@ -287,11 +332,72 @@ public class CoachMainController extends MainLayoutBasicController implements Ac } } content.rootController(title, selectedCtrl); + content.setInvisibleCrumb(1); addToHistory(ureq, selectedCtrl); } return (Activateable2)selectedCtrl; } + private Activateable2 selectMenuItem(UserRequest ureq, Organisation organisation) { + Controller selectedController = null; + + if (organisationModule.isEnabled()) { + OLATResourceable ores = OresHelper.createOLATResourceableInstance("Organisation", organisation.getKey()); + ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); + AbstactCoachListController organisationListController = new OrganisationListController(ureq, bwControl, content, organisation, OrganisationRoles.linemanager); + listenTo(organisationListController); + + String rootTitle = translate("admin.props.linemanagers"); + String title = "Organisation"; + TreeNode selTreeNode = TreeHelper.findNodeByUserObject(organisation, menu.getTreeModel().getRootNode()); + if (selTreeNode != null) { + title = selTreeNode.getTitle(); + if (!selTreeNode.getIdent().equals(menu.getSelectedNodeId())) { + menu.setSelectedNodeId(selTreeNode.getIdent()); + } + } + content.rootController(rootTitle, null); + content.pushController(title, null, organisationListController); + content.setInvisibleCrumb(0); + addToHistory(ureq, organisationListController); + + selectedController = organisationListController; + } + + return (Activateable2) selectedController; + } + + private Activateable2 selectMenuItem(UserRequest ureq, RelationRole relationRole) { + Controller selectedController = null; + + if (securityModule.isRelationRoleEnabled()) { + OLATResourceable ores = OresHelper.createOLATResourceableInstance("Relations", relationRole.getKey()); + ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores)); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); + AbstactCoachListController userRelationsListController = new UserRelationListController(ureq, bwControl, content, relationRole); + listenTo(userRelationsListController); + + String rootTitle = translate("relations.menu.title"); + String title = "Relation"; + TreeNode selTreeNode = TreeHelper.findNodeByUserObject(relationRole, menu.getTreeModel().getRootNode()); + if (selTreeNode != null) { + title = selTreeNode.getTitle(); + if (!selTreeNode.getIdent().equals(menu.getSelectedNodeId())) { + menu.setSelectedNodeId(selTreeNode.getIdent()); + } + } + content.rootController(rootTitle, null); + content.pushController(title, null, userRelationsListController); + content.setInvisibleCrumb(0); + addToHistory(ureq, userRelationsListController); + + selectedController = userRelationsListController; + } + + return (Activateable2) selectedController; + } + private TreeModel buildTreeModel() { GenericTreeModel gtm = new GenericTreeModel(); GenericTreeNode root = new GenericTreeNode(); @@ -334,16 +440,17 @@ public class CoachMainController extends MainLayoutBasicController implements Ac root.addChild(courses); } + // Add user relations // Add menu entry with sub entries if (isUserRelationAvailable() == 2) { GenericTreeNode relations = new GenericTreeNode(); - relations.setUserObject("UserRelationsNode"); + relations.setUserObject("Relations"); relations.setTitle(translate("relations.menu.title")); relations.setAltText("relations.menu.title"); for (RelationRole relationRole : userRelationRolesMap.values()) { GenericTreeNode relationRoleNode = new GenericTreeNode(); - relationRoleNode.setUserObject(relationRole.getRole()); + relationRoleNode.setUserObject(relationRole); relationRoleNode.setTitle(RelationRolesAndRightsUIFactory.getTranslatedContraRole(relationRole, getLocale())); relationRoleNode.setAltText(RelationRolesAndRightsUIFactory.getTranslatedContraDescription(relationRole, getLocale())); relations.addChild(relationRoleNode); @@ -356,13 +463,50 @@ public class CoachMainController extends MainLayoutBasicController implements Ac else if (isUserRelationAvailable() == 1) { for (RelationRole relationRole : userRelationRolesMap.values()) { GenericTreeNode relationRoleNode = new GenericTreeNode(); - relationRoleNode.setUserObject(relationRole.getRole()); + relationRoleNode.setUserObject(relationRole); relationRoleNode.setTitle(RelationRolesAndRightsUIFactory.getTranslatedContraRole(relationRole, getLocale())); relationRoleNode.setAltText(RelationRolesAndRightsUIFactory.getTranslatedContraDescription(relationRole, getLocale())); root.addChild(relationRoleNode); } } + // Add line manager view + // Add menu entry with sub entries + if (isLineManagerViewAvailable() == 2) { + GenericTreeNode organisationsNode = new GenericTreeNode(); + organisationsNode.setUserObject("Organisations"); + organisationsNode.setTitle(translate("line.manager.title")); + organisationsNode.setAltText(translate("line.manager.title")); + + List<Organisation> topLevelOrganisations = new ArrayList<>(); + + for (Organisation organisation : organisations) { + if (organisation.getParent() == null && !topLevelOrganisations.contains(organisation)) { + topLevelOrganisations.add(organisation); + } else if (!organisations.contains(organisation.getParent())){ + topLevelOrganisations.add(organisation); + } + } + + if (!topLevelOrganisations.isEmpty()) { + for (Organisation topLevelOrganisation : topLevelOrganisations) { + addOrganisationToTree(topLevelOrganisation, organisationsNode); + } + + setFirstChildAsDelegate(organisationsNode); + root.addChild(organisationsNode); + } + } + // Add only one main entry + else if (isLineManagerViewAvailable() == 1) { + GenericTreeNode organisationsNode = new GenericTreeNode(); + organisationsNode.setUserObject(organisations.get(0)); + organisationsNode.setTitle(translate(organisations.get(0).getDisplayName())); + organisationsNode.setAltText(translate(organisations.get(0).getDisplayName())); + + root.addChild(organisationsNode); + } + if(gradingModule.isEnabled() && (gradingSec.isGrader() || gradingSec.isGradedResourcesManager())) { GenericTreeNode courses = new GenericTreeNode(); courses.setUserObject("Grading"); @@ -381,6 +525,21 @@ public class CoachMainController extends MainLayoutBasicController implements Ac return gtm; } + private void addOrganisationToTree(Organisation organisation, GenericTreeNode parentNode) { + GenericTreeNode organisationNode = new GenericTreeNode(); + organisationNode.setUserObject(organisation); + organisationNode.setTitle(organisation.getDisplayName()); + organisationNode.setAltText(organisation.getDisplayName()); + + if (!organisation.getChildren().isEmpty()) { + for (Organisation child : organisation.getChildren()) { + addOrganisationToTree(child, organisationNode); + } + } + + parentNode.addChild(organisationNode); + } + /** * Returns 0 if nothing is available * Returns 1 if exactly one role is available @@ -399,6 +558,25 @@ public class CoachMainController extends MainLayoutBasicController implements Ac return 0; } + /** + * Returns 0 if nothing is available + * Returns 1 if exactly one organisation is available + * Returns 2 if more than one organisation is available + * + * @return + */ + private int isLineManagerViewAvailable() { + if (showLineManagerView) { + if (organisations.size() > 1) { + return 2; + } else if (organisations.size() > 0) { + return 1; + } + } + + return 0; + } + /** * Returns different roles for a given list of relations * diff --git a/src/main/java/org/olat/modules/coach/ui/UserRelationEnrollmentListController.java b/src/main/java/org/olat/modules/coach/ui/EnrollmentListController.java similarity index 91% rename from src/main/java/org/olat/modules/coach/ui/UserRelationEnrollmentListController.java rename to src/main/java/org/olat/modules/coach/ui/EnrollmentListController.java index 58e959e00daf05eea573afe509e9cdc1c5c2380a..1178fbfe13ecf2300b41d0a138ab500885e5b6f9 100644 --- a/src/main/java/org/olat/modules/coach/ui/UserRelationEnrollmentListController.java +++ b/src/main/java/org/olat/modules/coach/ui/EnrollmentListController.java @@ -62,7 +62,7 @@ import org.olat.modules.assessment.ui.ScoreCellRenderer; import org.olat.modules.assessment.ui.component.LearningProgressCompletionCellRenderer; import org.olat.modules.co.ContactFormController; import org.olat.modules.coach.CoachingService; -import org.olat.modules.coach.UserRelationSecurityCallback; +import org.olat.modules.coach.RoleSecurityCallback; import org.olat.modules.coach.model.EfficiencyStatementEntry; import org.olat.modules.coach.model.IdentityRepositoryEntryKey; import org.olat.modules.coach.model.IdentityResourceKey; @@ -87,12 +87,12 @@ import org.springframework.beans.factory.annotation.Autowired; * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class UserRelationEnrollmentListController extends FormBasicController implements Activateable2, GenericEventListener { +public class EnrollmentListController extends FormBasicController implements Activateable2, GenericEventListener { private final TooledStackedPanel stackedPanel; private final Identity student; private final StudentStatEntry statEntry; - private final UserRelationSecurityCallback userRelationSecurityCallback; + private final RoleSecurityCallback roleSecurityCallback; private final List<UserPropertyHandler> userPropertyHandlers; @@ -120,8 +120,8 @@ public class UserRelationEnrollmentListController extends FormBasicController im @Autowired private AssessmentService assessmentService; - public UserRelationEnrollmentListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackedPanel, - StudentStatEntry statEntry, Identity student, UserRelationSecurityCallback userRelationSecurityCallback) { + public EnrollmentListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackedPanel, + StudentStatEntry statEntry, Identity student, RoleSecurityCallback roleSecurityCallback) { super(ureq, wControl, "user_relation_enrollments"); setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); @@ -131,7 +131,7 @@ public class UserRelationEnrollmentListController extends FormBasicController im this.student = student; this.statEntry = statEntry; this.stackedPanel = stackedPanel; - this.userRelationSecurityCallback = userRelationSecurityCallback; + this.roleSecurityCallback = roleSecurityCallback; initForm(ureq); loadModel(); @@ -144,32 +144,25 @@ public class UserRelationEnrollmentListController extends FormBasicController im protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { // Add the table FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); - - int colIndex = UserListController.USER_PROPS_OFFSET; - for (int i = 0; i < userPropertyHandlers.size(); i++) { - UserPropertyHandler userPropertyHandler = userPropertyHandlers.get(i); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", - true, userPropertyHandler.i18nColumnDescriptorLabelKey())); - } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.repoName, "select")); - if (userRelationSecurityCallback.canViewCourseProgressAndStatus()) { + if (roleSecurityCallback.canViewCourseProgressAndStatus()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.completion, new LearningProgressCompletionCellRenderer())); } - if (userRelationSecurityCallback.canViewEfficiencyStatements()) { + if (roleSecurityCallback.canViewEfficiencyStatements()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.passed, new PassedCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.score, new ScoreCellRenderer())); } - if (userRelationSecurityCallback.canReceiveCertificatesMail()) { + if (roleSecurityCallback.canReceiveCertificatesMail()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.certificate, new DownloadCertificateCellRenderer(getLocale()))); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.recertification, new DateFlexiCellRenderer(getLocale()))); } - if (userRelationSecurityCallback.canViewEfficiencyStatements()) { + if (roleSecurityCallback.canViewEfficiencyStatements()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.numberAssessments, new ProgressOfCellRenderer())); } if(lectureModule.isEnabled()) { - if (userRelationSecurityCallback.canViewLecturesAndAbsences()) { + if (roleSecurityCallback.canViewLecturesAndAbsences()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.plannedLectures)); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.attendedLectures)); if (lectureModule.isAuthorizedAbsenceEnabled()) { diff --git a/src/main/java/org/olat/modules/coach/ui/UserRelationOverviewController.java b/src/main/java/org/olat/modules/coach/ui/UserOverviewController.java similarity index 86% rename from src/main/java/org/olat/modules/coach/ui/UserRelationOverviewController.java rename to src/main/java/org/olat/modules/coach/ui/UserOverviewController.java index 39ca41f590d1ab827eac424eb2b0dd601a1d7d56..aa4e09a2c21e4acd0fda3ad84279d327da2ef2be 100644 --- a/src/main/java/org/olat/modules/coach/ui/UserRelationOverviewController.java +++ b/src/main/java/org/olat/modules/coach/ui/UserOverviewController.java @@ -26,7 +26,6 @@ import org.olat.admin.user.UserChangePasswordController; import org.olat.admin.user.UserShortDescription; import org.olat.admin.user.groups.GroupOverviewController; import org.olat.basesecurity.BaseSecurityManager; -import org.olat.basesecurity.RelationRole; import org.olat.commons.calendar.CalendarManager; import org.olat.commons.calendar.model.CalendarUserConfiguration; import org.olat.commons.calendar.ui.CalendarController; @@ -63,9 +62,10 @@ import org.olat.core.util.resource.OresHelper; import org.olat.course.certificate.CertificatesManager; import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListController; import org.olat.modules.co.ContactFormController; -import org.olat.modules.coach.UserRelationSecurityCallback; +import org.olat.modules.coach.RoleSecurityCallback; import org.olat.modules.coach.model.StudentStatEntry; -import org.olat.modules.coach.ui.curriculum.CourseListWrapperController; +import org.olat.modules.coach.ui.curriculum.certificate.CertificateAndEfficiencyStatementWrapperController; +import org.olat.modules.coach.ui.curriculum.course.CourseListWrapperController; import org.olat.modules.curriculum.CurriculumRef; import org.olat.modules.curriculum.CurriculumSecurityCallback; import org.olat.modules.curriculum.CurriculumSecurityCallbackFactory; @@ -79,7 +79,6 @@ import org.olat.user.HomePageConfigManager; import org.olat.user.HomePageDisplayController; import org.olat.user.ProfileAndHomePageEditController; import org.olat.user.UserManager; -import org.olat.user.ui.role.RelationRolesAndRightsUIFactory; import org.springframework.beans.factory.annotation.Autowired; /** @@ -89,9 +88,9 @@ import org.springframework.beans.factory.annotation.Autowired; * * @author aboeckle, alexander.boeckle@frentix.com, http://www.frentix.com */ -public class UserRelationOverviewController extends BasicController implements Activateable2, GenericEventListener, TooledController { +public class UserOverviewController extends BasicController implements Activateable2, GenericEventListener, TooledController { - public static final String usageIdentifier = UserRelationOverviewController.class.getCanonicalName(); + public static final String usageIdentifier = UserOverviewController.class.getCanonicalName(); private static final String CMD_CALENDAR = "Calendar"; private static final String CMD_BOOKINGS = "Bookings"; @@ -130,6 +129,7 @@ public class UserRelationOverviewController extends BasicController implements A private CertificateAndEfficiencyStatementListController efficiencyStatementListController; private WeeklyCalendarController calendarController; private CourseListWrapperController courseListWrapperController; + private CertificateAndEfficiencyStatementWrapperController certificateAndEfficiencyStatementWrapperController; private TabbedPane functionsTabbedPane; @@ -137,9 +137,9 @@ public class UserRelationOverviewController extends BasicController implements A private final int numOfStudents; private final Identity mentee; private final StudentStatEntry statEntry; - private final RelationRole relationRole; + private final String role; - private final UserRelationSecurityCallback userRelationSecurityCallback; + private final RoleSecurityCallback roleSecurityCallback; @Autowired private UserManager userManager; @@ -154,8 +154,8 @@ public class UserRelationOverviewController extends BasicController implements A @Autowired private CurriculumService curriculumService; - public UserRelationOverviewController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, - StudentStatEntry statEntry, Identity mentee, int index, int numOfStudents, RelationRole relationRole, UserRelationSecurityCallback userRelationSecurityCallback) { + public UserOverviewController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, + StudentStatEntry statEntry, Identity mentee, int index, int numOfStudents, String role, RoleSecurityCallback roleSecurityCallback) { super(ureq, wControl); setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); @@ -164,8 +164,8 @@ public class UserRelationOverviewController extends BasicController implements A this.statEntry = statEntry; this.stackPanel = stackPanel; this.numOfStudents = numOfStudents; - this.userRelationSecurityCallback = userRelationSecurityCallback; - this.relationRole = relationRole; + this.roleSecurityCallback = roleSecurityCallback; + this.role = role; mainVC = createVelocityContainer("user_relation_overview"); @@ -177,7 +177,7 @@ public class UserRelationOverviewController extends BasicController implements A @Override public void initTools() { - if (userRelationSecurityCallback.canContact()) { + if (roleSecurityCallback.canContact()) { contactLink = LinkFactory.createToolLink("contact.link", translate("contact.link"), this); contactLink.setIconLeftCSS("o_icon o_icon_mail"); stackPanel.addTool(contactLink, Align.left, true); @@ -187,7 +187,7 @@ public class UserRelationOverviewController extends BasicController implements A homeLink.setIconLeftCSS("o_icon o_icon_home"); stackPanel.addTool(homeLink, Align.left, true); - if (userRelationSecurityCallback.canResetPassword()) { + if (roleSecurityCallback.canResetPassword()) { Roles roles = securityManager.getRoles(mentee); if (!(roles.isAuthor() || roles.isManager() || roles.isAdministrator() || roles.isSystemAdmin() || roles.isPrincipal())) { resetLink = LinkFactory.createToolLink("reset.link", translate("reset.link"), this); @@ -219,7 +219,7 @@ public class UserRelationOverviewController extends BasicController implements A private void initUserDetails(UserRequest ureq, Identity identity) { // Add user's name and relation StringBuilder relationAndName = new StringBuilder(256); - relationAndName.append(RelationRolesAndRightsUIFactory.getTranslatedContraRole(relationRole, getLocale())).append(" "); + relationAndName.append(role != null ? role + " " : ""); relationAndName.append(mentee.getUser().getFirstName()).append(" "); relationAndName.append(mentee.getUser().getLastName()); mainVC.contextPut("relationAndName", relationAndName); @@ -237,7 +237,7 @@ public class UserRelationOverviewController extends BasicController implements A userDetails.put("portrait", displayPortraitController.getInitialComponent()); removeAsListenerAndDispose(userShortDescriptionController); - userShortDescriptionController = new UserShortDescription(ureq, getWindowControl(), identity, userRelationSecurityCallback.isAdministrativeUser()); + userShortDescriptionController = new UserShortDescription(ureq, getWindowControl(), identity, roleSecurityCallback.isAdministrativeUser()); userDetails.put("userShortDescription", userShortDescriptionController.getInitialComponent()); } @@ -247,19 +247,19 @@ public class UserRelationOverviewController extends BasicController implements A functionsTabbedPane = new TabbedPane("functionsTabbedPane", ureq.getLocale()); functionsTabbedPane.addListener(this); - if (userRelationSecurityCallback.canViewCoursesAndCurriculum()) { + if (roleSecurityCallback.canViewCoursesAndCurriculum()) { List<CurriculumRef> curriculumRefs = curriculumService.getMyActiveCurriculumRefs(mentee); CurriculumSecurityCallback curriculumSecurityCallback = CurriculumSecurityCallbackFactory.createDefaultCallback(); courseTabIndex = functionsTabbedPane.addTabControllerCreator(ureq, translate("enrollments"), uureq -> { WindowControl bwControl = addToHistory(uureq, OresHelper.createOLATResourceableType(CMD_ENROLLMENTS), null); - courseListWrapperController = new CourseListWrapperController(uureq, bwControl, stackPanel, mentee, curriculumSecurityCallback, userRelationSecurityCallback, curriculumRefs, statEntry); + courseListWrapperController = new CourseListWrapperController(uureq, bwControl, stackPanel, mentee, curriculumSecurityCallback, roleSecurityCallback, curriculumRefs, statEntry); listenTo(courseListWrapperController); return courseListWrapperController; }); } - if (userRelationSecurityCallback.canViewResourcesAndBookings()) { + if (roleSecurityCallback.canViewResourcesAndBookings()) { orderTabIndex = functionsTabbedPane.addTabControllerCreator(ureq, translate("bookings"), uureq -> { WindowControl bwControl = addToHistory(uureq, OresHelper.createOLATResourceableType(CMD_BOOKINGS), null); userOrderController = new UserOrderController(uureq, bwControl, mentee); @@ -268,7 +268,7 @@ public class UserRelationOverviewController extends BasicController implements A }); } - if (lectureModule.isEnabled() && userRelationSecurityCallback.canViewLecturesAndAbsences()) { + if (lectureModule.isEnabled() && roleSecurityCallback.canViewLecturesAndAbsences()) { lecturesTabIndex = functionsTabbedPane.addTabControllerCreator(ureq, translate("lectures"), uureq -> { WindowControl bwControl = addToHistory(uureq, OresHelper.createOLATResourceableType(CMD_LECTURES), null); lecturesController = new ParticipantLecturesOverviewController(uureq, bwControl, mentee, null, true, true, true, true, false, true); @@ -278,17 +278,19 @@ public class UserRelationOverviewController extends BasicController implements A }); } - if (userRelationSecurityCallback.canViewEfficiencyStatements()) { + if (roleSecurityCallback.canViewEfficiencyStatements()) { + List<CurriculumRef> curriculumRefs = curriculumService.getMyActiveCurriculumRefs(mentee); + CurriculumSecurityCallback curriculumSecurityCallback = CurriculumSecurityCallbackFactory.createDefaultCallback(); + certificatesTabIndex = functionsTabbedPane.addTabControllerCreator(ureq, translate("statements"), uureq -> { WindowControl bwControl = addToHistory(uureq, OresHelper.createOLATResourceableType(CMD_STATEMENTS), null); - efficiencyStatementListController = new CertificateAndEfficiencyStatementListController(ureq, bwControl, mentee, true); - efficiencyStatementListController.setBreadcrumbPanel(stackPanel); - listenTo(efficiencyStatementListController); - return efficiencyStatementListController; + certificateAndEfficiencyStatementWrapperController = new CertificateAndEfficiencyStatementWrapperController(uureq, bwControl, stackPanel, mentee, curriculumSecurityCallback, roleSecurityCallback, curriculumRefs, statEntry); + listenTo(certificateAndEfficiencyStatementWrapperController); + return certificateAndEfficiencyStatementWrapperController; }); } - if (userRelationSecurityCallback.canViewGroupMemberships()) { + if (roleSecurityCallback.canViewGroupMemberships()) { groupTabIndex = functionsTabbedPane.addTab(ureq, translate("groups.menu.title"), uureq -> { WindowControl bwControl = addToHistory(uureq, OresHelper.createOLATResourceableType(CMD_GROUPS), null); groupOverviewController = new GroupOverviewController(ureq, bwControl, mentee, false, false); @@ -297,14 +299,14 @@ public class UserRelationOverviewController extends BasicController implements A }); } - if (userRelationSecurityCallback.canViewCalendar()) { + if (roleSecurityCallback.canViewCalendar()) { calendarTabIndex = functionsTabbedPane.addTab(ureq, translate("calendar"), uureq -> doOpenCalendar(uureq).getInitialComponent()); } - if (userRelationSecurityCallback.canViewAndEditProfile()) { + if (roleSecurityCallback.canViewAndEditProfile()) { profileTabIndex = functionsTabbedPane.addTab(ureq, translate("profile"), uureq -> { WindowControl bwControl = addToHistory(uureq, OresHelper.createOLATResourceableType(CMD_PROFILE), null); - profileAndHomePageEditController = new ProfileAndHomePageEditController(ureq, bwControl, mentee, userRelationSecurityCallback.isAdministrativeUser()); + profileAndHomePageEditController = new ProfileAndHomePageEditController(ureq, bwControl, mentee, roleSecurityCallback.isAdministrativeUser()); listenTo(profileAndHomePageEditController); return profileAndHomePageEditController.getInitialComponent(); }); @@ -398,6 +400,9 @@ public class UserRelationOverviewController extends BasicController implements A } } else if(CMD_STATEMENTS.equalsIgnoreCase(type) && certificatesTabIndex >= 0) { functionsTabbedPane.setSelectedPane(ureq, certificatesTabIndex); + if (certificateAndEfficiencyStatementWrapperController != null) { + certificateAndEfficiencyStatementWrapperController.activate(ureq, entries.subList(1, entries.size()), null); + } } else if(CMD_GROUPS.equalsIgnoreCase(type) && groupTabIndex >= 0) { functionsTabbedPane.setSelectedPane(ureq, groupTabIndex); } else if(CMD_PROFILE.equalsIgnoreCase(type) && profileTabIndex >= 0) { @@ -432,12 +437,14 @@ public class UserRelationOverviewController extends BasicController implements A } private void openHome(UserRequest ureq) { - HomePageConfig homePageConfig = homePageConfigManager.loadConfigFor(mentee); - removeAsListenerAndDispose(homePageDisplayController); - homePageDisplayController = new HomePageDisplayController(ureq, getWindowControl(), mentee, homePageConfig); - listenTo(homePageDisplayController); + if (stackPanel.getLastController() != homePageDisplayController) { + HomePageConfig homePageConfig = homePageConfigManager.loadConfigFor(mentee); + removeAsListenerAndDispose(homePageDisplayController); + homePageDisplayController = new HomePageDisplayController(ureq, getWindowControl(), mentee, homePageConfig); + listenTo(homePageDisplayController); - stackPanel.pushController("Visiting card", homePageDisplayController); + stackPanel.pushController("Visiting card", homePageDisplayController); + } } private WeeklyCalendarController doOpenCalendar(UserRequest ureq) { diff --git a/src/main/java/org/olat/modules/coach/ui/UserRelationListController.java b/src/main/java/org/olat/modules/coach/ui/UserRelationListController.java index f8abfec6e0f511ab860a6b0d52342e66b97cfaf3..f6d2808df1fbc8fc1aed9e801611c58ee11f1525 100644 --- a/src/main/java/org/olat/modules/coach/ui/UserRelationListController.java +++ b/src/main/java/org/olat/modules/coach/ui/UserRelationListController.java @@ -21,244 +21,62 @@ package org.olat.modules.coach.ui; import java.util.List; -import org.olat.basesecurity.BaseSecurity; -import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.IdentityRelationshipService; import org.olat.basesecurity.RelationRole; import org.olat.core.gui.UserRequest; -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.form.flexible.FormItem; -import org.olat.core.gui.components.form.flexible.FormItemContainer; -import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; -import org.olat.core.gui.components.form.flexible.impl.FormBasicController; -import org.olat.core.gui.components.form.flexible.impl.FormEvent; -import org.olat.core.gui.components.form.flexible.impl.elements.table.*; -import org.olat.core.gui.components.stack.PopEvent; import org.olat.core.gui.components.stack.TooledStackedPanel; -import org.olat.core.gui.control.Controller; -import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.Identity; import org.olat.core.id.OLATResourceable; -import org.olat.core.id.context.ContextEntry; -import org.olat.core.id.context.StateEntry; -import org.olat.core.util.UserSession; import org.olat.core.util.resource.OresHelper; -import org.olat.modules.assessment.ui.component.LearningProgressCompletionCellRenderer; import org.olat.modules.coach.CoachingService; -import org.olat.modules.coach.UserRelationSecurityCallback; import org.olat.modules.coach.model.StudentStatEntry; -import org.olat.modules.coach.security.UserRelationSecurityCallbackFactory; -import org.olat.modules.coach.ui.StudentsTableDataModel.Columns; -import org.olat.user.UserManager; -import org.olat.user.propertyhandlers.UserPropertyHandler; +import org.olat.modules.coach.security.RoleSecurityCallbackFactory; +import org.olat.user.ui.role.RelationRolesAndRightsUIFactory; import org.springframework.beans.factory.annotation.Autowired; /** * Initial date: 25 May 2020<br> * @author aboeckle, alexander.boeckle@frentix.com */ -public class UserRelationListController extends FormBasicController implements Activateable2 { +public class UserRelationListController extends AbstactCoachListController implements Activateable2 { - private final boolean isAdministrativeUser; - private final List<UserPropertyHandler> userPropertyHandlers; - - private final TooledStackedPanel stackPanel; - private final RelationRole relationRole; - private final UserRelationSecurityCallback securityCallback; - - private boolean hasChanged; - - private FlexiTableElement tableEl; - private StudentsTableDataModel model; - - private UserRelationOverviewController userCtrl; - - @Autowired - private UserManager userManager; - @Autowired - private BaseSecurity securityManager; - @Autowired - private BaseSecurityModule securityModule; @Autowired private CoachingService coachingService; @Autowired private IdentityRelationshipService identityRelationshipService; - public UserRelationListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RelationRole relationRole) { - super(ureq, wControl, LAYOUT_BAREBONE); + private RelationRole relationRole; - setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); - isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles()); - userPropertyHandlers = userManager.getUserPropertyHandlersFor(UserListController.usageIdentifyer, isAdministrativeUser); + public UserRelationListController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, RelationRole relationRole) { + super(ureq, wControl, stackPanel); - this.stackPanel = stackPanel; - this.stackPanel.setInvisibleCrumb(0); - stackPanel.addListener(this); this.relationRole = identityRelationshipService.getRole(relationRole.getKey()); - this.securityCallback = UserRelationSecurityCallbackFactory.create(this.relationRole.getRights()); + this.securityCallback = RoleSecurityCallbackFactory.create(this.relationRole.getRights()); - initForm(ureq); + super.initForm(ureq); loadModel(); } @Override - protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { - //add the table - FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); - - int colIndex = UserListController.USER_PROPS_OFFSET; - for (int i = 0; i < userPropertyHandlers.size(); i++) { - UserPropertyHandler userPropertyHandler = userPropertyHandlers.get(i); - boolean visible = userManager.isMandatoryUserProperty(UserListController.usageIdentifyer, userPropertyHandler); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", - true, userPropertyHandler.i18nColumnDescriptorLabelKey())); - } - - if (securityCallback.canViewCoursesAndCurriculum()) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.countCourse)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.initialLaunch, new LightIconRenderer())); - } - - if (securityCallback.canViewCourseProgressAndStatus()) { - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.completion, new LearningProgressCompletionCellRenderer())); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.countPassed, new ProgressOfCellRenderer())); - } - - model = new StudentsTableDataModel(columnsModel); - tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); - tableEl.setExportEnabled(true); - tableEl.setEmtpyTableMessageKey("error.no.found"); - tableEl.setAndLoadPersistedPreferences(ureq, "UserRelationsListController"); - - UserSession usess = ureq.getUserSession(); - boolean autoCompleteAllowed = securityModule.isUserAllowedAutoComplete(usess.getRoles()); - if (autoCompleteAllowed) { - tableEl.setSearchEnabled(new StudentListProvider(model, userManager), usess); - } - } - - @Override - protected void doDispose() { - stackPanel.removeListener(this); - } - - @Override - protected void formOK(UserRequest ureq) { - // - } - - @Override - protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - if (tableEl == source) { - if (event instanceof SelectionEvent) { - SelectionEvent se = (SelectionEvent) event; - String cmd = se.getCommand(); - StudentStatEntry selectedRow = model.getObject(se.getIndex()); - if ("select".equals(cmd)) { - selectStudent(ureq, selectedRow); - } - } else if (event instanceof FlexiTableSearchEvent) { - FlexiTableSearchEvent ftse = (FlexiTableSearchEvent) event; - String searchString = ftse.getSearch(); - model.search(searchString); - tableEl.reset(); - tableEl.reloadData(); - } - } - super.formInnerEvent(ureq, source, event); - } - - private void loadModel() { + protected void loadModel() { List<StudentStatEntry> students = coachingService.getUserStatistics(getIdentity(), relationRole, userPropertyHandlers, getLocale()); model.setObjects(students); tableEl.reset(); tableEl.reloadData(); } - private void reloadModel() { - if (hasChanged) { - loadModel(); - hasChanged = false; - } - } - - @Override - protected void event(UserRequest ureq, Controller source, Event event) { - if (source == userCtrl) { - if (event == Event.CHANGED_EVENT) { - hasChanged = true; - } else if ("next.student".equals(event.getCommand())) { - nextStudent(ureq); - } else if ("previous.student".equals(event.getCommand())) { - previousStudent(ureq); - } - } - super.event(ureq, source, event); - } - - @Override - public void event(UserRequest ureq, Component source, Event event) { - if (stackPanel == source) { - if (event instanceof PopEvent) { - PopEvent pe = (PopEvent) event; - if (pe.getController() == this.userCtrl && hasChanged) { - reloadModel(); - } - } - } - super.event(ureq, source, event); - } - - @Override - public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { - if (entries == null || entries.isEmpty()) return; - - ContextEntry ce = entries.get(0); - OLATResourceable ores = ce.getOLATResourceable(); - if ("Identity".equals(ores.getResourceableTypeName())) { - Long identityKey = ores.getResourceableId(); - for (StudentStatEntry entry : model.getObjects()) { - if (identityKey.equals(entry.getIdentityKey())) { - Activateable2 selectedCtrl = selectStudent(ureq, entry); - selectedCtrl.activate(ureq, entries.subList(1, entries.size()), ce.getTransientState()); - break; - } - } - } - } - - protected void previousStudent(UserRequest ureq) { - StudentStatEntry currentEntry = userCtrl.getEntry(); - int previousIndex = model.getObjects().indexOf(currentEntry) - 1; - if (previousIndex < 0 || previousIndex >= model.getRowCount()) { - previousIndex = model.getRowCount() - 1; - } - StudentStatEntry previousEntry = model.getObject(previousIndex); - selectStudent(ureq, previousEntry); - } - - protected void nextStudent(UserRequest ureq) { - StudentStatEntry currentEntry = userCtrl.getEntry(); - int nextIndex = model.getObjects().indexOf(currentEntry) + 1; - if (nextIndex < 0 || nextIndex >= model.getRowCount()) { - nextIndex = 0; - } - StudentStatEntry nextEntry = model.getObject(nextIndex); - selectStudent(ureq, nextEntry); - } - - protected UserRelationOverviewController selectStudent(UserRequest ureq, StudentStatEntry studentStat) { + protected UserOverviewController selectStudent(UserRequest ureq, StudentStatEntry studentStat) { Identity student = securityManager.loadIdentityByKey(studentStat.getIdentityKey()); OLATResourceable ores = OresHelper.createOLATResourceableInstance(Identity.class, student.getKey()); WindowControl bwControl = addToHistory(ureq, ores, null); int index = model.getObjects().indexOf(studentStat); - userCtrl = new UserRelationOverviewController(ureq, bwControl, stackPanel, studentStat, student, index, model.getRowCount(), relationRole, securityCallback); + String roleTranslation = RelationRolesAndRightsUIFactory.getTranslatedContraRole(relationRole, getLocale()); + userCtrl = new UserOverviewController(ureq, bwControl, stackPanel, studentStat, student, index, model.getRowCount(), roleTranslation, securityCallback); listenTo(userCtrl); - stackPanel.popUpToRootController(ureq); String displayName = userManager.getUserDisplayName(student); stackPanel.pushController(displayName, userCtrl); return userCtrl; diff --git a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties index 2416d91cced22c3b9152f2e99fa6b98659020e80..752ccc07b60789017b73a94fd89e0d5b0d8ed22f 100644 --- a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_de.properties @@ -27,6 +27,7 @@ lectures.teacher.menu.title=Lektionen lectures.teacher.menu.title.alt=Lektionen und Absenzmanagement home.link=Visitenkarte lectures=Lektionen \uFF06 Abwesenheiten +line.manager.title=$org.olat.admin.user\:role.linemanager main.menu.title.alt=\$:site.title.alt main.menu.title=\$:site.title menu.coaching.alt=\$:site.title.alt diff --git a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties index 4c41afe4c892b92616020620acc72cc740c52397..f4da3e3a1e103ed981fe5ce7529ceefca8408dc8 100644 --- a/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/coach/ui/_i18n/LocalStrings_en.properties @@ -27,6 +27,7 @@ lectures.mastercoach.menu.title=Classes lectures.mastercoach.menu.title.alt=Management of absences and lectures in classes lectures.teacher.menu.title=Lectures lectures.teacher.menu.title.alt=Lectures and absences management +line.manager.title=$org.olat.admin.user\:roles.linemanager main.menu.title=$\:site.title main.menu.title.alt=$\:site.title.alt menu.coaching=$\:site.title diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementWithViewsDataModel.java b/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementWithViewsDataModel.java deleted file mode 100644 index cee9015ab2644895dd55c2cbe6a936d87e324948..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementWithViewsDataModel.java +++ /dev/null @@ -1,173 +0,0 @@ -/** - * <a href="http://www.openolat.org"> - * OpenOLAT - Online Learning and Training</a><br> - * <p> - * Licensed under the Apache License, Version 2.0 (the "License"); <br> - * you may not use this file except in compliance with the License.<br> - * You may obtain a copy of the License at the - * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> - * <p> - * Unless required by applicable law or agreed to in writing,<br> - * software distributed under the License is distributed on an "AS IS" BASIS, <br> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> - * See the License for the specific language governing permissions and <br> - * limitations under the License. - * <p> - * Initial code contributed and copyrighted by<br> - * frentix GmbH, http://www.frentix.com - * <p> - */ -package org.olat.modules.coach.ui.curriculum; - -import java.util.ArrayList; -import java.util.List; - -import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; -import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTreeTableDataModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiBusinessPathModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; -import org.olat.modules.curriculum.CurriculumElementStatus; - -/** - * - * Initial date: 11 mai 2018<br> - * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com - * - */ -public class CurriculumElementWithViewsDataModel extends DefaultFlexiTreeTableDataModel<CurriculumElementWithViewsRow> implements FlexiBusinessPathModel { - - public CurriculumElementWithViewsDataModel(FlexiTableColumnModel columnsModel) { - super(columnsModel); - } - - @Override - public void filter(String searchString, List<FlexiTableFilter> filters) { - if(filters != null && !filters.isEmpty() && filters.get(0) != null) { - FlexiTableFilter filter = filters.get(0); - if(filter == null || filter.isShowAll()) { - setUnfilteredObjects(); - } else { - List<CurriculumElementWithViewsRow> filteredRows = new ArrayList<>(backupRows.size()); - // curriculum element inactive -> all repo are inactives - // parent inactive, child is active -> parent is forced active - for(CurriculumElementWithViewsRow row:backupRows) { - boolean accept = active(row); - if(accept) { - filteredRows.add(row); - } - } - setFilteredObjects(filteredRows); - } - } else { - setUnfilteredObjects(); - } - } - - private boolean active(CurriculumElementWithViewsRow row) { - boolean active = true; - if(row.isCurriculumElementOnly() || row.isCurriculumElementWithEntry()) { - active = row.getCurriculumElementStatus() == CurriculumElementStatus.active; - } - if(active) { - for(CurriculumElementWithViewsRow parent = row.getParent(); parent != null; parent=parent.getParent()) { - if(parent.isCurriculumElementOnly() || parent.isCurriculumElementWithEntry()) { - active &= row.getCurriculumElementStatus() == CurriculumElementStatus.active; - } - } - } - return active; - } - - @Override - public boolean hasChildren(int row) { - CurriculumElementWithViewsRow element = getObject(row); - return element.hasChildren(); - } - - @Override - public Object getValueAt(int row, int col) { - CurriculumElementWithViewsRow curriculum = getObject(row); - switch(ElementViewCols.values()[col]) { - case key: return curriculum.getKey(); - case displayName: { - String displayName; - if(curriculum.isRepositoryEntryOnly()) { - displayName = curriculum.getRepositoryEntryDisplayName(); - } else { - displayName = curriculum.getCurriculumElementDisplayName(); - } - return displayName; - } - case identifier: { - String identifier; - if(curriculum.isRepositoryEntryOnly()) { - identifier = curriculum.getRepositoryEntryExternalRef(); - } else { - identifier = curriculum.getCurriculumElementIdentifier(); - } - return identifier; - } - case mark: return curriculum.getMarkLink(); - case select: return curriculum.getSelectLink(); - case details: return curriculum.getDetailsLink(); - case start: return curriculum.getStartLink(); - case calendars: return curriculum.getCalendarsLink(); - case completion: return curriculum.getCompletionItem(); - default: return "ERROR"; - } - } - - @Override - public CurriculumElementWithViewsDataModel createCopyWithEmptyList() { - return new CurriculumElementWithViewsDataModel(getTableColumnModel()); - } - - public enum ElementViewCols implements FlexiSortableColumnDef { - key("table.header.key"), - displayName("table.header.curriculum.element.displayName"), - identifier("table.header.curriculum.element.identifier"), - mark("table.header.mark"), - select("table.header.displayName"), - completion("table.header.completion"), - details("table.header.details"), - start("table.header.start"), - calendars("table.header.calendars"); - - private final String i18nHeaderKey; - - private ElementViewCols(String i18nHeaderKey) { - this.i18nHeaderKey = i18nHeaderKey; - } - - @Override - public boolean sortable() { - return false; - } - - @Override - public String sortKey() { - return name(); - } - - @Override - public String i18nHeaderKey() { - return i18nHeaderKey; - } - } - - @Override - public String getUrl(Component source, Object object, String action) { - if("select".equals(action) && object instanceof CurriculumElementWithViewsRow) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow)object; - if(row.getStartUrl() != null) { - return row.getStartUrl(); - } - if(row.getDetailsUrl() != null) { - return row.getDetailsUrl(); - } - } - return null; - } -} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CertificateAndEfficiencyStatementCurriculumListController.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CertificateAndEfficiencyStatementCurriculumListController.java new file mode 100644 index 0000000000000000000000000000000000000000..47dd35c979488c2b357c6ce16493dbbee83e26b8 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CertificateAndEfficiencyStatementCurriculumListController.java @@ -0,0 +1,901 @@ +/** + * <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.coach.ui.curriculum.certificate; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +import org.olat.NewControllerFactory; +import org.olat.basesecurity.BaseSecurity; +import org.olat.core.commons.services.mark.Mark; +import org.olat.core.commons.services.mark.MarkManager; +import org.olat.core.dispatcher.mapper.MapperService; +import org.olat.core.dispatcher.mapper.manager.MapperKey; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.form.flexible.FormItem; +import org.olat.core.gui.components.form.flexible.FormItemContainer; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.core.gui.components.form.flexible.impl.FormBasicController; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.BooleanCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponentDelegate; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableCssDelegate; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.TextFlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.TreeNodeFlexiCellRenderer; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.progressbar.ProgressBar.BarColor; +import org.olat.core.gui.components.progressbar.ProgressBar.LabelAlignment; +import org.olat.core.gui.components.progressbar.ProgressBar.RenderSize; +import org.olat.core.gui.components.progressbar.ProgressBar.RenderStyle; +import org.olat.core.gui.components.progressbar.ProgressBarItem; +import org.olat.core.gui.components.stack.BreadcrumbPanel; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.Identity; +import org.olat.core.id.OLATResourceable; +import org.olat.core.id.Roles; +import org.olat.core.id.context.BusinessControlFactory; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.StringHelper; +import org.olat.core.util.Util; +import org.olat.core.util.resource.OresHelper; +import org.olat.core.util.vfs.VFSLeaf; +import org.olat.course.CorruptedCourseException; +import org.olat.course.assessment.AssessmentModule; +import org.olat.course.assessment.manager.EfficiencyStatementManager; +import org.olat.course.assessment.model.UserEfficiencyStatementLight; +import org.olat.course.certificate.CertificateLight; +import org.olat.course.certificate.CertificatesManager; +import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListController; +import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListModel; +import org.olat.modules.assessment.AssessmentEntryCompletion; +import org.olat.modules.assessment.AssessmentService; +import org.olat.modules.coach.RoleSecurityCallback; +import org.olat.modules.coach.ui.curriculum.certificate.CurriculumElementWithViewsDataModel.ElementViewCols; +import org.olat.modules.curriculum.Curriculum; +import org.olat.modules.curriculum.CurriculumElement; +import org.olat.modules.curriculum.CurriculumElementMembership; +import org.olat.modules.curriculum.CurriculumSecurityCallback; +import org.olat.modules.curriculum.CurriculumService; +import org.olat.modules.curriculum.model.CurriculumElementRefImpl; +import org.olat.modules.curriculum.model.CurriculumElementRepositoryEntryViews; +import org.olat.modules.curriculum.ui.CurriculumElementCalendarController; +import org.olat.modules.curriculum.ui.CurriculumListController; +import org.olat.repository.RepositoryEntry; +import org.olat.repository.RepositoryEntryMyView; +import org.olat.repository.RepositoryEntryRef; +import org.olat.repository.RepositoryManager; +import org.olat.repository.RepositoryService; +import org.olat.repository.controllers.EntryChangedEvent; +import org.olat.repository.controllers.EntryChangedEvent.Change; +import org.olat.repository.model.RepositoryEntryRefImpl; +import org.olat.repository.model.SearchMyRepositoryEntryViewParams; +import org.olat.repository.ui.PriceMethod; +import org.olat.repository.ui.RepositoryEntryImageMapper; +import org.olat.repository.ui.list.RepositoryEntryDetailsController; +import org.olat.resource.OLATResource; +import org.olat.resource.accesscontrol.ACService; +import org.olat.resource.accesscontrol.AccessControlModule; +import org.olat.resource.accesscontrol.method.AccessMethodHandler; +import org.olat.resource.accesscontrol.model.OLATResourceAccess; +import org.olat.resource.accesscontrol.model.PriceMethodBundle; +import org.olat.resource.accesscontrol.ui.PriceFormat; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * This is a list of curriculum elements and repository entries + * aimed to participants. The repository entries permissions + * follow the same rules as {@link org.olat.repository.ui.list.RepositoryEntryListController}<br> + * <p> + * <p> + * Initial date: 11 mai 2018<br> + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class CertificateAndEfficiencyStatementCurriculumListController extends FormBasicController implements FlexiTableCssDelegate, FlexiTableComponentDelegate, Activateable2 { + + private FlexiTableElement tableEl; + private CurriculumElementWithViewsDataModel tableModel; + private final BreadcrumbPanel stackPanel; + + private int counter; + private final boolean guestOnly; + private final List<Curriculum> curriculumList; + + private final MapperKey mapperThumbnailKey; + private final Identity assessedIdentity; + private final CurriculumSecurityCallback curriculumSecurityCallback; + private final RoleSecurityCallback roleSecurityCallback; + + private RepositoryEntryDetailsController detailsCtrl; + private CurriculumElementCalendarController calendarsCtrl; + + @Autowired + private ACService acService; + @Autowired + private MarkManager markManager; + @Autowired + private MapperService mapperService; + @Autowired + private AccessControlModule acModule; + @Autowired + private RepositoryService repositoryService; + @Autowired + private CurriculumService curriculumService; + @Autowired + private RepositoryManager repositoryManager; + @Autowired + private AssessmentService assessmentService; + @Autowired + private BaseSecurity securityManager; + @Autowired + private EfficiencyStatementManager esm; + @Autowired + private CertificatesManager certificatesManager; + + public CertificateAndEfficiencyStatementCurriculumListController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, + Identity assessedIdentity, CurriculumSecurityCallback curriculumSecurityCallback, RoleSecurityCallback roleSecurityCallback) { + super(ureq, wControl, "curriculum_element_list"); + setTranslator(Util.createPackageTranslator(AssessmentModule.class, getLocale(), getTranslator())); + setTranslator(Util.createPackageTranslator(CertificateAndEfficiencyStatementListController.class, getLocale(), getTranslator())); + setTranslator(Util.createPackageTranslator(CurriculumListController.class, getLocale(), getTranslator())); + setTranslator(Util.createPackageTranslator(RepositoryService.class, getLocale(), getTranslator())); + + this.stackPanel = stackPanel; + this.curriculumSecurityCallback = curriculumSecurityCallback; + this.roleSecurityCallback = roleSecurityCallback; + this.assessedIdentity = assessedIdentity; + this.curriculumList = curriculumService.getMyCurriculums(assessedIdentity); + guestOnly = ureq.getUserSession().getRoles().isGuestOnly(); + mapperThumbnailKey = mapperService.register(null, "repositoryentryImage", new RepositoryEntryImageMapper()); + + initForm(ureq); + loadModel(ureq); + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + + } + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ElementViewCols.key)); + + TreeNodeFlexiCellRenderer treeNodeRenderer = new TreeNodeFlexiCellRenderer("select"); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.displayName, treeNodeRenderer)); + + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.details)); + + DefaultFlexiColumnModel elementIdentifierCol = new DefaultFlexiColumnModel(ElementViewCols.identifier, "select"); + elementIdentifierCol.setCellRenderer(new CurriculumElementCompositeRenderer("select", new TextFlexiCellRenderer())); + columnsModel.addFlexiColumnModel(elementIdentifierCol); + + // Name column + // columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ElementViewCols.select)); + + if (roleSecurityCallback.canViewCourseProgressAndStatus()) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.passed)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.completion)); + } + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.lastModification)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.lastUserModified)); + if (roleSecurityCallback.canViewEfficiencyStatements()) { + BooleanCellRenderer efficiencyStatementRenderer = new BooleanCellRenderer(new StaticFlexiCellRenderer("openStatement", translate("table.header.show")), null); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.efficiencyStatement, efficiencyStatementRenderer)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.certificate)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.recertification)); + } + if (roleSecurityCallback.canViewCalendar()) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.calendars)); + } + + tableModel = new CurriculumElementWithViewsDataModel(columnsModel); + tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 50, false, getTranslator(), formLayout); + tableEl.setElementCssClass("o_curriculumtable"); + tableEl.setCustomizeColumns(true); + tableEl.setEmtpyTableMessageKey("table.curriculum.empty"); + tableEl.setCssDelegate(this); + tableEl.setFilters("activity", getFilters(), false); + tableEl.setSelectedFilterKey(CurriculumElementWithViewsDataModel.FilterKeys.withStatementOnly.name()); + + VelocityContainer row = createVelocityContainer("curriculum_element_row"); + row.setDomReplacementWrapperRequired(false); // sets its own DOM id in velocity container + tableEl.setRowRenderer(row, this); + + tableEl.setAndLoadPersistedPreferences(ureq, "c123oach-mentor-curriculum-" + + (assessedIdentity.equals(getIdentity()) ? "" : "look-")); + } + + private List<FlexiTableFilter> getFilters() { + List<FlexiTableFilter> filters = new ArrayList<>(5); + filters.add(new FlexiTableFilter(translate(CurriculumElementWithViewsDataModel.FilterKeys.activ.i18nHeaderKey()), CurriculumElementWithViewsDataModel.FilterKeys.activ.name())); + filters.add(new FlexiTableFilter(translate(CurriculumElementWithViewsDataModel.FilterKeys.withStatementOnly.i18nHeaderKey()), CurriculumElementWithViewsDataModel.FilterKeys.withStatementOnly.name())); + filters.add(FlexiTableFilter.SPACER); + filters.add(new FlexiTableFilter(translate(CurriculumElementWithViewsDataModel.FilterKeys.showAll.i18nHeaderKey()), CurriculumElementWithViewsDataModel.FilterKeys.showAll.name(), true)); + return filters; + } + + @Override + public String getWrapperCssClass(FlexiTableRendererType type) { + return null; + } + + @Override + public String getTableCssClass(FlexiTableRendererType type) { + return null; + } + + @Override + public String getRowCssClass(FlexiTableRendererType type, int pos) { + StringBuilder sb = new StringBuilder(64); + CurriculumTreeWithViewsRow rowWithView = tableModel.getObject(pos); + if (type == FlexiTableRendererType.custom) { + sb.append("o_table_row "); + + if (rowWithView.isCurriculumElementOnly()) { + sb.append("o_curriculum_element"); + if (rowWithView.getCurriculumElementRepositoryEntryCount() > 1) { + sb.append(" o_with_multi_repository_entries"); + } + } else if (rowWithView.isRepositoryEntryOnly()) { + sb.append("o_repository_entry"); + } else if (rowWithView.isCurriculumElementWithEntry()) { + sb.append("o_mixed_element"); + } + } + + if (rowWithView.isCurriculum() || rowWithView.getLevel() == -1) { + sb.append(" o_curriculum"); + } else { + int count = 0; + for (CurriculumTreeWithViewsRow parent = rowWithView.getParent(); parent != null; parent = parent.getParent()) { + count++; + } + + // Substract one level for the curriculum parent + if (count > 0) { + count -= 1; + } + + sb.append(" o_curriculum_element_l").append(count); + if (!rowWithView.isRepositoryEntryOnly() && rowWithView.getCurriculumElementTypeCssClass() != null) { + sb.append(" ").append(rowWithView.getCurriculumElementTypeCssClass()); + } + if (rowWithView.getEntryStatus() != null) { + sb.append(" repo_status_").append(rowWithView.getEntryStatus()); + } + } + return sb.toString(); + } + + @Override + public Iterable<Component> getComponents(int row, Object rowObject) { + return null; + } + + private void loadModel(UserRequest ureq) { + // Load efficiency statements + Map<Long, CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement> resourceKeyToStatments = new HashMap<>(); + List<CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement> statements = new ArrayList<>(); + List<UserEfficiencyStatementLight> efficiencyStatementsList = esm.findEfficiencyStatementsLight(assessedIdentity); + + List<Long> courseEntryKeys = efficiencyStatementsList.stream() + .map(UserEfficiencyStatementLight::getCourseRepoKey) + .filter(key -> key != null) + .collect(Collectors.toList()); + Map<Long, Double> courseEntryKeysToCompletion = assessmentService + .loadRootAssessmentEntriesByAssessedIdentity(assessedIdentity, courseEntryKeys).stream() + .filter(ae -> ae.getCompletion() != null) + .collect(Collectors.toMap( + ae -> ae.getRepositoryEntryKey(), + ae -> ae.getCompletion() + )); + + for(UserEfficiencyStatementLight efficiencyStatement:efficiencyStatementsList) { + CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement wrapper = new CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement(); + wrapper.setDisplayName(efficiencyStatement.getShortTitle()); + wrapper.setPassed(efficiencyStatement.getPassed()); + wrapper.setScore(efficiencyStatement.getScore()); + wrapper.setEfficiencyStatementKey(efficiencyStatement.getKey()); + wrapper.setResourceKey(efficiencyStatement.getArchivedResourceKey()); + wrapper.setLastModified(efficiencyStatement.getLastModified()); + wrapper.setLastUserModified(efficiencyStatement.getLastUserModified()); + Double completion = courseEntryKeysToCompletion.get(efficiencyStatement.getCourseRepoKey()); + wrapper.setCompletion(completion); + statements.add(wrapper); + resourceKeyToStatments.put(efficiencyStatement.getArchivedResourceKey(), wrapper); + } + + List<CertificateLight> certificates = certificatesManager.getLastCertificates(assessedIdentity); + for(CertificateLight certificate:certificates) { + Long resourceKey = certificate.getOlatResourceKey(); + CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement wrapper = resourceKeyToStatments.get(resourceKey); + if(wrapper == null) { + wrapper = new CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement(); + wrapper.setDisplayName(certificate.getCourseTitle()); + resourceKeyToStatments.put(resourceKey, wrapper); + statements.add(wrapper); + } else { + if(!StringHelper.containsNonWhitespace(wrapper.getDisplayName())) { + wrapper.setDisplayName(certificate.getCourseTitle()); + } + wrapper.setResourceKey(resourceKey); + } + if(resourceKey != null && wrapper.getResourceKey() == null) { + wrapper.setResourceKey(resourceKey); + } + wrapper.setCertificate(certificate); + } + + for(CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement statment:statements) { + if(!StringHelper.containsNonWhitespace(statment.getDisplayName()) && statment.getResourceKey() != null) { + String displayName = repositoryManager.lookupDisplayNameByResourceKey(statment.getResourceKey()); + statment.setDisplayName(displayName); + } + } + + // Set of Olat resources with statements + Set<Long> statementEntries = statements.stream().map(CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement::getResourceKey).collect(Collectors.toSet()); + // Set of entries, which will be added in the next step + Set<Long> alreadyAdded = new HashSet<>(); + + // Load Curricula + Roles roles = ureq.getUserSession().getRoles(); + List<CurriculumTreeWithViewsRow> allRows = new ArrayList<>(); + List<CurriculumElementRepositoryEntryViews> elementsWithViewsForAll = curriculumService.getCurriculumElements(assessedIdentity, roles, curriculumList); + Map<Curriculum, List<CurriculumElementRepositoryEntryViews>> elementsMap = elementsWithViewsForAll.stream().collect(Collectors.groupingBy(row -> row.getCurriculumElement().getCurriculum(), Collectors.toList())); + + for (Curriculum curriculum : curriculumList) { + CurriculumTreeWithViewsRow curriculumRow = new CurriculumTreeWithViewsRow(curriculum); + List<CurriculumElementRepositoryEntryViews> elementsWithViews = elementsMap.get(curriculum); + + if (elementsWithViews != null && !elementsWithViews.isEmpty()) { + List<CurriculumTreeWithViewsRow> rows = new ArrayList<>(); + + Set<Long> repoKeys = new HashSet<>(); + List<OLATResource> resourcesWithAC = new ArrayList<>(); + for (CurriculumElementRepositoryEntryViews elementWithViews : elementsWithViews) { + for (RepositoryEntryMyView entry : elementWithViews.getEntries()) { + repoKeys.add(entry.getKey()); + if (entry.isValidOfferAvailable()) { + resourcesWithAC.add(entry.getOlatResource()); + } + } + } + List<OLATResourceAccess> resourcesWithOffer = acService.filterResourceWithAC(resourcesWithAC); + repositoryService.filterMembership(assessedIdentity, repoKeys); + + for (CurriculumElementRepositoryEntryViews elementWithViews : elementsWithViews) { + CurriculumElement element = elementWithViews.getCurriculumElement(); + CurriculumElementMembership elementMembership = elementWithViews.getCurriculumMembership(); + + List<RepositoryEntryMyView> repositoryEntryMyViews = new ArrayList<>(); + if (elementWithViews.getEntries() != null && !elementWithViews.getEntries().isEmpty()) { + for (RepositoryEntryMyView entry : elementWithViews.getEntries()) { + // if (statementEntries.contains(entry.getOlatResource().getKey())) { + repositoryEntryMyViews.add(entry); + // } + } + } + + + if (repositoryEntryMyViews == null || repositoryEntryMyViews.isEmpty()) { + CurriculumTreeWithViewsRow row = new CurriculumTreeWithViewsRow(curriculum, element, elementMembership, 0); + forgeCalendarsLink(row); + rows.add(row); + } else if (repositoryEntryMyViews.size() == 1) { + CurriculumTreeWithViewsRow row = new CurriculumTreeWithViewsRow(curriculum, element, elementMembership, elementWithViews.getEntries().get(0), true); + forge(row, repoKeys, resourcesWithOffer); + forgeCalendarsLink(row); + rows.add(row); + } else { + CurriculumTreeWithViewsRow elementRow = new CurriculumTreeWithViewsRow(curriculum, element, elementMembership, elementWithViews.getEntries().size()); + forgeCalendarsLink(elementRow); + rows.add(elementRow); + for (RepositoryEntryMyView entry : repositoryEntryMyViews) { + CurriculumTreeWithViewsRow row = new CurriculumTreeWithViewsRow(curriculum, element, elementMembership, entry, false); + forge(row, repoKeys, resourcesWithOffer); + rows.add(row); + } + } + } + + + Map<CurriculumKey, CurriculumTreeWithViewsRow> keyToRow = rows.stream() + .collect(Collectors.toMap(CurriculumTreeWithViewsRow::getKey, row -> row, (row1, row2) -> row1)); + rows.forEach(row -> { + row.setParent(keyToRow.get(row.getParentKey())); + if (row.getOlatResource() != null) { + alreadyAdded.add(row.getOlatResource().getKey()); + if (statementEntries.contains(row.getOlatResource().getKey())){ + row.setHasStatement(true); + } + + VFSLeaf image = repositoryManager.getImage(row.getRepositoryEntryResourceable().getResourceableId(), row.getOlatResource()); + if (image != null) { + row.setThumbnailRelPath(mapperThumbnailKey.getUrl() + "/" + image.getName()); + } + } + }); + + removeByPermissions(rows); + forgeCurriculumCompletions(rows); + addRoot(rows, curriculumRow); + + allRows.add(curriculumRow); + allRows.addAll(rows); + } + } + + + + // Filter for entries which are already in a curriculum + Roles assessedRoles = securityManager.getRoles(assessedIdentity); + SearchMyRepositoryEntryViewParams params = new SearchMyRepositoryEntryViewParams(assessedIdentity, assessedRoles); + params.setMembershipMandatory(true); + List<RepositoryEntryMyView> courses = repositoryService.searchMyView(params, 0, 0); + +// // Filter for entries which have a efficiency statement +// Set<Long> alreadyAdded = new HashSet<>(); +// for (CurriculumTreeWithViewsRow row : allRows) { +// for (RepositoryEntryMyView entry : row.getEntries()) { +// alreadyAdded.add(entry.getOlatResource().getKey()); +// } +// } + + courses.removeIf(course -> alreadyAdded.contains(course.getOlatResource().getKey())); + + // Filter for entries which are without curriculum + CurriculumTreeWithViewsRow foreignEntryParent = new CurriculumTreeWithViewsRow(translate("curriculum.foreign.entries")); + + if (!courses.isEmpty()) { + allRows.add(foreignEntryParent); + + courses.forEach(course -> { + CurriculumTreeWithViewsRow row = new CurriculumTreeWithViewsRow(course); + forgeSelectLink(row); + forgeCompletion(row,row.getRepositoryEntryCompletion()); + forgeDetails(row); + row.setParent(foreignEntryParent); + row.setHasStatement(true); + allRows.add(row); + alreadyAdded.add(course.getOlatResource().getKey()); + }); + } + + // Add Statements which don't belong to any course + Set<Long> orphanCertificates = statementEntries.stream().filter(certificateResourceKey -> !alreadyAdded.contains(certificateResourceKey)).collect(Collectors.toSet()); + + if (!orphanCertificates.isEmpty()) { + if (!allRows.contains(foreignEntryParent)) { + allRows.add(foreignEntryParent); + } + + orphanCertificates.forEach(orphan -> { + CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement statement = statements.stream().filter(certStatement -> certStatement.getResourceKey().equals(orphan)).findFirst().get(); + CurriculumTreeWithViewsRow row = new CurriculumTreeWithViewsRow(statement); + row.setParent(foreignEntryParent); + row.setHasStatement(true); + allRows.add(row); + }); + } + + + Collections.sort(allRows, new CurriculumElementViewsRowComparator(getLocale())); + + + tableModel.setObjects(allRows); + tableEl.reset(true, true, true); + } + + private void removeByPermissions(List<CurriculumTreeWithViewsRow> rows) { + // propagate the member marker along the parent line + for (CurriculumTreeWithViewsRow row : rows) { + if (row.isCurriculumMember()) { + for (CurriculumTreeWithViewsRow parentRow = row.getParent(); parentRow != null; parentRow = parentRow.getParent()) { + parentRow.setCurriculumMember(true); + } + } + } + + // trim part of the tree without member flag + rows.removeIf(curriculumTreeWithViewsRow -> !curriculumTreeWithViewsRow.isCurriculumMember()); + } + + private void forge(CurriculumTreeWithViewsRow row, Collection<Long> repoKeys, List<OLATResourceAccess> resourcesWithOffer) { + if (row.getRepositoryEntryKey() == null || guestOnly) return;// nothing for guests + + boolean isMember = repoKeys.contains(row.getRepositoryEntryKey()); + row.setMember(isMember); + + FormLink startLink = null; + List<PriceMethod> types = new ArrayList<>(); + if (row.isAllUsers() || isMember) { + startLink = uifactory.addFormLink("start_" + (++counter), "start", "start", null, null, Link.LINK); + startLink.setElementCssClass("o_start btn-block"); + startLink.setCustomEnabledLinkCSS("o_start btn-block"); + startLink.setIconRightCSS("o_icon o_icon_start"); + } else if (row.isBookable()) { + // collect access control method icons + OLATResource resource = row.getOlatResource(); + for (OLATResourceAccess resourceAccess : resourcesWithOffer) { + if (resource.getKey().equals(resourceAccess.getResource().getKey())) { + for (PriceMethodBundle bundle : resourceAccess.getMethods()) { + String type = (bundle.getMethod().getMethodCssClass() + "_icon").intern(); + String price = bundle.getPrice() == null || bundle.getPrice().isEmpty() ? "" : PriceFormat.fullFormat(bundle.getPrice()); + AccessMethodHandler amh = acModule.getAccessMethodHandler(bundle.getMethod().getType()); + String displayName = amh.getMethodName(getLocale()); + types.add(new PriceMethod(price, type, displayName)); + } + } + } + + startLink = uifactory.addFormLink("start_" + (++counter), "start", "book", null, null, Link.LINK); + startLink.setElementCssClass("o_start btn-block"); + startLink.setCustomEnabledLinkCSS("o_book btn-block"); + startLink.setIconRightCSS("o_icon o_icon_start"); + } + + if(startLink != null) { + startLink.setUserObject(row); + String businessPath = "[RepositoryEntry:" + row.getRepositoryEntryKey() + "]"; + String startUrl = BusinessControlFactory.getInstance().getAuthenticatedURLFromBusinessPathString(businessPath); + startLink.setUrl(startUrl); + row.setStartLink(startLink, startUrl); + } + + + if (!row.isAllUsers() && !row.isGuests()) { + // members only always show lock icon + types.add(new PriceMethod("", "o_ac_membersonly_icon", translate("cif.access.membersonly.short"))); + } + if (!types.isEmpty()) { + row.setAccessTypes(types); + } + + forgeDetails(row); + forgeMarkLink(row); + forgeSelectLink(row); + forgeCompletion(row, row.getRepositoryEntryCompletion()); + } + + private void forgeDetails(CurriculumTreeWithViewsRow row) { + FormLink detailsLink = uifactory.addFormLink("details_" + (++counter), "details", "details", null, null, Link.LINK); + detailsLink.setCustomEnabledLinkCSS("o_details"); + detailsLink.setUserObject(row); + Long repoEntryKey = row.getRepositoryEntryKey(); + String detailsUrl = null; + if(repoEntryKey != null) { + String businessPath = "[RepositoryEntry:" + repoEntryKey + "][Infos:0]"; + detailsUrl = BusinessControlFactory.getInstance() + .getAuthenticatedURLFromBusinessPathString(businessPath); + detailsLink.setUrl(detailsUrl); + } + row.setDetailsLink(detailsLink, detailsUrl); + } + + private void forgeMarkLink(CurriculumTreeWithViewsRow row) { + if (!guestOnly) { + FormLink markLink = uifactory.addFormLink("mark_" + (++counter), "mark", "", null, null, Link.NONTRANSLATED); + markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE); + markLink.setTitle(translate(row.isMarked() ? "details.bookmark.remove" : "details.bookmark")); + markLink.setUserObject(row); + row.setMarkLink(markLink); + } + } + + private void forgeSelectLink(CurriculumTreeWithViewsRow row) { + if (row.isCurriculumElementOnly()) return; + + String displayName = StringHelper.escapeHtml(row.getRepositoryEntryDisplayName()); + FormLink selectLink = uifactory.addFormLink("select_" + (++counter), "select", displayName, null, null, Link.NONTRANSLATED); + if (row.isClosed()) { + selectLink.setIconLeftCSS("o_icon o_CourseModule_icon_closed"); + } + Long repoEntryKey = row.getRepositoryEntryKey(); + if (repoEntryKey != null) { + String businessPath = "[RepositoryEntry:" + repoEntryKey + "]"; + selectLink.setUrl(BusinessControlFactory.getInstance() + .getAuthenticatedURLFromBusinessPathString(businessPath)); + } + selectLink.setUserObject(row); + row.setSelectLink(selectLink); + } + + private void forgeCalendarsLink(CurriculumTreeWithViewsRow row) { + if (row.isCalendarsEnabled()) { + FormLink calendarLink = uifactory.addFormLink("cals_" + (++counter), "calendars", "calendars", null, null, Link.LINK); + calendarLink.setIconLeftCSS("o_icon o_icon-fw o_icon_timetable"); + calendarLink.setUserObject(row); + row.setCalendarsLink(calendarLink); + } + } + + private void forgeCurriculumCompletions(List<CurriculumTreeWithViewsRow> rows) { + Map<Long, Double> completions = loadCurriculumElementCompletions(rows); + + for (CurriculumTreeWithViewsRow row : rows) { + if (row.getCompletionItem() == null) { // does not show completion of the child entry + forgeCompletion(row, completions.get(row.getKey())); + } + } + } + + private void forgeCompletion(CurriculumTreeWithViewsRow row, Double completion) { + if (completion != null) { + ProgressBarItem completionItem = new ProgressBarItem("completion_" + row.getKey(), 100, + completion.floatValue(), Float.valueOf(1), null); + completionItem.setWidthInPercent(true); + completionItem.setLabelAlignment(LabelAlignment.none); + completionItem.setRenderStyle(RenderStyle.radial); + completionItem.setRenderSize(RenderSize.inline); + completionItem.setBarColor(BarColor.success); + row.setCompletionItem(completionItem); + } + } + + private void addRoot(List<CurriculumTreeWithViewsRow> rows, CurriculumTreeWithViewsRow parent) { + rows.stream().filter(row -> row.getParent() == null).forEach(row -> { + row.setParent(parent); + if (row.hasStatement()) { + parent.setHasStatement(true); + } + }); + } + + private Map<Long, Double> loadCurriculumElementCompletions(List<CurriculumTreeWithViewsRow> rows) { + List<Long> curEleLearningProgressKeys = rows.stream() + .filter(CurriculumTreeWithViewsRow::isLearningProgressEnabled) + .map(CurriculumTreeWithViewsRow::getKey) + .map(CurriculumKey::getCurriculumElement) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + List<AssessmentEntryCompletion> loadAvgCompletionsByCurriculumElements = assessmentService + .loadAvgCompletionsByCurriculumElements(assessedIdentity, curEleLearningProgressKeys); + Map<Long, Double> completions = new HashMap<>(); + for (AssessmentEntryCompletion completion : loadAvgCompletionsByCurriculumElements) { + if (completion.getCompletion() != null) { + completions.put(completion.getKey(), completion.getCompletion()); + } + } + return completions; + } + + @Override + protected void doDispose() { + // + } + + @Override + protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent event) { + //do not update the + } + + @Override + public void event(UserRequest ureq, Component source, Event event) { + if (source == mainForm.getInitialComponent()) { + if ("ONCLICK".equals(event.getCommand())) { + String rowKeyStr = ureq.getParameter("select_row"); + if (StringHelper.isLong(rowKeyStr)) { + try { + Long rowKey = Long.valueOf(rowKeyStr); + List<CurriculumTreeWithViewsRow> rows = tableModel.getObjects(); + for (CurriculumTreeWithViewsRow row : rows) { + if (row != null && row.getRepositoryEntryKey() != null && row.getRepositoryEntryKey().equals(rowKey)) { + if (row.isMember()) { + doOpen(ureq, row, null); + } else { + doOpenDetails(ureq, row); + } + } + } + } catch (NumberFormatException e) { + logWarn("Not a valid long: " + rowKeyStr, e); + } + } + } + } + super.event(ureq, source, event); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if (source instanceof FormLink) { + FormLink link = (FormLink) source; + if ("start".equals(link.getCmd())) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow) link.getUserObject(); + doOpen(ureq, row, null); + } else if ("details".equals(link.getCmd())) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow) link.getUserObject(); + doOpenDetails(ureq, row); + } else if ("select".equals(link.getCmd())) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow) link.getUserObject(); + if (row.isMember()) { + doOpen(ureq, row, null); + } else { + doOpenDetails(ureq, row); + } + } else if ("mark".equals(link.getCmd())) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow) link.getUserObject(); + boolean marked = doMark(ureq, row); + link.setIconLeftCSS(marked ? "o_icon o_icon_bookmark o_icon-lg" : "o_icon o_icon_bookmark_add o_icon-lg"); + link.setTitle(translate(marked ? "details.bookmark.remove" : "details.bookmark")); + link.getComponent().setDirty(true); + row.setMarked(marked); + } else if ("calendars".equals(link.getCmd())) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow) link.getUserObject(); + doOpenCalendars(ureq, row); + } + } else if (source == tableEl) { + if (event instanceof SelectionEvent) { + SelectionEvent se = (SelectionEvent) event; + CurriculumTreeWithViewsRow row = tableModel.getObject(se.getIndex()); + if (row.isMember()) { + doOpen(ureq, row, null); + } else { + doOpenDetails(ureq, row); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + protected void formOK(UserRequest ureq) { + // + } + + private void doOpen(UserRequest ureq, CurriculumTreeWithViewsRow row, String subPath) { + try { + String businessPath = "[RepositoryEntry:" + row.getRepositoryEntryKey() + "]"; + if (subPath != null) { + businessPath += subPath; + } + NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl()); + } catch (CorruptedCourseException e) { + logError("Course corrupted: " + row.getKey() + " (" + row.getOlatResource().getResourceableId() + ")", e); + showError("cif.error.corrupted"); + } + } + + private void doOpenDetails(UserRequest ureq, CurriculumTreeWithViewsRow row) { + // to be more consistent: course members see info page within the course, non-course members see it outside the course + if (row.isMember()) { + doOpen(ureq, row, "[Infos:0]"); + } else { + removeAsListenerAndDispose(detailsCtrl); + + OLATResourceable ores = OresHelper.createOLATResourceableInstance("Infos", 0l); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); + + Long repoEntryKey = row.getRepositoryEntryKey(); + RepositoryEntry entry = repositoryService.loadByKey(repoEntryKey); + if (repoEntryKey == null) { + showInfo("curriculum.element.empty"); + } else if (entry == null) { + showWarning("repositoryentry.not.existing"); + } else { + detailsCtrl = new RepositoryEntryDetailsController(ureq, bwControl, entry, false); + listenTo(detailsCtrl); + addToHistory(ureq, detailsCtrl); + + String displayName = row.getRepositoryEntryDisplayName(); + stackPanel.pushController(displayName, detailsCtrl); + } + } + } + + private void doOpenCalendars(UserRequest ureq, CurriculumTreeWithViewsRow row) { + removeAsListenerAndDispose(calendarsCtrl); + + OLATResourceable ores = OresHelper.createOLATResourceableInstance("Calendars", row.getCurriculumElementKey()); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); + CurriculumElement element = curriculumService + .getCurriculumElement(new CurriculumElementRefImpl(row.getCurriculumElementKey())); + List<CurriculumTreeWithViewsRow> rows = tableModel.getObjects(); + + Set<Long> entryKeys = new HashSet<>(); + for (CurriculumTreeWithView elementWithView : rows) { + if (elementWithView.isCurriculumMember() + && !elementWithView.getEntries().isEmpty() + && elementWithView.isParentOrSelf(row)) { + for (RepositoryEntryMyView view : elementWithView.getEntries()) { + if ("CourseModule".equals(view.getOlatResource().getResourceableTypeName())) { + entryKeys.add(view.getKey()); + } + } + } + } + + + List<RepositoryEntry> entries = repositoryService.loadByKeys(entryKeys); + calendarsCtrl = new CurriculumElementCalendarController(ureq, bwControl, element, entries, curriculumSecurityCallback); + listenTo(calendarsCtrl); + stackPanel.pushController(translate("calendars"), calendarsCtrl); + } + + private boolean doMark(UserRequest ureq, CurriculumTreeWithViewsRow row) { + OLATResourceable item = OresHelper.createOLATResourceableInstance("RepositoryEntry", row.getRepositoryEntryKey()); + RepositoryEntryRef ref = new RepositoryEntryRefImpl(row.getRepositoryEntryKey()); + if (markManager.isMarked(item, getIdentity(), null)) { + markManager.removeMark(item, getIdentity(), null); + + EntryChangedEvent e = new EntryChangedEvent(ref, getIdentity(), Change.removeBookmark, "curriculum"); + ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES); + return false; + } else { + String businessPath = "[RepositoryEntry:" + item.getResourceableId() + "]"; + markManager.setMark(item, getIdentity(), null, businessPath); + + EntryChangedEvent e = new EntryChangedEvent(ref, getIdentity(), Change.addBookmark, "curriculum"); + ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES); + return true; + } + } + + private List<CurriculumTreeWithViewsRow> sortCurriculumRows(List<CurriculumTreeWithViewsRow> rows) { + List<CurriculumTreeWithViewsRow> sortedRows = rows.stream().filter(row -> row. getLevel() == 0).collect(Collectors.toList()); + + for (CurriculumTreeWithViewsRow parent : sortedRows) { + if (parent.hasChildren()) { + sortedRows.addAll(sortedRows.indexOf(parent) + 1, sortCurriculumRows(rows, parent)); + } + } + + return sortedRows; + } + + private List<CurriculumTreeWithViewsRow> sortCurriculumRows(List<CurriculumTreeWithViewsRow> rows, CurriculumTreeWithViewsRow parent) { + List<CurriculumTreeWithViewsRow> filteredRows = rows.stream().filter(row -> row.getParent() != null && row.getParent().equals(parent)).collect(Collectors.toList()); + List<CurriculumTreeWithViewsRow> sortedRows = new ArrayList<>(filteredRows); + + for (CurriculumTreeWithViewsRow child : filteredRows) { + if (child.hasChildren()) { + sortedRows.addAll(filteredRows.indexOf(child) + 1, sortCurriculumRows(rows, parent)); + } + } + + return filteredRows; + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CertificateAndEfficiencyStatementWrapperController.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CertificateAndEfficiencyStatementWrapperController.java new file mode 100644 index 0000000000000000000000000000000000000000..44cffc8ccafc3121a39af55ffba1fc7f5a34a362 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CertificateAndEfficiencyStatementWrapperController.java @@ -0,0 +1,172 @@ +/** + * <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.coach.ui.curriculum.certificate; + +import java.util.List; + +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.stack.TooledStackedPanel; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.gui.control.generic.dtabs.Activateable2; +import org.olat.core.id.Identity; +import org.olat.core.id.context.ContextEntry; +import org.olat.core.id.context.StateEntry; +import org.olat.core.util.event.GenericEventListener; +import org.olat.core.util.resource.OresHelper; +import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListController; +import org.olat.modules.coach.RoleSecurityCallback; +import org.olat.modules.coach.model.StudentStatEntry; +import org.olat.modules.curriculum.CurriculumModule; +import org.olat.modules.curriculum.CurriculumRef; +import org.olat.modules.curriculum.CurriculumSecurityCallback; +import org.springframework.beans.factory.annotation.Autowired; + +public class CertificateAndEfficiencyStatementWrapperController extends BasicController implements Activateable2, GenericEventListener { + + private static final String WITH_CURRICULUM = "Curriculum"; + private static final String WITHOUT_CURRICULM = "List"; + + private final TooledStackedPanel stackPanel; + private final Identity mentee; + private final StudentStatEntry statEntry; + private final CurriculumSecurityCallback curriculumSecurityCallback; + private final RoleSecurityCallback roleSecurityCallback; + private final List<CurriculumRef> curriculumRefs; + + private CertificateAndEfficiencyStatementCurriculumListController certificateCurriculumListController; + private CertificateAndEfficiencyStatementListController certificateListController; + + private Link curriculumShow; + private Link curriculumHide; + private boolean showCurriculum; + private String activeCSS = "o_button_toggle o_on"; + private String inactiveCSS = "o_button_toggle"; + private VelocityContainer content; + + @Autowired + CurriculumModule curriculumModule; + + public CertificateAndEfficiencyStatementWrapperController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, Identity mentee, CurriculumSecurityCallback curriculumSecurityCallback, RoleSecurityCallback roleSecurityCallback, List<CurriculumRef> curriculumRefs, StudentStatEntry statEntry) { + super(ureq, wControl); + + this.stackPanel = stackPanel; + this.mentee = mentee; + this.curriculumSecurityCallback = curriculumSecurityCallback; + this.roleSecurityCallback = roleSecurityCallback; + this.curriculumRefs = curriculumRefs; + this.statEntry = statEntry; + + content = createVelocityContainer("certificate_list_wrapper"); + showCurriculum = curriculumModule.isEnabled() && roleSecurityCallback.canViewCoursesAndCurriculum(); + + if (showCurriculum) { + curriculumShow = LinkFactory.createLink("off", content, this); + curriculumShow.setCustomEnabledLinkCSS(inactiveCSS); + curriculumShow.setIconLeftCSS("o_icon o_icon_toggle"); + curriculumShow.setIconRightCSS(null); + + curriculumHide = LinkFactory.createLink("on", content, this); + curriculumHide.setCustomEnabledLinkCSS(activeCSS); + curriculumHide.setIconLeftCSS(null); + curriculumHide.setIconRightCSS("o_icon o_icon_toggle"); + + showCurriculumStructure(ureq); + } else { + hideCurriculumStructure(ureq); + } + + putInitialPanel(content); + } + + @Override + public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) { + if(entries != null && !entries.isEmpty()) { + ContextEntry currentEntry = entries.get(0); + String cmd = currentEntry.getOLATResourceable().getResourceableTypeName(); + + Activateable2 selectedCtrl; + + if (cmd.equals(WITHOUT_CURRICULM)) { + selectedCtrl = hideCurriculumStructure(ureq); + } else { + selectedCtrl = showCurriculumStructure(ureq); + } + + List<ContextEntry> subEntries = entries.subList(1, entries.size()); + selectedCtrl.activate(ureq, subEntries, currentEntry.getTransientState()); + } + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if (source == curriculumHide) { + hideCurriculumStructure(ureq); + } else if (source == curriculumShow) { + showCurriculumStructure(ureq); + } + } + + @Override + public void event(Event event) { + // + } + + @Override + protected void doDispose() { + // + } + + public Activateable2 showCurriculumStructure(UserRequest ureq) { + showCurriculum = true; + + if (certificateCurriculumListController == null) { + WindowControl bwControl = addToHistory(ureq, OresHelper.createOLATResourceableType(WITH_CURRICULUM), null); + certificateCurriculumListController = new CertificateAndEfficiencyStatementCurriculumListController(ureq, bwControl, stackPanel, mentee, curriculumSecurityCallback, roleSecurityCallback); + listenTo(certificateCurriculumListController); + } + + content.contextPut("showCurriculum", showCurriculum); + content.put("content", certificateCurriculumListController.getInitialComponent()); + addToHistory(ureq, certificateCurriculumListController); + return certificateCurriculumListController; + } + + public Activateable2 hideCurriculumStructure(UserRequest ureq) { + showCurriculum = false; + + if (certificateListController == null) { + WindowControl bwControl = addToHistory(ureq, OresHelper.createOLATResourceableType(WITHOUT_CURRICULM), null); + certificateListController = new CertificateAndEfficiencyStatementListController(ureq, bwControl, mentee, false, false, false, false); + certificateListController.setBreadcrumbPanel(stackPanel); + listenTo(certificateListController); + } + + content.contextPut("showCurriculum", showCurriculum); + content.put("content", certificateListController.getInitialComponent()); + addToHistory(ureq, certificateListController); + return certificateListController; + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementCompositeRenderer.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementCompositeRenderer.java similarity index 91% rename from src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementCompositeRenderer.java rename to src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementCompositeRenderer.java index faa5c548d66e32b362092f4bdd9eecdb0b1a1e4c..0eb0d0b469eeaa009362140b4a1a1d6346eef9e1 100644 --- a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementCompositeRenderer.java +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementCompositeRenderer.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.coach.ui.curriculum; +package org.olat.modules.coach.ui.curriculum.certificate; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; @@ -42,7 +42,7 @@ public class CurriculumElementCompositeRenderer extends StaticFlexiCellRenderer @Override public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, URLBuilder ubu, Translator translator) { - CurriculumElementWithViewsRow view = (CurriculumElementWithViewsRow)source.getFlexiTableElement().getTableDataModel().getObject(row); + CurriculumTreeWithViewsRow view = (CurriculumTreeWithViewsRow)source.getFlexiTableElement().getTableDataModel().getObject(row); if(view.isCurriculumElementOnly()) { getLabelDelegate().render(renderer, target, cellValue, row, source, ubu, translator); } else { diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementViewsRowComparator.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementViewsRowComparator.java new file mode 100644 index 0000000000000000000000000000000000000000..49c16a44a8b08c7edbc1d1ef04c22132899ffec4 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementViewsRowComparator.java @@ -0,0 +1,227 @@ +/** + * <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.coach.ui.curriculum.certificate; + +import java.text.Collator; +import java.util.Locale; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeNodeComparator; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeTableNode; + +/** + * Compare and reorder a tree like structure by compare the + * rows and their parents. + * + * Initial date: 26 juin 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * @author aboeckle, alexander.boeckle@frentix.com + * + */ +public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator { + + private final Collator collator; + + public CurriculumElementViewsRowComparator(Locale locale) { + collator = Collator.getInstance(locale); + } + + @Override + protected int compareNodes(FlexiTreeTableNode o1, FlexiTreeTableNode o2) { + if(o1 == null || o2 == null) { + return compareNullObjects(o1, o2); + } + + CurriculumTreeWithViewsRow c1 = (CurriculumTreeWithViewsRow)o1; + CurriculumTreeWithViewsRow c2 = (CurriculumTreeWithViewsRow)o2; + CurriculumKey parentKey1 = c1.getParentKey(); + CurriculumKey parentKey2 = c2.getParentKey(); + + int c = 0; + if(parentKey1 == null && parentKey2 == null) { + c = compareCurricula(c1, c2); + } else if(parentKey1 != null && parentKey1.equals(parentKey2)) { + c = compareSameParent(c1, c2); + } else if(parentKey1 != null && !parentKey1.equals(parentKey2)) { + System.out.println(parentKey1 + " " + parentKey2); + c = compareCurricula(c1, c2); + } else if(parentKey1 != null && parentKey2 != null) { + // This case is usually not possible + CurriculumTreeWithViewsRow p1 = c1.getParent(); + CurriculumTreeWithViewsRow p2 = c2.getParent(); + if(p1 == null || p2 == null) { + // reversed because no parent at the top, higher in the hierarchy + c = -compareNullObjects(p1, p2); + } else { + c = compareCurriculumElements(p1, p2); + } + } else { + // This case is usually not possible + c = compareDisplayName(c1, c2); + } + + if(c == 0) { + c = Integer.compare(c1.getKey().hashCode(), c2.getKey().hashCode()); + } + return c; + } + + private int compareCurricula(CurriculumTreeWithViewsRow c1, CurriculumTreeWithViewsRow c2) { + int c = 0; + + if(c1.getCurriculumElementDisplayName() == null || c2.getCurriculumElementDisplayName() == null) { + c = compareNullObjects(c1.getCurriculumElementDisplayName(), c2.getCurriculumElementDisplayName()); + } else { + c = collator.compare(c1.getCurriculumElementDisplayName(), c2.getCurriculumElementDisplayName()); + } + + if(c == 0) { + if(c1.getCurriculumElementIdentifier() == null || c2.getCurriculumElementIdentifier() == null) { + c = compareNullObjects(c1.getCurriculumElementIdentifier(), c2.getCurriculumElementIdentifier()); + } else { + c = collator.compare(c1.getCurriculumElementIdentifier(), c2.getCurriculumElementIdentifier()); + } + } + + if (c == 0) { + if (c1.getKey().isWithoutCurriculum() && !c2.getKey().isWithoutCurriculum()) { + c = -1; + } else if (c1.getKey().isWithoutCurriculum() && c2.getKey().isWithoutCurriculum()) { + c = collator.compare(c1.getRepositoryEntryDisplayName(), c2.getRepositoryEntryDisplayName()); + } + } + + if (c == 0) { + if (c1.getKey().isWithoutCurriculum() && c2.getKey().isWithoutCurriculum()) { + c = Long.compare(c1.getRepositoryEntryKey(), c2.getRepositoryEntryKey()); + } else { + c = Long.compare(c1.getCurriculumKey(), c2.getCurriculumKey()); + } + } + + return c; + } + + private int compareSameParent(CurriculumTreeWithViewsRow c1, CurriculumTreeWithViewsRow c2) { + int c = 0; + if((c1.isCurriculumElementOnly() || c1.isCurriculumElementWithEntry()) && (c2.isCurriculumElementOnly() || c2.isCurriculumElementWithEntry())) { + // compare by position + c = compareCurriculumElements(c1, c2); + } else if(c1.isCurriculumElementOnly() || c1.isCurriculumElementWithEntry()) { + c = 1; + } else if(c2.isCurriculumElementOnly() || c2.isCurriculumElementWithEntry()) { + c = -1; + } else { + c = compareRepositoryEntry(c1, c2); + } + return c; + } + + private int compareCurriculumElements(CurriculumTreeWithViewsRow c1, CurriculumTreeWithViewsRow c2) { + int c = compareClosed(c1, c2); + + if(c == 0) { + if(c1.getCurriculumElementBeginDate() == null || c2.getCurriculumElementBeginDate() == null) { + c = compareNullObjects(c1.getCurriculumElementBeginDate(), c2.getCurriculumElementBeginDate()); + } else { + c = c1.getCurriculumElementBeginDate().compareTo(c2.getCurriculumElementBeginDate()); + } + } + + if(c == 0) { + if(c1.getCurriculumElementDisplayName() == null || c2.getCurriculumElementDisplayName() == null) { + c = compareNullObjects(c1.getCurriculumElementDisplayName(), c2.getCurriculumElementDisplayName()); + } else { + c = collator.compare(c1.getCurriculumElementDisplayName(), c2.getCurriculumElementDisplayName()); + } + } + + if(c == 0) { + if(c1.getCurriculumElementIdentifier() == null || c2.getCurriculumElementIdentifier() == null) { + c = compareNullObjects(c1.getCurriculumElementIdentifier(), c2.getCurriculumElementIdentifier()); + } else { + c = collator.compare(c1.getCurriculumElementIdentifier(), c2.getCurriculumElementIdentifier()); + } + } + + if(c == 0) { + + c = Long.compare(c1.getCurriculumElementKey().longValue(), c2.getCurriculumElementKey().longValue()); + } + return c; + } + + private int compareRepositoryEntry(CurriculumTreeWithViewsRow c1, CurriculumTreeWithViewsRow c2) { + int c = compareClosed(c1, c2); + + if(c == 0) { + if(c1.getRepositoryEntryDisplayName() == null || c2.getRepositoryEntryDisplayName() == null) { + c = compareNullObjects(c1.getRepositoryEntryDisplayName(), c2.getRepositoryEntryDisplayName()); + } else { + c = collator.compare(c1.getRepositoryEntryDisplayName(), c2.getRepositoryEntryDisplayName()); + } + } + + if(c == 0) { + if(c1.getRepositoryEntryExternalRef() == null || c2.getRepositoryEntryExternalRef() == null) { + c = compareNullObjects(c1.getRepositoryEntryExternalRef(), c2.getRepositoryEntryExternalRef()); + } else { + c = collator.compare(c1.getRepositoryEntryExternalRef(), c2.getRepositoryEntryExternalRef()); + } + } + + if(c == 0) { + c = Long.compare(c1.getRepositoryEntryKey().longValue(), c2.getRepositoryEntryKey().longValue()); + } + return c; + } + + private int compareClosed(CurriculumTreeWithViewsRow c1, CurriculumTreeWithViewsRow c2) { + int c = 0; + if(c1.isClosedOrInactive() && !c2.isClosedOrInactive()) { + c = 1; + } else if(!c1.isClosedOrInactive() && c2.isClosedOrInactive()) { + c = -1; + } + return c; + } + + private int compareDisplayName(CurriculumTreeWithViewsRow c1, CurriculumTreeWithViewsRow c2) { + String d1 = getDisplayName(c1); + String d2 = getDisplayName(c2); + if(d1 == null || d2 == null) { + return compareNullObjects(d1, d2); + } + return d1.compareTo(d2); + } + + private String getDisplayName(CurriculumTreeWithViewsRow row) { + if(row.isCurriculumElementOnly()) { + return row.getCurriculumElementDisplayName(); + } + if(row.isRepositoryEntryOnly()) { + return row.getRepositoryEntryDisplayName(); + } + String d = row.getRepositoryEntryDisplayName(); + if(d == null) { + d = row.getCurriculumElementDisplayName(); + } + return d; + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementWithViewsDataModel.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementWithViewsDataModel.java new file mode 100644 index 0000000000000000000000000000000000000000..139c90cab922b73e805a36601195be9ff90eb2d3 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumElementWithViewsDataModel.java @@ -0,0 +1,302 @@ +/** + * <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.coach.ui.curriculum.certificate; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentMap; + +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTreeTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiBusinessPathModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.course.certificate.CertificateLight; +import org.olat.modules.coach.model.EfficiencyStatementEntry; +import org.olat.modules.coach.model.IdentityRepositoryEntryKey; +import org.olat.modules.coach.model.IdentityResourceKey; +import org.olat.modules.coach.ui.ProgressValue; +import org.olat.modules.curriculum.CurriculumElementStatus; +import org.olat.modules.lecture.model.LectureBlockStatistics; + +/** + * + * Initial date: 11 mai 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CurriculumElementWithViewsDataModel extends DefaultFlexiTreeTableDataModel<CurriculumTreeWithViewsRow> implements FlexiBusinessPathModel { + + private ConcurrentMap<IdentityResourceKey, CertificateLight> certificateMap; + private ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesStatisticsMap; + + public CurriculumElementWithViewsDataModel(FlexiTableColumnModel columnsModel) { + super(columnsModel); + } + + @Override + public void filter(String searchString, List<FlexiTableFilter> filters) { + if(filters != null && !filters.isEmpty() && filters.get(0) != null) { + FlexiTableFilter filter = filters.get(0); + if(filter == null || filter.isShowAll()) { + setUnfilteredObjects(); + } else { + List<CurriculumTreeWithViewsRow> filteredRows = new ArrayList<>(backupRows.size()); + // curriculum element inactive -> all repo are inactives + // parent inactive, child is active -> parent is forced active + for(CurriculumTreeWithViewsRow row:backupRows) { + if (filters.get(0).getFilter().equals(FilterKeys.activ.name())) { + boolean accept = active(row); + if(accept) { + filteredRows.add(row); + } + } else if (filters.get(0).getFilter().equals(FilterKeys.withStatementOnly.name())) { + if (row.hasStatement()) { + filteredRows.add(row); + } + } + + } + setFilteredObjects(filteredRows); + } + } else { + setUnfilteredObjects(); + } + } + + private boolean active(CurriculumTreeWithViewsRow row) { + boolean active = true; + if(row.isCurriculumElementOnly() || row.isCurriculumElementWithEntry()) { + active = row.getCurriculumElementStatus() == CurriculumElementStatus.active; + } + if(active) { + for(CurriculumTreeWithViewsRow parent = row.getParent(); parent != null; parent=parent.getParent()) { + if(parent.isCurriculumElementOnly() || parent.isCurriculumElementWithEntry()) { + active &= row.getCurriculumElementStatus() == CurriculumElementStatus.active; + } + } + } + return active; + } + + @Override + public boolean hasChildren(int row) { + CurriculumTreeWithViewsRow element = getObject(row); + return element.hasChildren(); + } + + @Override + public Object getValueAt(int row, int col) { + CurriculumTreeWithViewsRow curriculum = getObject(row); + switch(ElementViewCols.values()[col]) { + case key: return curriculum.getKey(); + case displayName: + return curriculum.getDisplayName(); + case hasStatement: + return curriculum.hasStatement(); + case identifier: { + String identifier; + if(curriculum.isRepositoryEntryOnly()) { + identifier = curriculum.getRepositoryEntryExternalRef(); + } else { + identifier = curriculum.getCurriculumElementIdentifier(); + } + return identifier; + } + case mark: return curriculum.getMarkLink(); + case select: return curriculum.getSelectLink(); + case details: return curriculum.getDetailsLink(); + case start: return curriculum.getStartLink(); + case calendars: return curriculum.getCalendarsLink(); + case completion: return curriculum.getCompletionItem(); + case score: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getScore() : null; + case passed: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getPassed() : null; + case certificate: return getCertificate(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + case recertification: { + CertificateLight certificate = getCertificate(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return certificate == null ? null : certificate.getNextRecertificationDate(); + } + case numberAssessments: { + ProgressValue val = null; + Integer totalNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getTotalNodes() : null; + if (totalNodes != null && totalNodes.intValue() > 0) { + val = new ProgressValue(); + val.setTotal(totalNodes.intValue()); + Integer attemptedNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getAttemptedNodes() : null; + val.setGreen(attemptedNodes == null ? 0 : attemptedNodes.intValue()); + } + return val; + } + case progress: { + Integer totalNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getTotalNodes() : null; + if(totalNodes == null) { + ProgressValue val = new ProgressValue(); + val.setTotal(100); + val.setGreen(0); + return val; + } + + ProgressValue val = new ProgressValue(); + val.setTotal(totalNodes.intValue()); + Integer attemptedNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getAttemptedNodes() : null; + val.setGreen(attemptedNodes == null ? 0 : attemptedNodes.intValue()); + return val; + } + case lastModification: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getLastModified() : null; + case lastUserModified: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getLastUserModified() : null; + case lastCoachModified: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getLastCoachModified() : null; + case plannedLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalPersonalPlannedLectures(); + } + case attendedLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalAttendedLectures(); + } + case unauthorizedAbsenceLectures: + case absentLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalAbsentLectures(); + } + case authorizedAbsenceLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalAuthorizedAbsentLectures(); + } + case efficiencyStatement: + return curriculum.getEfficiencyStatementEntry() != null; + default: return "ERROR"; + } + } + + private CertificateLight getCertificate(EfficiencyStatementEntry entry) { + if(certificateMap != null) { + IdentityResourceKey key = new IdentityResourceKey(entry.getIdentityKey(), entry.getCourse().getOlatResource().getKey()); + return certificateMap.get(key); + } + return null; + } + + private LectureBlockStatistics getLectureBlockStatistics(EfficiencyStatementEntry entry) { + if(lecturesStatisticsMap != null) { + IdentityRepositoryEntryKey key = new IdentityRepositoryEntryKey(entry); + return lecturesStatisticsMap.get(key); + } + return null; + } + + public void setObjects(List<CurriculumTreeWithViewsRow> objects, ConcurrentMap<IdentityResourceKey, CertificateLight> certificates) { + setObjects(objects, certificates, null); + } + + public void setObjects(List<CurriculumTreeWithViewsRow> objects, + ConcurrentMap<IdentityResourceKey, CertificateLight> certificates, + ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesStatisticsMap) { + setObjects(objects); + this.certificateMap = certificates; + this.lecturesStatisticsMap = lecturesStatisticsMap; + } + + @Override + public CurriculumElementWithViewsDataModel createCopyWithEmptyList() { + return new CurriculumElementWithViewsDataModel(getTableColumnModel()); + } + + public enum ElementViewCols implements FlexiSortableColumnDef { + key("table.header.key"), + displayName("table.header.curriculum.element.displayName"), + hasStatement("table.header.curriculum.element.has.statement"), + identifier("table.header.curriculum.element.identifier"), + mark("table.header.mark"), + select("table.header.displayName"), + completion("table.header.completion"), + details("table.header.details"), + start("table.header.start"), + calendars("table.header.calendars"), + score("table.header.score"), + passed("table.header.passed"), + certificate("table.header.certificate"), + recertification("table.header.recertification"), + numberAssessments("table.header.number.assessments"), + progress("table.header.progress"), + lastModification("table.header.lastScoreDate"), + lastUserModified("table.header.lastUserModificationDate"), + lastCoachModified("table.header.lastCoachModificationDate"), + plannedLectures("table.header.planned.lectures"), + attendedLectures("table.header.attended.lectures"), + absentLectures("table.header.absent.lectures"), + unauthorizedAbsenceLectures("table.header.unauthorized.absence"), + authorizedAbsenceLectures("table.header.authorized.absence"), + efficiencyStatement("table.header.show"), + deleteEfficiencyStatement("table.action.delete"), + artefact("table.header.artefact"); + + private final String i18nHeaderKey; + + private ElementViewCols(String i18nHeaderKey) { + this.i18nHeaderKey = i18nHeaderKey; + } + + @Override + public boolean sortable() { + return false; + } + + @Override + public String sortKey() { + return name(); + } + + @Override + public String i18nHeaderKey() { + return i18nHeaderKey; + } + } + + @Override + public String getUrl(Component source, Object object, String action) { + if("select".equals(action) && object instanceof CurriculumTreeWithViewsRow) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow)object; + if(row.getStartUrl() != null) { + return row.getStartUrl(); + } + if(row.getDetailsUrl() != null) { + return row.getDetailsUrl(); + } + } + return null; + } + + public enum FilterKeys { + activ("filter.activ"), + withStatementOnly("filter.with.statement.only"), + showAll("show.all"); + + private final String i18nHeaderKey; + + private FilterKeys(String i18nHeaderKey) { + this.i18nHeaderKey = i18nHeaderKey; + } + + public String i18nHeaderKey() { + return i18nHeaderKey; + } + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumKey.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumKey.java new file mode 100644 index 0000000000000000000000000000000000000000..ca48298d63dfbaaecb82a8bb17fee7511e2c5554 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumKey.java @@ -0,0 +1,76 @@ +package org.olat.modules.coach.ui.curriculum.certificate; + +public class CurriculumKey { + private final Long curriculum; + private final Long curriculumElement; + private final boolean isWithoutCurriculum; + + public CurriculumKey(Long curriculum, Long curriculumElement) { + this(curriculum, curriculumElement, false); + } + + public CurriculumKey(Long curriculum, Long curriculumElement, boolean isWithoutCurriculum) { + this.curriculum = curriculum; + this.curriculumElement = curriculumElement; + this.isWithoutCurriculum = isWithoutCurriculum; + } + + public Long getCurriculum() { + return curriculum; + } + + public Long getCurriculumElement() { + return curriculumElement; + } + + public boolean isWithoutCurriculum() { + return this.isWithoutCurriculum; + } + + @Override + public String toString() { + return "CurriculumKey[" + + "curriculum=" + curriculum + + ", curriculumElement=" + curriculumElement + + ']'; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj instanceof CurriculumKey) { + CurriculumKey compareKey = (CurriculumKey) obj; + boolean equals = true; + + // Compare curriculum + if ((curriculum == null && compareKey.getCurriculum() != null) + || (curriculum != null && compareKey.getCurriculum() == null)) { + equals = false; + } else if ((curriculum != null && compareKey.getCurriculum() != null) + && (!curriculum.equals(compareKey.getCurriculum()))) { + equals = false; + } + + // Compare curriculumElement + if ((curriculumElement == null && compareKey.getCurriculumElement() != null) + || (curriculumElement != null && compareKey.getCurriculumElement() == null)) { + equals = false; + } else if ((curriculumElement != null && compareKey.getCurriculumElement() != null) + && (!curriculumElement.equals(compareKey.getCurriculumElement()))) { + equals = false; + } + + return equals; + } else { + return false; + } + } + + @Override + public int hashCode() { + return (curriculum == null ? 890112 : curriculum.hashCode()) + (curriculumElement == null ? 312739 : curriculumElement.hashCode()); + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumTreeWithView.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumTreeWithView.java new file mode 100644 index 0000000000000000000000000000000000000000..9a47e482353f5406cf1294b1a76b554721be3659 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumTreeWithView.java @@ -0,0 +1,56 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.coach.ui.curriculum.certificate; + +import java.util.List; + +import org.olat.repository.RepositoryEntryMyView; + +/** + * + * Initial date: 8 Oct 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public interface CurriculumTreeWithView { + + public boolean isCurriculumMember(); + + public CurriculumTreeWithView getParent(); + + public List<RepositoryEntryMyView> getEntries(); + + public CurriculumKey getKey(); + + public default boolean isParentOrSelf(CurriculumTreeWithView parent) { + boolean hasParent = false; + + if(getKey().equals(parent.getKey())) { + hasParent = true; + } else { + for(CurriculumTreeWithView parentRow = getParent(); parentRow != null; parentRow=parentRow.getParent()) { + if(parentRow.getKey().equals(parent.getKey())) { + hasParent = true; + } + } + } + return hasParent; + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumTreeWithViewsRow.java b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumTreeWithViewsRow.java new file mode 100644 index 0000000000000000000000000000000000000000..6392755d53071e93b0168f7d4544a1cf5a4bda8d --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/CurriculumTreeWithViewsRow.java @@ -0,0 +1,764 @@ +/** + * <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.coach.ui.curriculum.certificate; + +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.olat.core.gui.components.form.flexible.elements.FormLink; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTreeTableNode; +import org.olat.core.gui.components.progressbar.ProgressBarItem; +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.StringHelper; +import org.olat.core.util.filter.FilterFactory; +import org.olat.course.assessment.AssessmentHelper; +import org.olat.course.certificate.ui.CertificateAndEfficiencyStatementListModel; +import org.olat.modules.coach.model.EfficiencyStatementEntry; +import org.olat.modules.curriculum.Curriculum; +import org.olat.modules.curriculum.CurriculumCalendars; +import org.olat.modules.curriculum.CurriculumElement; +import org.olat.modules.curriculum.CurriculumElementMembership; +import org.olat.modules.curriculum.CurriculumElementStatus; +import org.olat.modules.curriculum.CurriculumElementType; +import org.olat.modules.curriculum.CurriculumLearningProgress; +import org.olat.repository.RepositoryEntryMyView; +import org.olat.repository.RepositoryEntryStatusEnum; +import org.olat.repository.ui.PriceMethod; +import org.olat.repository.ui.RepositoyUIFactory; +import org.olat.resource.OLATResource; + +/** + * + * Initial date: 14 févr. 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CurriculumTreeWithViewsRow implements CurriculumTreeWithView, FlexiTreeTableNode { + + private boolean hasChildren; + private CurriculumTreeWithViewsRow parent; + + private CurriculumKey parentKey; + private CurriculumKey key; + + private final Curriculum curriculum; + private final CurriculumElement element; + private final CurriculumElementType elementType; + private final CurriculumElementMembership curriculumMembership; + private boolean curriculumMember; + private int level; + + private boolean singleEntry; + private int elementEntryCount; + private OLATResource olatResource; + private RepositoryEntryMyView repositoryEntry; + + private String shortenedDescription; + private String representationalName; + + private RepositoryEntryStatusEnum status; + private boolean guests; + private boolean allUsers; + private boolean bookable; + private List<PriceMethod> accessTypes; + + private boolean member; + private String thumbnailRelPath; + private boolean marked; + + private String startUrl; + private String detailsUrl; + + private FormLink startLink; + private FormLink detailsLink; + private FormLink markLink; + private FormLink selectLink; + private FormLink calendarsLink; + private ProgressBarItem completionItem; + + private EfficiencyStatementEntry efficiencyStatementEntry; + private CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement certificateAndEfficiencyStatement; + private boolean hasStatement; + + public CurriculumTreeWithViewsRow(Curriculum curriculum, CurriculumElement element, CurriculumElementMembership curriculumMembership, int myEntryCount) { + this.element = element; + elementType = element.getType(); + this.curriculumMembership = curriculumMembership; + curriculumMember = curriculumMembership != null && curriculumMembership.hasMembership(); + singleEntry = false; + elementEntryCount = myEntryCount; + this.curriculum = curriculum; + setKey(); + setParentKey(); + setShortenedDescription(element.getDescription()); + + // calculate level of current curr element based on parent chain + for(CurriculumElement parentEl=element.getParent(); parentEl != null; parentEl=parentEl.getParent()) { + level++; + } + } + + public CurriculumTreeWithViewsRow(Curriculum curriculum) { + this.curriculum = curriculum; + parentKey = null; + element = null; + elementType = null; + curriculumMembership = null; + curriculumMember = true; + level = -1; + setKey(); + } + + /** + * Used to show the head parent of elements without any curriculum + * @param representationalName + */ + public CurriculumTreeWithViewsRow(String representationalName) { + this.representationalName = representationalName; + curriculum = null; + parentKey = null; + element = null; + elementType = null; + curriculumMembership = null; + curriculumMember = false; + level = -1; + setKey(); + } + + /** + * Used to show elements without any curriculum + * @param repositoryEntryView + */ + public CurriculumTreeWithViewsRow(RepositoryEntryMyView repositoryEntryView) { + guests = repositoryEntryView.isGuests(); + allUsers = repositoryEntryView.isAllUsers(); + bookable = repositoryEntryView.isBookable(); + status = repositoryEntryView.getEntryStatus(); + repositoryEntry = repositoryEntryView; + olatResource = repositoryEntryView.getOlatResource(); + marked = repositoryEntryView.isMarked(); + setShortenedDescription(repositoryEntryView.getDescription()); + + curriculum = null; + parentKey = null; + element = null; + elementType = null; + curriculumMembership = null; + curriculumMember = false; + level = 0; + setKey(true); + } + + public CurriculumTreeWithViewsRow(CertificateAndEfficiencyStatementListModel.CertificateAndEfficiencyStatement statement) { + this.certificateAndEfficiencyStatement = statement; + + setShortenedDescription(statement.getDisplayName()); + setKey(true); + + curriculum = null; + parentKey = null; + element = null; + elementType = null; + curriculumMembership = null; + curriculumMember = false; + level = 0; + } + + public CurriculumTreeWithViewsRow(Curriculum curriculum, CurriculumElement element, CurriculumElementMembership curriculumMembership, + RepositoryEntryMyView repositoryEntryView, boolean alone) { + this.element = element; + elementType = element == null ? null : element.getType(); + this.curriculumMembership = curriculumMembership; + curriculumMember = curriculumMembership != null && curriculumMembership.hasMembership(); + singleEntry = alone; + elementEntryCount = 0; + + Long parentElementKey; + Long parentCurriculumKey = curriculum != null ? curriculum.getKey() : null; + + if(alone) { + parentElementKey = element != null && element.getParent() != null ? element.getParent().getKey() : null; + } else { + parentElementKey = element == null ? null : element.getKey(); + // add ourself as level + level++; + } + parentKey = new CurriculumKey(parentCurriculumKey, parentElementKey); + setKey(); + + guests = repositoryEntryView.isGuests(); + allUsers = repositoryEntryView.isAllUsers(); + bookable = repositoryEntryView.isBookable(); + status = repositoryEntryView.getEntryStatus(); + repositoryEntry = repositoryEntryView; + olatResource = repositoryEntryView.getOlatResource(); + marked = repositoryEntryView.isMarked(); + setShortenedDescription(repositoryEntryView.getDescription()); + + // calculate level of current curr element based on parent chain + for(CurriculumElement parentEl=element.getParent(); parentEl != null; parentEl=parentEl.getParent()) { + level++; + } + + this.curriculum = curriculum; + } + + @Override + public CurriculumKey getKey() { + return this.key; + } + + public boolean isActive() { + if(element != null) { + return element.getElementStatus() == null + || element.getElementStatus() == CurriculumElementStatus.active; + } + return true; + } + + public Curriculum getCurriculum() { + return curriculum; + } + + public String getDisplayName() { + if(repositoryEntry != null) { + return repositoryEntry.getDisplayname(); + } else if(element != null) { + return element.getDisplayName(); + } else if (curriculum != null) { + return curriculum.getDisplayName(); + } else if (certificateAndEfficiencyStatement != null) { + return certificateAndEfficiencyStatement.getDisplayName(); + } else if (representationalName != null) { + return representationalName; + } + return null; + } + + public boolean isCurriculum() { + return curriculum != null && element == null && repositoryEntry == null && parentKey == null; + } + + public boolean isCurriculumElementOnly() { + return element != null && repositoryEntry == null; + } + + public boolean isRepositoryEntryOnly() { + return element != null && repositoryEntry != null && !singleEntry; + } + + public boolean isCurriculumElementWithEntry() { + return element != null && repositoryEntry != null && singleEntry; + } + + public String getCurriculumElementIdentifier() { + if ((repositoryEntry == null || singleEntry) && element != null) { + return element.getIdentifier(); + } else if (isCurriculum()) { + return curriculum.getIdentifier(); + } else { + return null; + } + } + + public String getCurriculumElementExternalId() { + return element == null ? null : element.getExternalId(); + } + + public CurriculumElementStatus getCurriculumElementStatus() { + return element == null ? null : element.getElementStatus(); + } + + public String getCurriculumElementDisplayName() { + if ((representationalName == null || singleEntry) && element != null) { + return element.getDisplayName(); + } else if (isCurriculum()) { + return curriculum.getDisplayName(); + } else if (repositoryEntry != null) { + return repositoryEntry.getDisplayname(); + } else if (representationalName != null) { + return representationalName; + } else { + return null; + } + } + + public Long getCurriculumKey() { + return curriculum == null ? null : curriculum.getKey(); + } + + public Long getCurriculumElementKey() { + return element == null ? null : element.getKey(); + } + + public Date getCurriculumElementBeginDate() { + return element == null ? null : element.getBeginDate(); + } + + public Date getCurriculumElementEndDate() { + return element == null ? null : element.getEndDate(); + } + + public Long getCurriculumElementPos() { + return element == null ? null : element.getPos(); + } + + public String getCurriculumElementTypeCssClass() { + return elementType == null ? null : element.getType().getCssClass(); + } + + public String getCurriculumElementTypeName() { + return elementType == null ? null : element.getType().getDisplayName(); + } + + public boolean isCalendarsEnabled() { + boolean enabled = false; + if(element != null) { + if(element.getCalendars() == CurriculumCalendars.enabled) { + enabled = true; + } else if(element.getCalendars() == CurriculumCalendars.inherited && elementType != null) { + enabled = elementType.getCalendars() == CurriculumCalendars.enabled; + } + } + return enabled; + } + + public boolean isLearningProgressEnabled() { + boolean enabled = false; + if(element != null) { + if(element.getLearningProgress() == CurriculumLearningProgress.enabled) { + enabled = true; + } else if(element.getLearningProgress() == CurriculumLearningProgress.inherited && elementType != null) { + enabled = elementType.getLearningProgress() == CurriculumLearningProgress.enabled; + } + } + return enabled; + } + + public int getCurriculumElementRepositoryEntryCount() { + return elementEntryCount; + } + + public int getLevel() { + return level; + } + + + public String getExternalId() { + String extId = null; + if (element != null && element.getExternalId() != null) { + extId = element.getExternalId(); + } + if (repositoryEntry != null && repositoryEntry.getExternalId() != null) { + if (extId != null) { + extId += " "; + extId += repositoryEntry.getExternalId(); + } else { + extId += repositoryEntry.getExternalId(); + } + } + return extId; + } + + public String getMaterializedPathKeys() { + return element.getMaterializedPathKeys(); + } + + public String getShortenedDescription() { + return shortenedDescription; + } + + private void setShortenedDescription(String description) { + if(description != null) { + String shortDesc = FilterFactory.getHtmlTagsFilter().filter(description); + if(shortDesc.length() > 255) { + shortenedDescription = shortDesc.substring(0, 255); + } else { + shortenedDescription = shortDesc; + } + } else { + shortenedDescription = ""; + } + } + + private void setParentKey() { + Long curriculumKey = element != null && curriculum != null ? curriculum.getKey() : null; + Long curriculumElementParentKey = element != null && element.getParent() != null ? element.getParent().getKey() : null; + + parentKey = new CurriculumKey(curriculumKey, curriculumElementParentKey); + } + + private void setKey() { + Long curriculumKey = curriculum != null ? curriculum.getKey() : null; + Long curriculumElementKey = element != null ? element.getKey() : null; + + key = new CurriculumKey(curriculumKey, curriculumElementKey); + } + + private void setKey(boolean isWithoutCurriculum) { + key = new CurriculumKey(null, null, isWithoutCurriculum); + } + + public boolean isClosed() { + return status.decommissioned(); + } + + public boolean isSingleEntry() { + return singleEntry; + } + + public boolean isMarked() { + return marked; + } + + public void setMarked(boolean marked) { + this.marked = marked; + } + + public RepositoryEntryStatusEnum getEntryStatus() { + return status; + } + + public boolean isAllUsers() { + return allUsers; + } + + public boolean isGuests() { + return guests; + } + + public boolean isBookable() { + return bookable; + } + + public boolean isThumbnailAvailable() { + return StringHelper.containsNonWhitespace(thumbnailRelPath); + } + + public String getThumbnailRelPath() { + return thumbnailRelPath; + } + + public void setThumbnailRelPath(String thumbnailRelPath) { + this.thumbnailRelPath = thumbnailRelPath; + } + + public Long getRepositoryEntryKey() { + return repositoryEntry == null ? null : repositoryEntry.getKey(); + } + + public String getRepositoryEntryDisplayName() { + if (repositoryEntry != null) { + return repositoryEntry.getDisplayname(); + } else if (certificateAndEfficiencyStatement != null) { + return certificateAndEfficiencyStatement.getDisplayName(); + } else { + return null; + } + } + + public String getRepositoryEntryExternalRef() { + return repositoryEntry == null ? null : repositoryEntry.getExternalRef(); + } + + public String getRepositoryEntryCssClass() { + return olatResource == null ? "" : RepositoyUIFactory.getIconCssClass(olatResource.getResourceableTypeName()); + } + + public String getRepositoryEntryAuthors() { + return repositoryEntry == null ? null : repositoryEntry.getAuthors(); + } + + public String getRepositoryEntryLocation() { + return repositoryEntry == null ? null : repositoryEntry.getLocation(); + } + + public String getRepositoryEntryShortenedDescription() { + return repositoryEntry == null ? null : repositoryEntry.getDescription(); + } + + public Date getLifecycleStart() { + return repositoryEntry == null || repositoryEntry.getLifecycle() == null + ? null : repositoryEntry.getLifecycle().getValidFrom(); + } + + public Date getLifecycleEnd() { + return repositoryEntry == null || repositoryEntry.getLifecycle() == null + ? null : repositoryEntry.getLifecycle().getValidTo(); + } + + public String getLifecycleSoftKey() { + return repositoryEntry == null || repositoryEntry.getLifecycle() == null || repositoryEntry.getLifecycle().isPrivateCycle() + ? null : repositoryEntry.getLifecycle().getSoftKey(); + } + + public String getLifecycleLabel() { + return repositoryEntry == null || repositoryEntry.getLifecycle() == null || repositoryEntry.getLifecycle().isPrivateCycle() + ? null : repositoryEntry.getLifecycle().getLabel(); + } + + public String getScore() { + return repositoryEntry == null ? null : AssessmentHelper.getRoundedScore(repositoryEntry.getScore()); + } + + public boolean isPassed() { + return repositoryEntry == null || repositoryEntry.getPassed() == null + ? false : repositoryEntry.getPassed().booleanValue(); + } + + public boolean isFailed() { + return repositoryEntry == null || repositoryEntry.getPassed() == null + ? false : !repositoryEntry.getPassed().booleanValue(); + } + + public Double getRepositoryEntryCompletion() { + return repositoryEntry != null? repositoryEntry.getCompletion(): null; + } + + public OLATResourceable getRepositoryEntryResourceable() { + return repositoryEntry; + } + + public OLATResource getOlatResource() { + return olatResource; + } + + @Override + public List<RepositoryEntryMyView> getEntries() { + if(repositoryEntry == null) { + return Collections.emptyList(); + } + return Collections.singletonList(repositoryEntry); + } + + /** + * Is member if the row as some type of access control + * @return + */ + public boolean isMember() { + return member; + } + + public void setMember(boolean member) { + this.member = member; + } + + public CurriculumElementMembership getCurriculumMembership() { + return curriculumMembership; + } + + @Override + public boolean isCurriculumMember() { + return curriculumMember; + } + + public void setCurriculumMember(boolean curriculumMember) { + this.curriculumMember = curriculumMember; + } + + public List<PriceMethod> getAccessTypes() { + return accessTypes; + } + + public void setAccessTypes(List<PriceMethod> accessTypes) { + this.accessTypes = accessTypes; + } + + public boolean isClosedOrInactive() { + if(isCurriculumElementOnly()) { + return element.getElementStatus() == CurriculumElementStatus.inactive || element.getElementStatus() == CurriculumElementStatus.deleted; + } + if(isRepositoryEntryOnly()) { + return status != null && status.decommissioned(); + } + return (status != null && status.decommissioned()) + || (element != null && element.getElementStatus() != null + && (element.getElementStatus() == CurriculumElementStatus.inactive || element.getElementStatus() == CurriculumElementStatus.deleted)); + } + + @Override + public CurriculumTreeWithViewsRow getParent() { + return parent; + } + + public void setParent(CurriculumTreeWithViewsRow parent) { + this.parent = parent; + if(parent != null) { + parent.hasChildren = true; + } + } + + public boolean hasChildren() { + return hasChildren; + } + + public CurriculumKey getParentKey() { + return parentKey; + } + + public FormLink getMarkLink() { + return markLink; + } + + public String getMarkLinkName() { + if(markLink != null) { + return markLink.getComponent().getComponentName(); + } + return null; + } + + public void setMarkLink(FormLink markLink) { + this.markLink = markLink; + } + + public String getStartLinkName() { + return startLink == null ? null : startLink.getComponent().getComponentName(); + } + + public FormLink getStartLink() { + return startLink; + } + + public void setStartLink(FormLink startLink, String startURL) { + this.startLink = startLink; + this.startUrl = startURL; + } + + public String getStartUrl() { + return startUrl; + } + + public String getDetailsLinkName() { + return detailsLink == null ? null : detailsLink.getComponent().getComponentName(); + } + + public FormLink getDetailsLink() { + return detailsLink; + } + + public void setDetailsLink(FormLink detailsLink, String detailsURL) { + this.detailsLink = detailsLink; + this.detailsUrl = detailsURL; + } + + public String getDetailsUrl() { + return detailsUrl; + } + + public String getSelectLinkName() { + return selectLink == null ? null : selectLink.getComponent().getComponentName(); + } + + public FormLink getSelectLink() { + return selectLink; + } + + public void setSelectLink(FormLink selectLink) { + this.selectLink = selectLink; + } + + public FormLink getCalendarsLink() { + return calendarsLink; + } + + public void setCalendarsLink(FormLink calendarsLink) { + this.calendarsLink = calendarsLink; + } + + public String getCalendarsLinkName() { + return calendarsLink == null ? null : calendarsLink.getComponent().getComponentName(); + } + + public ProgressBarItem getCompletionItem() { + return completionItem; + } + + public void setCompletionItem(ProgressBarItem completionItem) { + this.completionItem = completionItem; + } + + public String getCompletionItemName() { + return completionItem == null ? null : completionItem.getComponent().getComponentName(); + } + + public EfficiencyStatementEntry getEfficiencyStatementEntry() { + return this.efficiencyStatementEntry; + } + + public void setEfficiencyStatementEntry(EfficiencyStatementEntry efficiencyStatementEntry) { + this.efficiencyStatementEntry = efficiencyStatementEntry; + } + + public boolean hasStatement() { + return hasStatement; + } + + public void setHasStatement(boolean hasStatement) { + if (parent != null) { + parent.setHasStatement(true); + } + this.hasStatement = hasStatement; + } + + @Override + public String getCrump() { + return element.getDisplayName(); + } + + @Override + public int hashCode() { + return (element == null ? 73465971 : element.getKey().hashCode()) + + (repositoryEntry == null ?-3726247 : repositoryEntry.getKey().hashCode()); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof CurriculumTreeWithViewsRow) { + CurriculumTreeWithViewsRow row = (CurriculumTreeWithViewsRow)obj; + return ((element == null && row.element == null && curriculum!= null && row.curriculum != null && curriculum.getKey().equals(row.curriculum.getKey())) + || (element != null && row.element != null && element.getKey().equals(row.element.getKey()))) + && ((repositoryEntry == null && row.repositoryEntry == null) + || (repositoryEntry != null && row.repositoryEntry != null && repositoryEntry.getKey().equals(row.repositoryEntry.getKey()))); + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if(isCurriculumElementOnly()) { + sb.append("element[key").append(element.getKey()).append(":identifier=").append(element.getIdentifier()).append("]"); + } else if(isRepositoryEntryOnly()) { + sb.append("repositoryEntry[key").append(repositoryEntry.getKey()).append(":identifier=").append(repositoryEntry.getExternalRef()).append("]"); + } else if(isCurriculumElementWithEntry()) { + sb.append("composite[key").append(element.getKey()).append(":identifier=").append(element.getIdentifier()).append("]") + .append("entry[key").append(repositoryEntry.getKey()).append(":identifier=").append(repositoryEntry.getExternalRef()).append("]"); + } else if(isCurriculum()) { + sb.append("curriculum[key").append(curriculum.getKey()).append(":identifier=").append(curriculum.getIdentifier()).append("]"); + } + + return sb.toString(); + } + +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/_content/course_list_wrapper.html b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_content/certificate_list_wrapper.html similarity index 100% rename from src/main/java/org/olat/modules/coach/ui/curriculum/_content/course_list_wrapper.html rename to src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_content/certificate_list_wrapper.html diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/_content/curriculum_element_list.html b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_content/curriculum_element_list.html similarity index 100% rename from src/main/java/org/olat/modules/coach/ui/curriculum/_content/curriculum_element_list.html rename to src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_content/curriculum_element_list.html diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/_content/curriculum_list.html b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_content/curriculum_list.html similarity index 100% rename from src/main/java/org/olat/modules/coach/ui/curriculum/_content/curriculum_list.html rename to src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_content/curriculum_list.html diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_i18n/LocalStrings_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..87a51a349088f79cb84addae67475bb1435634da --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_i18n/LocalStrings_de.properties @@ -0,0 +1,4 @@ +curriculum.foreign.entries=Sonstige Kurse +curriculum.toggle.description=Curriculum-Struktur anzeigen +filter.with.statement.only=Nur mit Leistungsnachweis +filter.activ=Nur aktiv diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_i18n/LocalStrings_en.properties new file mode 100644 index 0000000000000000000000000000000000000000..75ff302635bd7a30ed7ccb6ad04a608b350f42d0 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/certificate/_i18n/LocalStrings_en.properties @@ -0,0 +1,4 @@ +curriculum.foreign.entries=Other courses +curriculum.toggle.description=Show curriculum structure +filter.with.statement.only=With efficiency statement only +filter.activ=Only active diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementWithViewsRow.java b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CourseCurriculumTreeWithViewsRow.java similarity index 92% rename from src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementWithViewsRow.java rename to src/main/java/org/olat/modules/coach/ui/curriculum/course/CourseCurriculumTreeWithViewsRow.java index d09fedba7228e48adc726e22ebce31f0e5543b81..e215e7b57be3eaa42f09e8e318f6427bddd0e6ad 100644 --- a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementWithViewsRow.java +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CourseCurriculumTreeWithViewsRow.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.coach.ui.curriculum; +package org.olat.modules.coach.ui.curriculum.course; import java.util.Collections; import java.util.Date; @@ -30,6 +30,7 @@ import org.olat.core.id.OLATResourceable; import org.olat.core.util.StringHelper; import org.olat.core.util.filter.FilterFactory; import org.olat.course.assessment.AssessmentHelper; +import org.olat.modules.coach.model.EfficiencyStatementEntry; import org.olat.modules.curriculum.Curriculum; import org.olat.modules.curriculum.CurriculumCalendars; import org.olat.modules.curriculum.CurriculumElement; @@ -50,10 +51,10 @@ import org.olat.resource.OLATResource; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class CurriculumElementWithViewsRow implements CurriculumElementWithView, FlexiTreeTableNode { +public class CourseCurriculumTreeWithViewsRow implements CurriculumElementWithView, FlexiTreeTableNode { private boolean hasChildren; - private CurriculumElementWithViewsRow parent; + private CourseCurriculumTreeWithViewsRow parent; private Long parentKey; @@ -91,8 +92,10 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, private FormLink selectLink; private FormLink calendarsLink; private ProgressBarItem completionItem; + + private EfficiencyStatementEntry efficiencyStatementEntry; - public CurriculumElementWithViewsRow(Curriculum curriculum, CurriculumElement element, CurriculumElementMembership curriculumMembership, int myEntryCount) { + public CourseCurriculumTreeWithViewsRow(Curriculum curriculum, CurriculumElement element, CurriculumElementMembership curriculumMembership, int myEntryCount) { this.element = element; elementType = element.getType(); this.curriculumMembership = curriculumMembership; @@ -109,7 +112,7 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, } } - public CurriculumElementWithViewsRow(Curriculum curriculum) { + public CourseCurriculumTreeWithViewsRow(Curriculum curriculum) { this.curriculum = curriculum; parentKey = null; element = null; @@ -123,7 +126,7 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, * Used to show the head parent of elements without any curriculum * @param representationalName */ - public CurriculumElementWithViewsRow(String representationalName) { + public CourseCurriculumTreeWithViewsRow(String representationalName) { this.representationalName = representationalName; curriculum = null; parentKey = null; @@ -138,7 +141,7 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, * Used to show elements without any curriculum * @param repositoryEntryView */ - public CurriculumElementWithViewsRow(RepositoryEntryMyView repositoryEntryView) { + public CourseCurriculumTreeWithViewsRow(RepositoryEntryMyView repositoryEntryView) { guests = repositoryEntryView.isGuests(); allUsers = repositoryEntryView.isAllUsers(); bookable = repositoryEntryView.isBookable(); @@ -157,8 +160,8 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, level = 0; } - public CurriculumElementWithViewsRow(Curriculum curriculum, CurriculumElement element, CurriculumElementMembership curriculumMembership, - RepositoryEntryMyView repositoryEntryView, boolean alone) { + public CourseCurriculumTreeWithViewsRow(Curriculum curriculum, CurriculumElement element, CurriculumElementMembership curriculumMembership, + RepositoryEntryMyView repositoryEntryView, boolean alone) { this.element = element; elementType = element == null ? null : element.getType(); this.curriculumMembership = curriculumMembership; @@ -215,7 +218,7 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, return element.getDisplayName(); } else if (curriculum != null) { return curriculum.getDisplayName(); - } + } else return null; } @@ -535,11 +538,11 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, } @Override - public CurriculumElementWithViewsRow getParent() { + public CourseCurriculumTreeWithViewsRow getParent() { return parent; } - public void setParent(CurriculumElementWithViewsRow parent) { + public void setParent(CourseCurriculumTreeWithViewsRow parent) { this.parent = parent; if(parent != null) { parent.hasChildren = true; @@ -639,6 +642,14 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, return completionItem == null ? null : completionItem.getComponent().getComponentName(); } + public EfficiencyStatementEntry getEfficiencyStatementEntry() { + return this.efficiencyStatementEntry; + } + + public void setEfficiencyStatementEntry(EfficiencyStatementEntry efficiencyStatementEntry) { + this.efficiencyStatementEntry = efficiencyStatementEntry; + } + @Override public String getCrump() { return element.getDisplayName(); @@ -655,8 +666,8 @@ public class CurriculumElementWithViewsRow implements CurriculumElementWithView, if(this == obj) { return true; } - if(obj instanceof CurriculumElementWithViewsRow) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow)obj; + if(obj instanceof CourseCurriculumTreeWithViewsRow) { + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow)obj; return ((element == null && row.element == null && curriculum!= null && row.curriculum != null && curriculum.getKey().equals(row.curriculum.getKey())) || (element != null && row.element != null && element.getKey().equals(row.element.getKey()))) && ((repositoryEntry == null && row.repositoryEntry == null) diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/CourseListWrapperController.java b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CourseListWrapperController.java similarity index 82% rename from src/main/java/org/olat/modules/coach/ui/curriculum/CourseListWrapperController.java rename to src/main/java/org/olat/modules/coach/ui/curriculum/course/CourseListWrapperController.java index a1544fec257699ea68009f28fae36f3c11db421b..4da55e05b58eaf46f2ac6b0f17b45820f187faf7 100644 --- a/src/main/java/org/olat/modules/coach/ui/curriculum/CourseListWrapperController.java +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CourseListWrapperController.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.coach.ui.curriculum; +package org.olat.modules.coach.ui.curriculum.course; import java.util.List; @@ -36,9 +36,9 @@ import org.olat.core.id.context.ContextEntry; import org.olat.core.id.context.StateEntry; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OresHelper; -import org.olat.modules.coach.UserRelationSecurityCallback; +import org.olat.modules.coach.RoleSecurityCallback; import org.olat.modules.coach.model.StudentStatEntry; -import org.olat.modules.coach.ui.UserRelationEnrollmentListController; +import org.olat.modules.coach.ui.EnrollmentListController; import org.olat.modules.curriculum.CurriculumModule; import org.olat.modules.curriculum.CurriculumRef; import org.olat.modules.curriculum.CurriculumSecurityCallback; @@ -53,11 +53,11 @@ public class CourseListWrapperController extends BasicController implements Acti private final Identity mentee; private final StudentStatEntry statEntry; private final CurriculumSecurityCallback curriculumSecurityCallback; - private final UserRelationSecurityCallback userRelationSecurityCallback; + private final RoleSecurityCallback roleSecurityCallback; private final List<CurriculumRef> curriculumRefs; private CurriculumElementListController curriculumListController; - private UserRelationEnrollmentListController userRelationEnrollmentListController; + private EnrollmentListController enrollmentListController; private Link curriculumShow; private Link curriculumHide; @@ -69,18 +69,18 @@ public class CourseListWrapperController extends BasicController implements Acti @Autowired CurriculumModule curriculumModule; - public CourseListWrapperController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, Identity mentee, CurriculumSecurityCallback curriculumSecurityCallback, UserRelationSecurityCallback userRelationSecurityCallback, List<CurriculumRef> curriculumRefs, StudentStatEntry statEntry) { + public CourseListWrapperController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel, Identity mentee, CurriculumSecurityCallback curriculumSecurityCallback, RoleSecurityCallback roleSecurityCallback, List<CurriculumRef> curriculumRefs, StudentStatEntry statEntry) { super(ureq, wControl); this.stackPanel = stackPanel; this.mentee = mentee; this.curriculumSecurityCallback = curriculumSecurityCallback; - this.userRelationSecurityCallback = userRelationSecurityCallback; + this.roleSecurityCallback = roleSecurityCallback; this.curriculumRefs = curriculumRefs; this.statEntry = statEntry; content = createVelocityContainer("course_list_wrapper"); - showCurriculum = curriculumModule.isEnabled() && userRelationSecurityCallback.canViewCoursesAndCurriculum(); + showCurriculum = curriculumModule.isEnabled() && roleSecurityCallback.canViewCoursesAndCurriculum(); if (showCurriculum) { curriculumShow = LinkFactory.createLink("off", content, this); @@ -144,7 +144,7 @@ public class CourseListWrapperController extends BasicController implements Acti if (curriculumListController == null) { WindowControl bwControl = addToHistory(ureq, OresHelper.createOLATResourceableType(WITH_CURRICULUM), null); - curriculumListController = new CurriculumElementListController(ureq, bwControl, stackPanel, mentee, curriculumRefs, curriculumSecurityCallback, userRelationSecurityCallback); + curriculumListController = new CurriculumElementListController(ureq, bwControl, stackPanel, mentee, curriculumRefs, curriculumSecurityCallback, roleSecurityCallback); listenTo(curriculumListController); } @@ -157,15 +157,15 @@ public class CourseListWrapperController extends BasicController implements Acti public Activateable2 hideCurriculumStructure(UserRequest ureq) { showCurriculum = false; - if (userRelationEnrollmentListController == null) { + if (enrollmentListController == null) { WindowControl bwControl = addToHistory(ureq, OresHelper.createOLATResourceableType(WITHOUT_CURRICULM), null); - userRelationEnrollmentListController = new UserRelationEnrollmentListController(ureq, bwControl, stackPanel, statEntry, mentee, userRelationSecurityCallback); - listenTo(userRelationEnrollmentListController); + enrollmentListController = new EnrollmentListController(ureq, bwControl, stackPanel, statEntry, mentee, roleSecurityCallback); + listenTo(enrollmentListController); } content.contextPut("showCurriculum", showCurriculum); - content.put("content", userRelationEnrollmentListController.getInitialComponent()); - addToHistory(ureq, userRelationEnrollmentListController); - return userRelationEnrollmentListController; + content.put("content", enrollmentListController.getInitialComponent()); + addToHistory(ureq, enrollmentListController); + return enrollmentListController; } } diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementCompositeRenderer.java b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementCompositeRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..b7ca1336ac2ced47bc60327ee3756dbf7055854a --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementCompositeRenderer.java @@ -0,0 +1,52 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.modules.coach.ui.curriculum.course; + +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; +import org.olat.core.gui.components.form.flexible.impl.elements.table.StaticFlexiCellRenderer; +import org.olat.core.gui.render.Renderer; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; + +/** + * + * Initial date: 10 août 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CurriculumElementCompositeRenderer extends StaticFlexiCellRenderer { + + public CurriculumElementCompositeRenderer(String action, FlexiCellRenderer labelDelegate) { + super(action, labelDelegate); + } + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source, + URLBuilder ubu, Translator translator) { + CourseCurriculumTreeWithViewsRow view = (CourseCurriculumTreeWithViewsRow)source.getFlexiTableElement().getTableDataModel().getObject(row); + if(view.isCurriculumElementOnly()) { + getLabelDelegate().render(renderer, target, cellValue, row, source, ubu, translator); + } else { + super.render(renderer, target, cellValue, row, source, ubu, translator); + } + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementListController.java b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementListController.java similarity index 84% rename from src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementListController.java rename to src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementListController.java index a728565415fd99e4df33ac65cddc80b8011d7507..af2ba1035232603f878fd5566e8101612aee7e2f 100644 --- a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementListController.java +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementListController.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.coach.ui.curriculum; +package org.olat.modules.coach.ui.curriculum.course; import java.util.ArrayList; import java.util.Collection; @@ -79,8 +79,8 @@ import org.olat.core.util.vfs.VFSLeaf; import org.olat.course.CorruptedCourseException; import org.olat.modules.assessment.AssessmentEntryCompletion; import org.olat.modules.assessment.AssessmentService; -import org.olat.modules.coach.UserRelationSecurityCallback; -import org.olat.modules.coach.ui.curriculum.CurriculumElementWithViewsDataModel.ElementViewCols; +import org.olat.modules.coach.RoleSecurityCallback; +import org.olat.modules.coach.ui.curriculum.course.CurriculumElementWithViewsDataModel.ElementViewCols; import org.olat.modules.curriculum.Curriculum; import org.olat.modules.curriculum.CurriculumElement; import org.olat.modules.curriculum.CurriculumElementMembership; @@ -137,7 +137,7 @@ public class CurriculumElementListController extends FormBasicController impleme private final MapperKey mapperThumbnailKey; private final Identity assessedIdentity; private final CurriculumSecurityCallback curriculumSecurityCallback; - private final UserRelationSecurityCallback userRelationSecurityCallback; + private final RoleSecurityCallback roleSecurityCallback; private RepositoryEntryDetailsController detailsCtrl; private CurriculumElementCalendarController calendarsCtrl; @@ -162,12 +162,12 @@ public class CurriculumElementListController extends FormBasicController impleme private BaseSecurity securityManager; public CurriculumElementListController(UserRequest ureq, WindowControl wControl, BreadcrumbPanel stackPanel, - Identity assessedIdentity, List<CurriculumRef> curriculumRefList, CurriculumSecurityCallback curriculumSecurityCallback, UserRelationSecurityCallback userRelationSecurityCallback) { + Identity assessedIdentity, List<CurriculumRef> curriculumRefList, CurriculumSecurityCallback curriculumSecurityCallback, RoleSecurityCallback roleSecurityCallback) { super(ureq, wControl, "curriculum_element_list", Util.createPackageTranslator(CurriculumListController.class, RepositoryService.class, ureq.getLocale())); this.curriculumRefList = curriculumRefList; this.stackPanel = stackPanel; this.curriculumSecurityCallback = curriculumSecurityCallback; - this.userRelationSecurityCallback = userRelationSecurityCallback; + this.roleSecurityCallback = roleSecurityCallback; this.assessedIdentity = assessedIdentity; this.curriculumList = curriculumService.getMyCurriculums(assessedIdentity); guestOnly = ureq.getUserSession().getRoles().isGuestOnly(); @@ -185,18 +185,25 @@ public class CurriculumElementListController extends FormBasicController impleme @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ElementViewCols.key)); + TreeNodeFlexiCellRenderer treeNodeRenderer = new TreeNodeFlexiCellRenderer("select"); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.displayName, treeNodeRenderer)); + DefaultFlexiColumnModel elementIdentifierCol = new DefaultFlexiColumnModel(ElementViewCols.identifier, "select"); elementIdentifierCol.setCellRenderer(new CurriculumElementCompositeRenderer("select", new TextFlexiCellRenderer())); columnsModel.addFlexiColumnModel(elementIdentifierCol); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ElementViewCols.select)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.details)); - if (userRelationSecurityCallback.canViewCourseProgressAndStatus()) { + + // Name column + // columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ElementViewCols.select)); + // Info site column + // columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.details)); + + if (roleSecurityCallback.canViewCourseProgressAndStatus()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.completion)); } - if (userRelationSecurityCallback.canViewCalendar()) { + if (roleSecurityCallback.canViewCalendar()) { columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.calendars)); } @@ -238,7 +245,7 @@ public class CurriculumElementListController extends FormBasicController impleme @Override public String getRowCssClass(FlexiTableRendererType type, int pos) { StringBuilder sb = new StringBuilder(64); - CurriculumElementWithViewsRow rowWithView = tableModel.getObject(pos); + CourseCurriculumTreeWithViewsRow rowWithView = tableModel.getObject(pos); if (type == FlexiTableRendererType.custom) { sb.append("o_table_row "); @@ -258,7 +265,7 @@ public class CurriculumElementListController extends FormBasicController impleme sb.append(" o_curriculum"); } else { int count = 0; - for (CurriculumElementWithViewsRow parent = rowWithView.getParent(); parent != null; parent = parent.getParent()) { + for (CourseCurriculumTreeWithViewsRow parent = rowWithView.getParent(); parent != null; parent = parent.getParent()) { count++; } @@ -285,15 +292,15 @@ public class CurriculumElementListController extends FormBasicController impleme private void loadModel(UserRequest ureq) { Roles roles = ureq.getUserSession().getRoles(); - List<CurriculumElementWithViewsRow> allRows = new ArrayList<>(); + List<CourseCurriculumTreeWithViewsRow> allRows = new ArrayList<>(); List<CurriculumElementRepositoryEntryViews> elementsWithViewsForAll = curriculumService.getCurriculumElements(assessedIdentity, roles, curriculumRefList); Map<Curriculum, List<CurriculumElementRepositoryEntryViews>> elementsMap = elementsWithViewsForAll.stream().collect(Collectors.groupingBy(row -> row.getCurriculumElement().getCurriculum(), Collectors.toList())); for (Curriculum curriculum : curriculumList) { - CurriculumElementWithViewsRow curriculumRow = new CurriculumElementWithViewsRow(curriculum); + CourseCurriculumTreeWithViewsRow curriculumRow = new CourseCurriculumTreeWithViewsRow(curriculum); List<CurriculumElementRepositoryEntryViews> elementsWithViews = elementsMap.get(curriculum); if (elementsWithViews != null && !elementsWithViews.isEmpty()) { - List<CurriculumElementWithViewsRow> rows = new ArrayList<>(); + List<CourseCurriculumTreeWithViewsRow> rows = new ArrayList<>(); Set<Long> repoKeys = new HashSet<>(); List<OLATResource> resourcesWithAC = new ArrayList<>(); @@ -313,20 +320,20 @@ public class CurriculumElementListController extends FormBasicController impleme CurriculumElementMembership elementMembership = elementWithViews.getCurriculumMembership(); if (elementWithViews.getEntries() == null || elementWithViews.getEntries().isEmpty()) { - CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(curriculum, element, elementMembership, 0); + CourseCurriculumTreeWithViewsRow row = new CourseCurriculumTreeWithViewsRow(curriculum, element, elementMembership, 0); forgeCalendarsLink(row); rows.add(row); } else if (elementWithViews.getEntries().size() == 1) { - CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(curriculum, element, elementMembership, elementWithViews.getEntries().get(0), true); + CourseCurriculumTreeWithViewsRow row = new CourseCurriculumTreeWithViewsRow(curriculum, element, elementMembership, elementWithViews.getEntries().get(0), true); forge(row, repoKeys, resourcesWithOffer); forgeCalendarsLink(row); rows.add(row); } else { - CurriculumElementWithViewsRow elementRow = new CurriculumElementWithViewsRow(curriculum, element, elementMembership, elementWithViews.getEntries().size()); + CourseCurriculumTreeWithViewsRow elementRow = new CourseCurriculumTreeWithViewsRow(curriculum, element, elementMembership, elementWithViews.getEntries().size()); forgeCalendarsLink(elementRow); rows.add(elementRow); for (RepositoryEntryMyView entry : elementWithViews.getEntries()) { - CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(curriculum, element, elementMembership, entry, false); + CourseCurriculumTreeWithViewsRow row = new CourseCurriculumTreeWithViewsRow(curriculum, element, elementMembership, entry, false); forge(row, repoKeys, resourcesWithOffer); rows.add(row); } @@ -335,8 +342,8 @@ public class CurriculumElementListController extends FormBasicController impleme } - Map<Long, CurriculumElementWithViewsRow> keyToRow = rows.stream() - .collect(Collectors.toMap(CurriculumElementWithViewsRow::getKey, row -> row, (row1, row2) -> row1)); + Map<Long, CourseCurriculumTreeWithViewsRow> keyToRow = rows.stream() + .collect(Collectors.toMap(CourseCurriculumTreeWithViewsRow::getKey, row -> row, (row1, row2) -> row1)); rows.forEach(row -> { row.setParent(keyToRow.get(row.getParentKey())); if (row.getOlatResource() != null) { @@ -368,7 +375,7 @@ public class CurriculumElementListController extends FormBasicController impleme // Filter for entries which are already in a curriculum if (!courses.isEmpty()) { - CurriculumElementWithViewsRow foreignEntryParent = new CurriculumElementWithViewsRow(translate("curriculum.foreign.entries")); + CourseCurriculumTreeWithViewsRow foreignEntryParent = new CourseCurriculumTreeWithViewsRow(translate("curriculum.foreign.entries")); allRows.add(foreignEntryParent); List<RepositoryEntryMyView> foreignCourses = courses.stream() @@ -377,7 +384,7 @@ public class CurriculumElementListController extends FormBasicController impleme ).collect(Collectors.toList()); foreignCourses.forEach(course -> { - CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(course); + CourseCurriculumTreeWithViewsRow row = new CourseCurriculumTreeWithViewsRow(course); forgeSelectLink(row); forgeCompletion(row,row.getRepositoryEntryCompletion()); forgeDetails(row); @@ -391,25 +398,25 @@ public class CurriculumElementListController extends FormBasicController impleme tableEl.reset(true, true, true); } - private void removeByPermissions(List<CurriculumElementWithViewsRow> rows) { + private void removeByPermissions(List<CourseCurriculumTreeWithViewsRow> rows) { // propagate the member marker along the parent line - for (CurriculumElementWithViewsRow row : rows) { + for (CourseCurriculumTreeWithViewsRow row : rows) { if (row.isCurriculumMember()) { - for (CurriculumElementWithViewsRow parentRow = row.getParent(); parentRow != null; parentRow = parentRow.getParent()) { + for (CourseCurriculumTreeWithViewsRow parentRow = row.getParent(); parentRow != null; parentRow = parentRow.getParent()) { parentRow.setCurriculumMember(true); } } } // trim part of the tree without member flag - for (Iterator<CurriculumElementWithViewsRow> it = rows.iterator(); it.hasNext(); ) { + for (Iterator<CourseCurriculumTreeWithViewsRow> it = rows.iterator(); it.hasNext(); ) { if (!it.next().isCurriculumMember()) { it.remove(); } } } - private void forge(CurriculumElementWithViewsRow row, Collection<Long> repoKeys, List<OLATResourceAccess> resourcesWithOffer) { + private void forge(CourseCurriculumTreeWithViewsRow row, Collection<Long> repoKeys, List<OLATResourceAccess> resourcesWithOffer) { if (row.getRepositoryEntryKey() == null || guestOnly) return;// nothing for guests boolean isMember = repoKeys.contains(row.getRepositoryEntryKey()); @@ -466,7 +473,7 @@ public class CurriculumElementListController extends FormBasicController impleme forgeCompletion(row, row.getRepositoryEntryCompletion()); } - private void forgeDetails(CurriculumElementWithViewsRow row) { + private void forgeDetails(CourseCurriculumTreeWithViewsRow row) { FormLink detailsLink = uifactory.addFormLink("details_" + (++counter), "details", "details", null, null, Link.LINK); detailsLink.setCustomEnabledLinkCSS("o_details"); detailsLink.setUserObject(row); @@ -481,7 +488,7 @@ public class CurriculumElementListController extends FormBasicController impleme row.setDetailsLink(detailsLink, detailsUrl); } - private void forgeMarkLink(CurriculumElementWithViewsRow row) { + private void forgeMarkLink(CourseCurriculumTreeWithViewsRow row) { if (!guestOnly) { FormLink markLink = uifactory.addFormLink("mark_" + (++counter), "mark", "", null, null, Link.NONTRANSLATED); markLink.setIconLeftCSS(row.isMarked() ? Mark.MARK_CSS_LARGE : Mark.MARK_ADD_CSS_LARGE); @@ -491,7 +498,7 @@ public class CurriculumElementListController extends FormBasicController impleme } } - private void forgeSelectLink(CurriculumElementWithViewsRow row) { + private void forgeSelectLink(CourseCurriculumTreeWithViewsRow row) { if (row.isCurriculumElementOnly()) return; String displayName = StringHelper.escapeHtml(row.getRepositoryEntryDisplayName()); @@ -509,7 +516,7 @@ public class CurriculumElementListController extends FormBasicController impleme row.setSelectLink(selectLink); } - private void forgeCalendarsLink(CurriculumElementWithViewsRow row) { + private void forgeCalendarsLink(CourseCurriculumTreeWithViewsRow row) { if (row.isCalendarsEnabled()) { FormLink calendarLink = uifactory.addFormLink("cals_" + (++counter), "calendars", "calendars", null, null, Link.LINK); calendarLink.setIconLeftCSS("o_icon o_icon-fw o_icon_timetable"); @@ -518,17 +525,17 @@ public class CurriculumElementListController extends FormBasicController impleme } } - private void forgeCurriculumCompletions(List<CurriculumElementWithViewsRow> rows) { + private void forgeCurriculumCompletions(List<CourseCurriculumTreeWithViewsRow> rows) { Map<Long, Double> completions = loadCurriculumElementCompletions(rows); - for (CurriculumElementWithViewsRow row : rows) { + for (CourseCurriculumTreeWithViewsRow row : rows) { if (row.getCompletionItem() == null) { // does not show completion of the child entry forgeCompletion(row, completions.get(row.getKey())); } } } - private void forgeCompletion(CurriculumElementWithViewsRow row, Double completion) { + private void forgeCompletion(CourseCurriculumTreeWithViewsRow row, Double completion) { if (completion != null) { ProgressBarItem completionItem = new ProgressBarItem("completion_" + row.getKey(), 100, completion.floatValue(), Float.valueOf(1), null); @@ -541,14 +548,14 @@ public class CurriculumElementListController extends FormBasicController impleme } } - private void addRoot(List<CurriculumElementWithViewsRow> rows, CurriculumElementWithViewsRow parent) { + private void addRoot(List<CourseCurriculumTreeWithViewsRow> rows, CourseCurriculumTreeWithViewsRow parent) { rows.stream().filter(row -> row.getParent() == null).forEach(row -> row.setParent(parent)); } - private Map<Long, Double> loadCurriculumElementCompletions(List<CurriculumElementWithViewsRow> rows) { + private Map<Long, Double> loadCurriculumElementCompletions(List<CourseCurriculumTreeWithViewsRow> rows) { List<Long> curEleLearningProgressKeys = rows.stream() - .filter(CurriculumElementWithViewsRow::isLearningProgressEnabled) - .map(CurriculumElementWithViewsRow::getKey) + .filter(CourseCurriculumTreeWithViewsRow::isLearningProgressEnabled) + .map(CourseCurriculumTreeWithViewsRow::getKey) .collect(Collectors.toList()); List<AssessmentEntryCompletion> loadAvgCompletionsByCurriculumElements = assessmentService .loadAvgCompletionsByCurriculumElements(assessedIdentity, curEleLearningProgressKeys); @@ -579,8 +586,8 @@ public class CurriculumElementListController extends FormBasicController impleme if (StringHelper.isLong(rowKeyStr)) { try { Long rowKey = Long.valueOf(rowKeyStr); - List<CurriculumElementWithViewsRow> rows = tableModel.getObjects(); - for (CurriculumElementWithViewsRow row : rows) { + List<CourseCurriculumTreeWithViewsRow> rows = tableModel.getObjects(); + for (CourseCurriculumTreeWithViewsRow row : rows) { if (row != null && row.getRepositoryEntryKey() != null && row.getRepositoryEntryKey().equals(rowKey)) { if (row.isMember()) { doOpen(ureq, row, null); @@ -603,33 +610,33 @@ public class CurriculumElementListController extends FormBasicController impleme if (source instanceof FormLink) { FormLink link = (FormLink) source; if ("start".equals(link.getCmd())) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow) link.getUserObject(); + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow) link.getUserObject(); doOpen(ureq, row, null); } else if ("details".equals(link.getCmd())) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow) link.getUserObject(); + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow) link.getUserObject(); doOpenDetails(ureq, row); } else if ("select".equals(link.getCmd())) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow) link.getUserObject(); + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow) link.getUserObject(); if (row.isMember()) { doOpen(ureq, row, null); } else { doOpenDetails(ureq, row); } } else if ("mark".equals(link.getCmd())) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow) link.getUserObject(); + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow) link.getUserObject(); boolean marked = doMark(ureq, row); link.setIconLeftCSS(marked ? "o_icon o_icon_bookmark o_icon-lg" : "o_icon o_icon_bookmark_add o_icon-lg"); link.setTitle(translate(marked ? "details.bookmark.remove" : "details.bookmark")); link.getComponent().setDirty(true); row.setMarked(marked); } else if ("calendars".equals(link.getCmd())) { - CurriculumElementWithViewsRow row = (CurriculumElementWithViewsRow) link.getUserObject(); + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow) link.getUserObject(); doOpenCalendars(ureq, row); } } else if (source == tableEl) { if (event instanceof SelectionEvent) { SelectionEvent se = (SelectionEvent) event; - CurriculumElementWithViewsRow row = tableModel.getObject(se.getIndex()); + CourseCurriculumTreeWithViewsRow row = tableModel.getObject(se.getIndex()); if (row.isMember()) { doOpen(ureq, row, null); } else { @@ -645,7 +652,7 @@ public class CurriculumElementListController extends FormBasicController impleme // } - private void doOpen(UserRequest ureq, CurriculumElementWithViewsRow row, String subPath) { + private void doOpen(UserRequest ureq, CourseCurriculumTreeWithViewsRow row, String subPath) { try { String businessPath = "[RepositoryEntry:" + row.getRepositoryEntryKey() + "]"; if (subPath != null) { @@ -658,7 +665,7 @@ public class CurriculumElementListController extends FormBasicController impleme } } - private void doOpenDetails(UserRequest ureq, CurriculumElementWithViewsRow row) { + private void doOpenDetails(UserRequest ureq, CourseCurriculumTreeWithViewsRow row) { // to be more consistent: course members see info page within the course, non-course members see it outside the course if (row.isMember()) { doOpen(ureq, row, "[Infos:0]"); @@ -685,14 +692,14 @@ public class CurriculumElementListController extends FormBasicController impleme } } - private void doOpenCalendars(UserRequest ureq, CurriculumElementWithViewsRow row) { + private void doOpenCalendars(UserRequest ureq, CourseCurriculumTreeWithViewsRow row) { removeAsListenerAndDispose(calendarsCtrl); OLATResourceable ores = OresHelper.createOLATResourceableInstance("Calendars", row.getCurriculumElementKey()); WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl()); CurriculumElement element = curriculumService .getCurriculumElement(new CurriculumElementRefImpl(row.getCurriculumElementKey())); - List<CurriculumElementWithViewsRow> rows = tableModel.getObjects(); + List<CourseCurriculumTreeWithViewsRow> rows = tableModel.getObjects(); Set<Long> entryKeys = new HashSet<>(); for (CurriculumElementWithView elementWithView : rows) { @@ -714,7 +721,7 @@ public class CurriculumElementListController extends FormBasicController impleme stackPanel.pushController(translate("calendars"), calendarsCtrl); } - private boolean doMark(UserRequest ureq, CurriculumElementWithViewsRow row) { + private boolean doMark(UserRequest ureq, CourseCurriculumTreeWithViewsRow row) { OLATResourceable item = OresHelper.createOLATResourceableInstance("RepositoryEntry", row.getRepositoryEntryKey()); RepositoryEntryRef ref = new RepositoryEntryRefImpl(row.getRepositoryEntryKey()); if (markManager.isMarked(item, getIdentity(), null)) { @@ -733,10 +740,10 @@ public class CurriculumElementListController extends FormBasicController impleme } } - private List<CurriculumElementWithViewsRow> sortCurriculumRows(List<CurriculumElementWithViewsRow> rows) { - List<CurriculumElementWithViewsRow> sortedRows = rows.stream().filter(row -> row. getLevel() == 0).collect(Collectors.toList()); + private List<CourseCurriculumTreeWithViewsRow> sortCurriculumRows(List<CourseCurriculumTreeWithViewsRow> rows) { + List<CourseCurriculumTreeWithViewsRow> sortedRows = rows.stream().filter(row -> row. getLevel() == 0).collect(Collectors.toList()); - for (CurriculumElementWithViewsRow parent : sortedRows) { + for (CourseCurriculumTreeWithViewsRow parent : sortedRows) { if (parent.hasChildren()) { sortedRows.addAll(sortedRows.indexOf(parent) + 1, sortCurriculumRows(rows, parent)); } @@ -745,11 +752,11 @@ public class CurriculumElementListController extends FormBasicController impleme return sortedRows; } - private List<CurriculumElementWithViewsRow> sortCurriculumRows(List<CurriculumElementWithViewsRow> rows, CurriculumElementWithViewsRow parent) { - List<CurriculumElementWithViewsRow> filteredRows = rows.stream().filter(row -> row.getParent() != null && row.getParent().equals(parent)).collect(Collectors.toList()); - List<CurriculumElementWithViewsRow> sortedRows = new ArrayList<>(filteredRows); + private List<CourseCurriculumTreeWithViewsRow> sortCurriculumRows(List<CourseCurriculumTreeWithViewsRow> rows, CourseCurriculumTreeWithViewsRow parent) { + List<CourseCurriculumTreeWithViewsRow> filteredRows = rows.stream().filter(row -> row.getParent() != null && row.getParent().equals(parent)).collect(Collectors.toList()); + List<CourseCurriculumTreeWithViewsRow> sortedRows = new ArrayList<>(filteredRows); - for (CurriculumElementWithViewsRow child : filteredRows) { + for (CourseCurriculumTreeWithViewsRow child : filteredRows) { if (child.hasChildren()) { sortedRows.addAll(filteredRows.indexOf(child) + 1, sortCurriculumRows(rows, parent)); } diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementViewsRowComparator.java b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementViewsRowComparator.java similarity index 85% rename from src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementViewsRowComparator.java rename to src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementViewsRowComparator.java index 14d136c31b9ec717e91d0f47c0f43a0ead9b42f5..87b8af24262cb8abf10100e08dd172440d9d8595 100644 --- a/src/main/java/org/olat/modules/coach/ui/curriculum/CurriculumElementViewsRowComparator.java +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementViewsRowComparator.java @@ -17,7 +17,7 @@ * frentix GmbH, http://www.frentix.com * <p> */ -package org.olat.modules.coach.ui.curriculum; +package org.olat.modules.coach.ui.curriculum.course; import java.text.Collator; import java.util.Locale; @@ -47,8 +47,8 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return compareNullObjects(o1, o2); } - CurriculumElementWithViewsRow c1 = (CurriculumElementWithViewsRow)o1; - CurriculumElementWithViewsRow c2 = (CurriculumElementWithViewsRow)o2; + CourseCurriculumTreeWithViewsRow c1 = (CourseCurriculumTreeWithViewsRow)o1; + CourseCurriculumTreeWithViewsRow c2 = (CourseCurriculumTreeWithViewsRow)o2; Long parentKey1 = c1.getParentKey(); Long parentKey2 = c2.getParentKey(); @@ -59,8 +59,8 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator c = compareSameParent(c1, c2); } else if(parentKey1 != null && parentKey2 != null) { // This case is usually not possible - CurriculumElementWithViewsRow p1 = c1.getParent(); - CurriculumElementWithViewsRow p2 = c2.getParent(); + CourseCurriculumTreeWithViewsRow p1 = c1.getParent(); + CourseCurriculumTreeWithViewsRow p2 = c2.getParent(); if(p1 == null || p2 == null) { // reversed because no parent at the top, higher in the hierarchy c = -compareNullObjects(p1, p2); @@ -78,7 +78,7 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return c; } - private int compareSameParent(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) { + private int compareSameParent(CourseCurriculumTreeWithViewsRow c1, CourseCurriculumTreeWithViewsRow c2) { int c = 0; if((c1.isCurriculumElementOnly() || c1.isCurriculumElementWithEntry()) && (c2.isCurriculumElementOnly() || c2.isCurriculumElementWithEntry())) { // compare by position @@ -93,7 +93,7 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return c; } - private int compareCurriculumElements(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) { + private int compareCurriculumElements(CourseCurriculumTreeWithViewsRow c1, CourseCurriculumTreeWithViewsRow c2) { int c = compareClosed(c1, c2); if(c == 0) { @@ -126,7 +126,7 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return c; } - private int compareRepositoryEntry(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) { + private int compareRepositoryEntry(CourseCurriculumTreeWithViewsRow c1, CourseCurriculumTreeWithViewsRow c2) { int c = compareClosed(c1, c2); if(c == 0) { @@ -151,7 +151,7 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return c; } - private int compareClosed(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) { + private int compareClosed(CourseCurriculumTreeWithViewsRow c1, CourseCurriculumTreeWithViewsRow c2) { int c = 0; if(c1.isClosedOrInactive() && !c2.isClosedOrInactive()) { c = 1; @@ -161,7 +161,7 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return c; } - private int compareDisplayName(CurriculumElementWithViewsRow c1, CurriculumElementWithViewsRow c2) { + private int compareDisplayName(CourseCurriculumTreeWithViewsRow c1, CourseCurriculumTreeWithViewsRow c2) { String d1 = getDisplayName(c1); String d2 = getDisplayName(c2); if(d1 == null || d2 == null) { @@ -170,7 +170,7 @@ public class CurriculumElementViewsRowComparator extends FlexiTreeNodeComparator return d1.compareTo(d2); } - private String getDisplayName(CurriculumElementWithViewsRow row) { + private String getDisplayName(CourseCurriculumTreeWithViewsRow row) { if(row.isCurriculumElementOnly()) { return row.getCurriculumElementDisplayName(); } diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementWithViewsDataModel.java b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementWithViewsDataModel.java new file mode 100644 index 0000000000000000000000000000000000000000..a925b43ac177dd3331197970391318139775d453 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/CurriculumElementWithViewsDataModel.java @@ -0,0 +1,278 @@ +/** + * <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.coach.ui.curriculum.course; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentMap; + +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; +import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTreeTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiBusinessPathModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.course.certificate.CertificateLight; +import org.olat.modules.coach.model.EfficiencyStatementEntry; +import org.olat.modules.coach.model.IdentityRepositoryEntryKey; +import org.olat.modules.coach.model.IdentityResourceKey; +import org.olat.modules.coach.ui.ProgressValue; +import org.olat.modules.curriculum.CurriculumElementStatus; +import org.olat.modules.lecture.model.LectureBlockStatistics; + +/** + * + * Initial date: 11 mai 2018<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CurriculumElementWithViewsDataModel extends DefaultFlexiTreeTableDataModel<CourseCurriculumTreeWithViewsRow> implements FlexiBusinessPathModel { + + private ConcurrentMap<IdentityResourceKey, CertificateLight> certificateMap; + private ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesStatisticsMap; + + public CurriculumElementWithViewsDataModel(FlexiTableColumnModel columnsModel) { + super(columnsModel); + } + + @Override + public void filter(String searchString, List<FlexiTableFilter> filters) { + if(filters != null && !filters.isEmpty() && filters.get(0) != null) { + FlexiTableFilter filter = filters.get(0); + if(filter == null || filter.isShowAll()) { + setUnfilteredObjects(); + } else { + List<CourseCurriculumTreeWithViewsRow> filteredRows = new ArrayList<>(backupRows.size()); + // curriculum element inactive -> all repo are inactives + // parent inactive, child is active -> parent is forced active + for(CourseCurriculumTreeWithViewsRow row:backupRows) { + boolean accept = active(row); + if(accept) { + filteredRows.add(row); + } + } + setFilteredObjects(filteredRows); + } + } else { + setUnfilteredObjects(); + } + } + + private boolean active(CourseCurriculumTreeWithViewsRow row) { + boolean active = true; + if(row.isCurriculumElementOnly() || row.isCurriculumElementWithEntry()) { + active = row.getCurriculumElementStatus() == CurriculumElementStatus.active; + } + if(active) { + for(CourseCurriculumTreeWithViewsRow parent = row.getParent(); parent != null; parent=parent.getParent()) { + if(parent.isCurriculumElementOnly() || parent.isCurriculumElementWithEntry()) { + active &= row.getCurriculumElementStatus() == CurriculumElementStatus.active; + } + } + } + return active; + } + + @Override + public boolean hasChildren(int row) { + CourseCurriculumTreeWithViewsRow element = getObject(row); + return element.hasChildren(); + } + + @Override + public Object getValueAt(int row, int col) { + CourseCurriculumTreeWithViewsRow curriculum = getObject(row); + switch(ElementViewCols.values()[col]) { + case key: return curriculum.getKey(); + case displayName: { + String displayName; + if(curriculum.isRepositoryEntryOnly()) { + displayName = curriculum.getRepositoryEntryDisplayName(); + } else { + displayName = curriculum.getCurriculumElementDisplayName(); + } + return displayName; + } + case identifier: { + String identifier; + if(curriculum.isRepositoryEntryOnly()) { + identifier = curriculum.getRepositoryEntryExternalRef(); + } else { + identifier = curriculum.getCurriculumElementIdentifier(); + } + return identifier; + } + case mark: return curriculum.getMarkLink(); + case select: return curriculum.getSelectLink(); + case details: return curriculum.getDetailsLink(); + case start: return curriculum.getStartLink(); + case calendars: return curriculum.getCalendarsLink(); + case completion: return curriculum.getCompletionItem(); + case score: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getScore() : null; + case passed: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getPassed() : null; + case certificate: return getCertificate(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + case recertification: { + CertificateLight certificate = getCertificate(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return certificate == null ? null : certificate.getNextRecertificationDate(); + } + case numberAssessments: { + ProgressValue val = null; + Integer totalNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getTotalNodes() : null; + if (totalNodes != null && totalNodes.intValue() > 0) { + val = new ProgressValue(); + val.setTotal(totalNodes.intValue()); + Integer attemptedNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getAttemptedNodes() : null; + val.setGreen(attemptedNodes == null ? 0 : attemptedNodes.intValue()); + } + return val; + } + case progress: { + Integer totalNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getTotalNodes() : null; + if(totalNodes == null) { + ProgressValue val = new ProgressValue(); + val.setTotal(100); + val.setGreen(0); + return val; + } + + ProgressValue val = new ProgressValue(); + val.setTotal(totalNodes.intValue()); + Integer attemptedNodes = curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getAttemptedNodes() : null; + val.setGreen(attemptedNodes == null ? 0 : attemptedNodes.intValue()); + return val; + } + case lastModification: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getLastModified() : null; + case lastUserModified: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getLastUserModified() : null; + case lastCoachModified: return curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry().getLastCoachModified() : null; + case plannedLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalPersonalPlannedLectures(); + } + case attendedLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalAttendedLectures(); + } + case unauthorizedAbsenceLectures: + case absentLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalAbsentLectures(); + } + case authorizedAbsenceLectures: { + LectureBlockStatistics statistics = getLectureBlockStatistics(curriculum.getEfficiencyStatementEntry() != null ? curriculum.getEfficiencyStatementEntry() : null); + return statistics == null ? null : statistics.getTotalAuthorizedAbsentLectures(); + } + default: return "ERROR"; + } + } + + private CertificateLight getCertificate(EfficiencyStatementEntry entry) { + if(certificateMap != null) { + IdentityResourceKey key = new IdentityResourceKey(entry.getIdentityKey(), entry.getCourse().getOlatResource().getKey()); + return certificateMap.get(key); + } + return null; + } + + private LectureBlockStatistics getLectureBlockStatistics(EfficiencyStatementEntry entry) { + if(lecturesStatisticsMap != null) { + IdentityRepositoryEntryKey key = new IdentityRepositoryEntryKey(entry); + return lecturesStatisticsMap.get(key); + } + return null; + } + + public void setObjects(List<CourseCurriculumTreeWithViewsRow> objects, ConcurrentMap<IdentityResourceKey, CertificateLight> certificates) { + setObjects(objects, certificates, null); + } + + public void setObjects(List<CourseCurriculumTreeWithViewsRow> objects, + ConcurrentMap<IdentityResourceKey, CertificateLight> certificates, + ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesStatisticsMap) { + setObjects(objects); + this.certificateMap = certificates; + this.lecturesStatisticsMap = lecturesStatisticsMap; + } + + @Override + public CurriculumElementWithViewsDataModel createCopyWithEmptyList() { + return new CurriculumElementWithViewsDataModel(getTableColumnModel()); + } + + public enum ElementViewCols implements FlexiSortableColumnDef { + key("table.header.key"), + displayName("table.header.curriculum.element.displayName"), + identifier("table.header.curriculum.element.identifier"), + mark("table.header.mark"), + select("table.header.displayName"), + completion("table.header.completion"), + details("table.header.details"), + start("table.header.start"), + calendars("table.header.calendars"), + score("table.header.score"), + passed("table.header.passed"), + certificate("table.header.certificate"), + recertification("table.header.recertification"), + numberAssessments("table.header.number.assessments"), + progress("table.header.progress"), + lastModification("table.header.lastScoreDate"), + lastUserModified("table.header.lastUserModificationDate"), + lastCoachModified("table.header.lastCoachModificationDate"), + plannedLectures("table.header.planned.lectures"), + attendedLectures("table.header.attended.lectures"), + absentLectures("table.header.absent.lectures"), + unauthorizedAbsenceLectures("table.header.unauthorized.absence"), + authorizedAbsenceLectures("table.header.authorized.absence"); + + private final String i18nHeaderKey; + + private ElementViewCols(String i18nHeaderKey) { + this.i18nHeaderKey = i18nHeaderKey; + } + + @Override + public boolean sortable() { + return false; + } + + @Override + public String sortKey() { + return name(); + } + + @Override + public String i18nHeaderKey() { + return i18nHeaderKey; + } + } + + @Override + public String getUrl(Component source, Object object, String action) { + if("select".equals(action) && object instanceof CourseCurriculumTreeWithViewsRow) { + CourseCurriculumTreeWithViewsRow row = (CourseCurriculumTreeWithViewsRow)object; + if(row.getStartUrl() != null) { + return row.getStartUrl(); + } + if(row.getDetailsUrl() != null) { + return row.getDetailsUrl(); + } + } + return null; + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/course_list_wrapper.html b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/course_list_wrapper.html new file mode 100644 index 0000000000000000000000000000000000000000..5e24835375b6742bb25c795c4f459f1d76814dc9 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/course_list_wrapper.html @@ -0,0 +1,12 @@ +#if($r.available("on")) +<span> + $r.translate("curriculum.toggle.description") + #if($showCurriculum) + $r.render("on") + #else + $r.render("off") + #end +</span> +#end + +$r.render("content") diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/curriculum_element_list.html b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/curriculum_element_list.html new file mode 100644 index 0000000000000000000000000000000000000000..99ac382380fc019dd5fcdceaf52f22eea7dbda71 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/curriculum_element_list.html @@ -0,0 +1 @@ +$r.render("table") diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/curriculum_list.html b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/curriculum_list.html new file mode 100644 index 0000000000000000000000000000000000000000..99ac382380fc019dd5fcdceaf52f22eea7dbda71 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_content/curriculum_list.html @@ -0,0 +1 @@ +$r.render("table") diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_i18n/LocalStrings_de.properties similarity index 100% rename from src/main/java/org/olat/modules/coach/ui/curriculum/_i18n/LocalStrings_de.properties rename to src/main/java/org/olat/modules/coach/ui/curriculum/course/_i18n/LocalStrings_de.properties diff --git a/src/main/java/org/olat/modules/coach/ui/curriculum/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/coach/ui/curriculum/course/_i18n/LocalStrings_en.properties similarity index 100% rename from src/main/java/org/olat/modules/coach/ui/curriculum/_i18n/LocalStrings_en.properties rename to src/main/java/org/olat/modules/coach/ui/curriculum/course/_i18n/LocalStrings_en.properties diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumService.java b/src/main/java/org/olat/modules/curriculum/CurriculumService.java index 6d79391713dddd68c101f0c0f07f3ea6337a3e40..a4e867373f3384db6fa6d8bbdd321e005efffca4 100644 --- a/src/main/java/org/olat/modules/curriculum/CurriculumService.java +++ b/src/main/java/org/olat/modules/curriculum/CurriculumService.java @@ -501,7 +501,7 @@ public interface CurriculumService { public List<CurriculumElement> filterElementsWithoutManagerRole(List<CurriculumElement> elements, Roles roles); - public List<CurriculumElementRepositoryEntryViews> getCurriculumElements(Identity identity, Roles roles, List<CurriculumRef> curriculum); + public List<CurriculumElementRepositoryEntryViews> getCurriculumElements(Identity identity, Roles roles, List<? extends CurriculumRef> curriculum); public List<CurriculumElementWebDAVInfos> getCurriculumElementInfosForWebDAV(IdentityRef identity); 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 0e1ef0d1ca4a6736e602e92354415bd945de1bf4..a2f7626c3948044a631b30885444b12c19071eca 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumElementDAO.java @@ -870,7 +870,7 @@ public class CurriculumElementDAO { .getResultList(); } - public List<CurriculumElementMembership> getMembershipInfos(List<CurriculumRef> curriculums, Collection<CurriculumElement> elements, Identity... identities) { + public List<CurriculumElementMembership> getMembershipInfos(List<? extends CurriculumRef> curriculums, Collection<CurriculumElement> elements, Identity... identities) { StringBuilder sb = new StringBuilder(256); sb.append("select el.key, membership from curriculumelement el") .append(" inner join el.group baseGroup") diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java index 6afbd5dc9f3dcf96cd52fcb6b8d9037f0e5ee491..74175307c96ee931f18304a338253edf6ead4816 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumRepositoryEntryRelationDAO.java @@ -172,7 +172,7 @@ public class CurriculumRepositoryEntryRelationDAO { * @param curriculum The curriculum * @return A map of curriculum element to their repository entries */ - public Map<CurriculumElement, List<Long>> getCurriculumElementsWithRepositoryEntryKeys(List<CurriculumRef> curriculums) { + public Map<CurriculumElement, List<Long>> getCurriculumElementsWithRepositoryEntryKeys(List<? extends CurriculumRef> curriculums) { if(curriculums == null || curriculums.isEmpty()) return Collections.emptyMap(); QueryBuilder sb = new QueryBuilder(256); 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 c5a11a19f6f9ca9a3a683317a9a17e35eb8e8f82..4993272a91b65431a4b3f4bd1cf645ab507236f6 100644 --- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java +++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java @@ -866,7 +866,7 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat } @Override - public List<CurriculumElementRepositoryEntryViews> getCurriculumElements(Identity identity, Roles roles, List<CurriculumRef> curriculums) { + public List<CurriculumElementRepositoryEntryViews> getCurriculumElements(Identity identity, Roles roles, List<? extends CurriculumRef> curriculums) { if(curriculums == null || curriculums.isEmpty()) return Collections.emptyList(); List<CurriculumElementMembership> memberships = curriculumElementDao.getMembershipInfos(curriculums, null, identity); 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 46f5889befb4af3726e60ff9267fee01e200a328..36ffa7701e124387737190aabdec9516af1499cc 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 @@ -111,6 +111,7 @@ table.header.completion=$org.olat.modules.assessment.ui\:learning.progress table.header.curriculum=Curriculum table.header.curriculum.element.displayName=Name table.header.curriculum.element.identifier=Bezeichnung +table.header.curriculum.element.has.statement=Leistungsnachweis vorhanden table.header.details=<i class\="o_icon o_icon-lg o_icon_details" title\="Infoseite"> </i> table.header.displayName=Name table.header.edit=Bearbeiten 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 8d8b2ba8da8b9671e0363fe782a1c9dd573cbc02..cd542c2674be9f14fd8acff61c5a473b337592fc 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 @@ -110,6 +110,7 @@ table.header.calendars=Calendar table.header.completion=$org.olat.modules.assessment.ui\:learning.progress table.header.curriculum=Curriculum table.header.curriculum.element.displayName=Name +table.header.curriculum.element.has.statement=Has Statement table.header.curriculum.element.identifier=Identifier table.header.details=<i class\="o_icon o_icon-lg o_icon_details" title\="Info page"> </i> table.header.displayName=Name diff --git a/src/main/java/org/olat/modules/quality/QualityReportAccessRightProvider.java b/src/main/java/org/olat/modules/quality/QualityReportAccessRightProvider.java index 2f0a486f33ce9fe602640cdb0d9c804cff85d3d0..9406cc5fd20660b2805620490773e7c3388f835c 100644 --- a/src/main/java/org/olat/modules/quality/QualityReportAccessRightProvider.java +++ b/src/main/java/org/olat/modules/quality/QualityReportAccessRightProvider.java @@ -19,9 +19,12 @@ */ package org.olat.modules.quality; +import java.util.Collection; +import java.util.Collections; import java.util.Locale; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.OrganisationRoles; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Util; import org.olat.modules.quality.ui.QualityMainController; @@ -34,23 +37,38 @@ import org.springframework.stereotype.Component; * */ @Component -public class QualityReportAccessRightProvider implements RelationRightProvider { +public class QualityReportAccessRightProvider implements RightProvider { public static final String RELATION_RIGHT = "selectableQualityReportAccess"; @Override - public RelationRightProvider getParent() { + public String getRight() { + return RELATION_RIGHT; + } + + @Override + public RightProvider getParent() { return null; } @Override - public int getPosition() { - return Order.QualityReportAccessRight.ordinal(); + public boolean isUserRelationsRight() { + return true; } - + @Override - public String getRight() { - return RELATION_RIGHT; + public int getUserRelationsPosition() { + return UserRelationRightsOrder.QualityReportAccessRight.ordinal(); + } + + @Override + public Collection<OrganisationRoles> getOrganisationRoles() { + return Collections.emptyList(); + } + + @Override + public int getOrganisationPosition() { + return -1; } @Override diff --git a/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java b/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java index a7207b5e70624ca43fd122ad7a89d70af8c7a8d9..2e30cb192bbe97e3fcb5bff98beedef21702f315 100644 --- a/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java +++ b/src/main/java/org/olat/repository/model/SearchMyRepositoryEntryViewParams.java @@ -47,7 +47,7 @@ public class SearchMyRepositoryEntryViewParams { private List<Filter> filters; private CatalogEntry parentEntry; private List<String> resourceTypes; - private List<CurriculumRef> curriculums; + private List<? extends CurriculumRef> curriculums; private String idAndRefs; private String idRefsAndTitle; @@ -76,11 +76,11 @@ public class SearchMyRepositoryEntryViewParams { this.membershipMandatory = membershipMandatory; } - public List<CurriculumRef> getCurriculums() { + public List<? extends CurriculumRef> getCurriculums() { return curriculums; } - public void setCurriculums(List<CurriculumRef> curriculums) { + public void setCurriculums(List<? extends CurriculumRef> curriculums) { this.curriculums = curriculums; } diff --git a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml index 8d509faafad9553a06e1b357f9c6aa78588177b4..6bafc0f7595165a882d6102e2c5d5b8cf96af41b 100644 --- a/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml +++ b/src/main/java/org/olat/user/propertyhandlers/_spring/userPropertiesContext.xml @@ -1291,7 +1291,7 @@ </bean> </entry> - <entry key="org.olat.modules.coach.ui.UserRelationOverviewController"> + <entry key="org.olat.modules.coach.ui.UserOverviewController"> <bean class="org.olat.user.propertyhandlers.UserPropertyUsageContext"> <property name="description" value="Short description of a user" /> <property name="propertyHandlers"> diff --git a/src/main/java/org/olat/user/ui/role/EditRelationRoleController.java b/src/main/java/org/olat/user/ui/role/EditRelationRoleController.java index c65561b3e12bf9804642263e6a29154dcbc61fbe..023e787a014bc80b8fed00b88ec92c18ebb5611f 100644 --- a/src/main/java/org/olat/user/ui/role/EditRelationRoleController.java +++ b/src/main/java/org/olat/user/ui/role/EditRelationRoleController.java @@ -30,10 +30,10 @@ import java.util.stream.Collectors; import org.olat.basesecurity.IdentityRelationshipService; import org.olat.basesecurity.RelationRight; -import org.olat.basesecurity.RelationRightProvider; import org.olat.basesecurity.RelationRole; import org.olat.basesecurity.RelationRoleManagedFlag; import org.olat.basesecurity.RelationRoleToRight; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -66,8 +66,7 @@ public class EditRelationRoleController extends FormBasicController { "", "supervisor", "legalRepresentative", "tutor", "parent", "teacher", "expert", "legalGardian", "employer", "sportsClub" }; - private static final String INTENDING = "\u00a0"; // non-breaking space - + private TextElement roleEl; private SingleSelection predefinedLabelEl; private MultipleSelectionElement rightsEl; @@ -75,7 +74,7 @@ public class EditRelationRoleController extends FormBasicController { private RelationRole relationRole; String[] rightKeys; String[] rightValues; - List<RelationRightProvider> rightProviders; + List<RightProvider> rightProviders; @Autowired private I18nModule i18nModule; @@ -84,19 +83,15 @@ public class EditRelationRoleController extends FormBasicController { @Autowired private IdentityRelationshipService identityRelationsService; @Autowired - private List<RelationRightProvider> relationRights; + private List<RightProvider> relationRights; - public EditRelationRoleController(UserRequest ureq, WindowControl wControl) { - this(ureq, wControl,null); - } - public EditRelationRoleController(UserRequest ureq, WindowControl wControl, RelationRole relationRole) { super(ureq, wControl, Util.createPackageTranslator(UserModule.class, ureq.getLocale())); this.relationRole = relationRole; this.rightKeys = new String[relationRights.size()]; this.rightValues = new String[relationRights.size()]; this.rightProviders = new ArrayList<>(relationRights.size()); - this.relationRights.sort(Comparator.comparing(RelationRightProvider::getPosition)); + this.relationRights.sort(Comparator.comparing(RightProvider::getUserRelationsPosition)); initForm(ureq); } @@ -233,7 +228,7 @@ public class EditRelationRoleController extends FormBasicController { private void checkDependentRights() { for(int i=0; i < relationRights.size(); i++) { - RelationRightProvider rightProvider = rightProviders.get(i); + RightProvider rightProvider = rightProviders.get(i); if (rightProvider.getParent() != null) { int parentIndex = rightProviders.indexOf(rightProvider.getParent()); diff --git a/src/main/java/org/olat/user/ui/role/RelationRolesAdminController.java b/src/main/java/org/olat/user/ui/role/RelationRolesAdminController.java index 13cacb6a7bdfec2899496162d61b7fbdae2f75e3..403b334955a7ff9ff6d0409a4cabc5fa89d33165 100644 --- a/src/main/java/org/olat/user/ui/role/RelationRolesAdminController.java +++ b/src/main/java/org/olat/user/ui/role/RelationRolesAdminController.java @@ -25,6 +25,7 @@ import java.util.List; import org.olat.basesecurity.BaseSecurityModule; import org.olat.basesecurity.IdentityRelationshipService; import org.olat.basesecurity.RelationRole; +import org.olat.basesecurity.RightProvider; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -77,7 +78,7 @@ public class RelationRolesAdminController extends FormBasicController { private BaseSecurityModule securityModule; @Autowired private IdentityRelationshipService identityRelationsService; - + public RelationRolesAdminController(UserRequest ureq, WindowControl wControl) { super(ureq, wControl, "relation_roles", Util.createPackageTranslator(UserModule.class, ureq.getLocale())); initForm(ureq); @@ -131,6 +132,7 @@ public class RelationRolesAdminController extends FormBasicController { private void loadModel() { List<RelationRole> relationRoles = identityRelationsService.getAvailableRoles(); + List<RelationRoleRow> rows = new ArrayList<>(relationRoles.size()); for(RelationRole relationRole:relationRoles) { rows.add(new RelationRoleRow(relationRole)); @@ -143,9 +145,10 @@ public class RelationRolesAdminController extends FormBasicController { @Override protected void event(UserRequest ureq, Controller source, Event event) { if(editRoleCtrl == source || translatorCtrl == source) { - if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { - loadModel(); + if(event == Event.DONE_EVENT) { + System.out.println("save"); } + loadModel(); cmc.deactivate(); cleanUp(); } else if(confirmDeleteCtrl == source) { @@ -207,8 +210,9 @@ public class RelationRolesAdminController extends FormBasicController { private void doAddRole(UserRequest ureq) { if(guardModalController(editRoleCtrl)) return; - - editRoleCtrl = new EditRelationRoleController(ureq, getWindowControl()); + + List<RightProvider> userRelationRights = identityRelationsService.getAvailableRightProviders(); + editRoleCtrl = new EditRelationRoleController(ureq, getWindowControl(), null); listenTo(editRoleCtrl); cmc = new CloseableModalController(getWindowControl(), "close", editRoleCtrl.getInitialComponent(), true, translate("add.role")); diff --git a/src/main/java/org/olat/user/ui/role/RelationRolesAndRightsUIFactory.java b/src/main/java/org/olat/user/ui/role/RelationRolesAndRightsUIFactory.java index 1845f786ddded122571c512534e999414a56cafb..5cceaf0577e17bd7c9fcb30199616ab267a98815 100644 --- a/src/main/java/org/olat/user/ui/role/RelationRolesAndRightsUIFactory.java +++ b/src/main/java/org/olat/user/ui/role/RelationRolesAndRightsUIFactory.java @@ -24,7 +24,7 @@ import java.util.Locale; import org.apache.logging.log4j.Level; import org.olat.basesecurity.IdentityRelationshipService; import org.olat.basesecurity.RelationRight; -import org.olat.basesecurity.RelationRightProvider; +import org.olat.basesecurity.RightProvider; import org.olat.basesecurity.RelationRole; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.translator.Translator; @@ -46,7 +46,7 @@ public class RelationRolesAndRightsUIFactory { public static String getTranslatedRight(RelationRight right, Locale locale) { IdentityRelationshipService relationshipService = CoreSpringFactory.getImpl(IdentityRelationshipService.class); - RelationRightProvider provider = relationshipService.getRelationRightProvider(right); + RightProvider provider = relationshipService.getRelationRightProvider(right); return provider != null? provider.getTranslatedName(locale): "???"; } diff --git a/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_de.properties index 761735a8db3fd596f4bea4bfd4183799ae4419d4..e6b93336716fe122cd47c639ae71f96445167cc9 100644 --- a/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/user/ui/role/_i18n/LocalStrings_de.properties @@ -15,6 +15,7 @@ on=ein predefined.labels=Vordefinierte Bezeichnungen relations.enable=Rolle Benutzer zu Benutzer role.identifier=Bezeichnung +role.line.manager=Linienvorgesetzter role.name=Rolle role.rights=Rechte table.header.id=ID diff --git a/src/test/java/org/olat/basesecurity/manager/IdentityToIdentityRelationDAOTest.java b/src/test/java/org/olat/basesecurity/manager/IdentityToIdentityRelationDAOTest.java index 7bf7b72debad3f3d9cf6226669772c1c39704b4d..b5638f184c6e952ccd6aa207c17e442e159cfee2 100644 --- a/src/test/java/org/olat/basesecurity/manager/IdentityToIdentityRelationDAOTest.java +++ b/src/test/java/org/olat/basesecurity/manager/IdentityToIdentityRelationDAOTest.java @@ -57,7 +57,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void createIdentityToIdentityRelation() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-1"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-2"); dbInstance.commitAndCloseSession(); @@ -76,7 +76,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void isUsed_yes() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-1"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-2"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, null, null); @@ -90,7 +90,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void isUsed_no() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); dbInstance.commitAndCloseSession(); boolean used = identityToIdentityRelationDao.isUsed(relationRole); @@ -100,7 +100,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void hasRelation() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-1"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-2"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, null, null); @@ -120,7 +120,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void getRelation() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-1"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-2"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, "External-id", "all"); @@ -141,7 +141,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void getRelationsAsSource() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-1"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-2"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, null, null); @@ -162,7 +162,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void getRelationsAsTarget() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-1"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-2"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, null, null); @@ -184,9 +184,9 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void getRelationsAsTarget_filterRight() { // Init roles - RelationRole roleA = relationRoleDao.createRelationRole(random(), null, null, null); - RelationRole roleB = relationRoleDao.createRelationRole(random(), null, null, null); - RelationRole roleNoRight = relationRoleDao.createRelationRole(random(), null, null, null); + RelationRole roleA = relationRoleDao.createRelationRole(random(), null, null, null, true); + RelationRole roleB = relationRoleDao.createRelationRole(random(), null, null, null, true); + RelationRole roleNoRight = relationRoleDao.createRelationRole(random(), null, null, null, true); // Init rights relationRightDao.ensureRightExists("testRight"); RelationRight right = relationRightDao.loadRelationRightByRight("testRight"); @@ -225,7 +225,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void getSources() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-8"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-9"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, null, null); @@ -240,7 +240,7 @@ public class IdentityToIdentityRelationDAOTest extends OlatTestCase { @Test public void getTargets() { String role = random(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); Identity idSource = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-8"); Identity idTarget = JunitTestHelper.createAndPersistIdentityAsRndUser("id-2-id-9"); IdentityToIdentityRelation relation = identityToIdentityRelationDao.createRelation(idSource, idTarget, relationRole, null, null); diff --git a/src/test/java/org/olat/basesecurity/manager/RelationRoleDAOTest.java b/src/test/java/org/olat/basesecurity/manager/RelationRoleDAOTest.java index 199cec34436743670461cee74bd9041da66a4cd9..d433ab40a26de3ae83d8009a3bc9c0233140a79d 100644 --- a/src/test/java/org/olat/basesecurity/manager/RelationRoleDAOTest.java +++ b/src/test/java/org/olat/basesecurity/manager/RelationRoleDAOTest.java @@ -54,7 +54,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void createRelationRole() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, "External-id", "External-ref", null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, "External-id", "External-ref", null, true); dbInstance.commit(); Assert.assertNotNull(relationRole); @@ -68,7 +68,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void loadRelationRole_byKey() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); dbInstance.commitAndCloseSession(); RelationRole loadedRelationRole = relationRoleDao.loadRelationRoleByKey(relationRole.getKey()); @@ -81,7 +81,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void loadRelationRole_byRole() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); dbInstance.commitAndCloseSession(); RelationRole loadedRelationRole = relationRoleDao.loadRelationRoleByRole(role); @@ -96,9 +96,9 @@ public class RelationRoleDAOTest extends OlatTestCase { String role1 = UUID.randomUUID().toString(); String role2 = UUID.randomUUID().toString(); String roleOther = UUID.randomUUID().toString(); - RelationRole relationRole1 = relationRoleDao.createRelationRole(role1, null, null, null); - RelationRole relationRole2 = relationRoleDao.createRelationRole(role2, null, null, null); - RelationRole relationRole3 = relationRoleDao.createRelationRole(roleOther, null, null, null); + RelationRole relationRole1 = relationRoleDao.createRelationRole(role1, null, null, null, true); + RelationRole relationRole2 = relationRoleDao.createRelationRole(role2, null, null, null, true); + RelationRole relationRole3 = relationRoleDao.createRelationRole(roleOther, null, null, null, true); String right1 = UUID.randomUUID().toString(); RelationRight relationRight1 = relationRightDao.createRelationRight(right1); String rightOther = UUID.randomUUID().toString(); @@ -117,7 +117,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void addRight() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); String right = UUID.randomUUID().toString(); RelationRight relationRight = relationRightDao.createRelationRight(right); relationRoleDao.addRight(relationRole, relationRight); @@ -138,7 +138,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void setRights_once() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); String right = UUID.randomUUID().toString(); RelationRight relationRight1 = relationRightDao.createRelationRight(right + "-1"); RelationRight relationRight2 = relationRightDao.createRelationRight(right + "-2"); @@ -167,7 +167,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void setRights_twice() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); String right = UUID.randomUUID().toString(); RelationRight relationRight1 = relationRightDao.createRelationRight(right + "-1"); RelationRight relationRight2 = relationRightDao.createRelationRight(right + "-2"); @@ -217,7 +217,7 @@ public class RelationRoleDAOTest extends OlatTestCase { @Test public void deleteRelationRole() { String role = UUID.randomUUID().toString(); - RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null); + RelationRole relationRole = relationRoleDao.createRelationRole(role, null, null, null, true); String right = UUID.randomUUID().toString(); RelationRight relationRight1 = relationRightDao.createRelationRight(right + "-1"); RelationRight relationRight2 = relationRightDao.createRelationRight(right + "-2");