From 079057d10df1e9e53303ff0fb0265b3db866f87a Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Fri, 3 Jun 2016 09:53:19 +0200 Subject: [PATCH] OO-2046: fix selenium, fix rs in coaching tool, add table search in coaching tool --- .../basesecurity/BaseSecurityManager.java | 4 + .../table/DefaultFlexiColumnModel.java | 10 ++ .../org/olat/ims/qti/QTIResultManager.java | 1 - .../modules/coach/manager/CoachingDAO.java | 142 ++++++++------- .../modules/coach/ui/CourseController.java | 8 +- ...fficiencyStatementEntryTableDataModel.java | 19 +- .../modules/coach/ui/GroupController.java | 6 +- .../coach/ui/StudentCoursesController.java | 170 ++++++++++-------- .../coach/ui/StudentListController.java | 14 +- .../modules/coach/ui/StudentListProvider.java | 79 ++++++++ .../coach/ui/StudentsTableDataModel.java | 63 ++++++- .../modules/coach/ui/UserListController.java | 5 +- .../ui/_content/student_course_list.html | 12 +- .../modules/reminder/manager/ReminderDAO.java | 4 +- .../manager/RepositoryEntryRelationDAO.java | 16 +- src/main/java/org/olat/user/UserImpl.java | 5 + .../basesecurity/BaseSecurityManagerTest.java | 12 ++ 17 files changed, 397 insertions(+), 173 deletions(-) create mode 100644 src/main/java/org/olat/modules/coach/ui/StudentListProvider.java diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java index 48ea10f339e..6e798d65f6e 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java @@ -72,6 +72,7 @@ import org.olat.portfolio.manager.InvitationDAO; import org.olat.resource.OLATResource; import org.olat.resource.OLATResourceManager; import org.olat.user.ChangePasswordController; +import org.olat.user.UserImpl; import org.olat.user.UserManager; /** @@ -694,6 +695,7 @@ public class BaseSecurityManager implements BaseSecurity { public Identity createAndPersistIdentity(String username, User user, String provider, String authusername, String credential) { IdentityImpl iimpl = new IdentityImpl(username, user); dbInstance.getCurrentEntityManager().persist(iimpl); + ((UserImpl)user).setIdentity(iimpl); if (provider != null) { createAndPersistAuthenticationIntern(iimpl, provider, authusername, credential, loginModule.getDefaultHashAlgorithm()); } @@ -714,6 +716,7 @@ public class BaseSecurityManager implements BaseSecurity { IdentityImpl iimpl = new IdentityImpl(username, user); iimpl.setExternalId(externalId); dbInstance.getCurrentEntityManager().persist(iimpl); + ((UserImpl)user).setIdentity(iimpl); if (provider != null) { createAndPersistAuthenticationIntern(iimpl, provider, authusername, null, null); } @@ -737,6 +740,7 @@ public class BaseSecurityManager implements BaseSecurity { IdentityImpl iimpl = new IdentityImpl(username, user); iimpl.setExternalId(externalId); dbInstance.getCurrentEntityManager().persist(iimpl); + ((UserImpl)user).setIdentity(iimpl); if (provider != null) { createAndPersistAuthenticationIntern(iimpl, provider, authusername, credential, loginModule.getDefaultHashAlgorithm()); } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java index fe5569d7e55..3eba71c2052 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/DefaultFlexiColumnModel.java @@ -63,11 +63,21 @@ public class DefaultFlexiColumnModel implements FlexiColumnModel { new StaticFlexiCellRenderer(action, new TextFlexiCellRenderer())); } + public DefaultFlexiColumnModel(boolean defVisible, FlexiColumnDef def, String action) { + this(defVisible, false, def.i18nHeaderKey(), def.ordinal(), action, false, null, FlexiColumnModel.ALIGNMENT_LEFT, + new StaticFlexiCellRenderer(action, new TextFlexiCellRenderer())); + } + public DefaultFlexiColumnModel(FlexiSortableColumnDef def, String action) { this(true, false, def.i18nHeaderKey(), def.ordinal(), action, def.sortable(), def.sortKey(), FlexiColumnModel.ALIGNMENT_LEFT, new StaticFlexiCellRenderer(action, new TextFlexiCellRenderer())); } + public DefaultFlexiColumnModel(boolean defVisible, FlexiSortableColumnDef def, String action) { + this(defVisible, false, def.i18nHeaderKey(), def.ordinal(), action, def.sortable(), def.sortKey(), FlexiColumnModel.ALIGNMENT_LEFT, + new StaticFlexiCellRenderer(action, new TextFlexiCellRenderer())); + } + public DefaultFlexiColumnModel(FlexiColumnDef def, FlexiCellRenderer renderer) { this(true, false, def.i18nHeaderKey(), def.ordinal(), null, false, null, FlexiColumnModel.ALIGNMENT_LEFT, renderer); } diff --git a/src/main/java/org/olat/ims/qti/QTIResultManager.java b/src/main/java/org/olat/ims/qti/QTIResultManager.java index 57f9c4b3bc7..e7217678bb8 100644 --- a/src/main/java/org/olat/ims/qti/QTIResultManager.java +++ b/src/main/java/org/olat/ims/qti/QTIResultManager.java @@ -37,7 +37,6 @@ import javax.persistence.TypedQuery; import org.olat.basesecurity.Group; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; -import org.olat.core.id.UserConstants; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; import org.olat.user.UserDataDeletable; diff --git a/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java b/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java index d73030e5ab8..0bc6c5bf97e 100644 --- a/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java +++ b/src/main/java/org/olat/modules/coach/manager/CoachingDAO.java @@ -40,7 +40,6 @@ import org.olat.core.commons.persistence.PersistenceHelper; import org.olat.core.id.Identity; import org.olat.core.logging.OLog; import org.olat.core.logging.Tracing; -import org.olat.core.util.CodeHelper; import org.olat.core.util.StringHelper; import org.olat.course.assessment.UserEfficiencyStatement; import org.olat.course.assessment.model.UserEfficiencyStatementLight; @@ -620,9 +619,7 @@ public class CoachingDAO { protected List<StudentStatEntry> getStudentsStatisticsNative(Identity coach, List<UserPropertyHandler> userPropertyHandlers) { Map<Long, StudentStatEntry> map = new HashMap<>(); - long start = System.nanoTime(); boolean hasCoachedStudents = getStudentsStastisticInfosForCoach(coach, map, userPropertyHandlers); - CodeHelper.printNanoTime(start, "Coach stats infos"); boolean hasOwnedStudents = getStudentsStastisticInfosForOwner(coach, map, userPropertyHandlers); if(hasOwnedStudents || hasCoachedStudents) { for(StudentStatEntry entry:map.values()) { @@ -631,7 +628,7 @@ public class CoachingDAO { entry.setInitialLaunch(entry.getLaunchIds().size()); entry.setLaunchIds(null); } - getStudentsStatisticStatement(coach, map); + getStudentsStatisticStatement(coach, hasCoachedStudents, hasOwnedStudents, map); for(StudentStatEntry entry:map.values()) { int notAttempted = entry.getCountRepo() - entry.getCountPassed() - entry.getCountFailed(); entry.setCountNotAttempted(notAttempted); @@ -641,39 +638,6 @@ public class CoachingDAO { } private boolean getStudentsStastisticInfosForCoach(IdentityRef coach, Map<Long, StudentStatEntry> map, List<UserPropertyHandler> userPropertyHandlers) { - /* - NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance); - sb.append("select") - .append(" sg_participant.fk_identity_id as part_id,") - .append(" ").appendToArray("sg_re.repositoryentry_id").append(" as re_ids,") - .append(" ").appendToArray("pg_initial_launch.id").append(" as pg_ids") - .append(" from o_repositoryentry sg_re") - .append(" inner join o_olatresource sg_res on (sg_res.resource_id = sg_re.fk_olatresource and sg_res.resname = 'CourseModule') ") - .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id)") - .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach')") - .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant')") - .append(" left join o_as_user_course_infos pg_initial_launch") - .append(" on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = sg_participant.fk_identity_id)") - .append(" where sg_coach.fk_identity_id=:coachKey and ( ") - .append(" (sg_re.accesscode >= ").append(RepositoryEntry.ACC_USERS).append(" and sg_coach.g_role = 'coach') ")//BAR - .append(" or ") - .append(" (sg_re.accesscode = ").append(RepositoryEntry.ACC_OWNERS).append(" and sg_re.membersonly=").appendTrue().append(")) ") - .append(" group by sg_participant.fk_identity_id"); - - List<?> rawList = dbInstance.getCurrentEntityManager() - .createNativeQuery(sb.toString()) - .setParameter("coachKey", coach.getKey()) - .getResultList(); - - for(Object rawObject:rawList) { - Object[] rawStat = (Object[])rawObject; - StudentStatEntry entry = new StudentStatEntry(((Number)rawStat[0]).longValue()); - appendArrayToSet(rawStat[1], entry.getRepoIds()); - appendArrayToSet(rawStat[2], entry.getLaunchIds()); - map.put(entry.getStudentKey(), entry); - } - */ - NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance); sb.append("select") .append(" sg_participant_id.id as part_id,") @@ -818,7 +782,7 @@ public class CoachingDAO { } } - private boolean getStudentsStatisticStatement(IdentityRef coach, Map<Long,StudentStatEntry> stats) { + private boolean getStudentsStatisticStatement(IdentityRef coach, boolean hasCoached, boolean hasOwned, Map<Long,StudentStatEntry> stats) { NativeQueryBuilder sb = new NativeQueryBuilder(1024, dbInstance); sb.append("select ") .append(" fin_statement.fk_identity, ") @@ -826,29 +790,40 @@ public class CoachingDAO { .append(" sum(case when fin_statement.passed=").appendTrue().append(" then 1 else 0 end) as num_of_passed, ") .append(" sum(case when fin_statement.passed=").appendFalse().append(" then 1 else 0 end) as num_of_failed ") .append(" from o_as_eff_statement fin_statement ") - .append(" where fin_statement.id in ( select ") - .append(" distinct sg_statement.id as st_id ") - .append(" from o_repositoryentry sg_re ") - .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ") - .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach') ") - .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant') ") - .append(" inner join o_as_eff_statement sg_statement ") - .append(" on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ") - .append(" where sg_coach.fk_identity_id=:coachKey and ( ") - .append(" (sg_re.accesscode>2 and sg_coach.g_role = 'coach') ") - .append(" or ") - .append(" (sg_re.accesscode=1 and sg_re.membersonly=").appendTrue().append(")) ") - .append(" ) or fin_statement.id in ( select ") - .append(" distinct sg_statement.id as st_id ") - .append(" from o_repositoryentry sg_re ") - .append(" inner join o_re_to_group owngroup on (owngroup.fk_entry_id = sg_re.repositoryentry_id and owngroup.r_defgroup=").appendTrue().append(") ") - .append(" inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner') ") - .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ") - .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ") - .append(" inner join o_as_eff_statement sg_statement ") - .append(" on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ") - .append(" where sg_owner.fk_identity_id=:coachKey and sg_re.accesscode>=").append(RepositoryEntry.ACC_OWNERS).append(") ") - .append(" group by fin_statement.fk_identity"); + .append(" where "); + if(hasCoached) { + sb.append(" fin_statement.id in ( select ") + .append(" distinct sg_statement.id as st_id ") + .append(" from o_repositoryentry sg_re ") + .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ") + .append(" inner join o_bs_group_member sg_coach on (sg_coach.fk_group_id=togroup.fk_group_id and sg_coach.g_role = 'coach') ") + .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=sg_coach.fk_group_id and sg_participant.g_role='participant') ") + .append(" inner join o_as_eff_statement sg_statement ") + .append(" on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ") + .append(" where sg_coach.fk_identity_id=:coachKey and ( ") + .append(" (sg_re.accesscode>2 and sg_coach.g_role = 'coach') ") + .append(" or ") + .append(" (sg_re.accesscode=1 and sg_re.membersonly=").appendTrue().append(")) ") + .append(" )"); + } + if(hasOwned) { + if(hasCoached) { + sb.append(" or "); + } + + sb.append(" fin_statement.id in ( select ") + .append(" distinct sg_statement.id as st_id ") + .append(" from o_repositoryentry sg_re ") + .append(" inner join o_re_to_group owngroup on (owngroup.fk_entry_id = sg_re.repositoryentry_id and owngroup.r_defgroup=").appendTrue().append(") ") + .append(" inner join o_bs_group_member sg_owner on (sg_owner.fk_group_id=owngroup.fk_group_id and sg_owner.g_role = 'owner') ") + .append(" inner join o_re_to_group togroup on (togroup.fk_entry_id = sg_re.repositoryentry_id) ") + .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ") + .append(" inner join o_as_eff_statement sg_statement ") + .append(" on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ") + .append(" where sg_owner.fk_identity_id=:coachKey and sg_re.accesscode>=").append(RepositoryEntry.ACC_OWNERS).append(") "); + + } + sb.append(" group by fin_statement.fk_identity"); List<?> rawList = dbInstance.getCurrentEntityManager() .createNativeQuery(sb.toString()) @@ -902,8 +877,8 @@ public class CoachingDAO { .append(" inner join o_bs_identity sg_participant_id on (sg_participant_id.id=sg_participant.fk_identity_id)") .append(" inner join o_user sg_participant_user on (sg_participant_user.user_id=sg_participant_id.fk_user_id)") .append(" left join o_as_user_course_infos pg_initial_launch ") - .append(" on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = id_participant.id) "); - appendUsersStatisticsJoins(params, queryParams, sb) + .append(" on (pg_initial_launch.fk_resource_id = sg_re.fk_olatresource and pg_initial_launch.fk_identity = id_participant.id) ") + .append(" inner join o_user user_participant on (user_participant.user_id=id_participant.fk_user_id)") .append(" where sg_re.accesscode >= ").append(RepositoryEntry.ACC_OWNERS).append(" "); appendUsersStatisticsSearchParams(params, queryParams, sb) .append(" group by sg_participant_id.id, sg_participant_user.user_id"); @@ -951,7 +926,7 @@ public class CoachingDAO { .append(" inner join o_bs_group_member sg_participant on (sg_participant.fk_group_id=togroup.fk_group_id and sg_participant.g_role='participant') ") .append(" inner join o_as_eff_statement sg_statement on (sg_statement.fk_identity = sg_participant.fk_identity_id and sg_statement.fk_resource_id = sg_re.fk_olatresource) ") .append(" inner join o_bs_identity id_participant on (sg_participant.fk_identity_id = id_participant.id) "); - appendUsersStatisticsJoins(params, queryParams, sb) + appendUsersStatisticsJoins(params, sb) .append(" where sg_re.accesscode>0 "); appendUsersStatisticsSearchParams(params, queryParams, sb) .append(") ") @@ -980,7 +955,7 @@ public class CoachingDAO { } - private NativeQueryBuilder appendUsersStatisticsJoins(SearchCoachedIdentityParams params, Map<String,Object> queryParams, NativeQueryBuilder sb) { + private NativeQueryBuilder appendUsersStatisticsJoins(SearchCoachedIdentityParams params, NativeQueryBuilder sb) { if(params != null && params.getUserProperties() != null && params.getUserProperties().size() > 0) { sb.append(" inner join o_user user_participant on (user_participant.user_id=id_participant.fk_user_id)"); } @@ -1042,6 +1017,43 @@ public class CoachingDAO { return sb; } + public List<Identity> getStudents(Identity coach) { + StringBuilder sc = new StringBuilder(); + sc.append("select participantIdent from repositoryentry as re") + .append(" inner join re.groups as ownedRelGroup on ownedRelGroup.defaultGroup=true") + .append(" inner join ownedRelGroup.group as ownedGroup") + .append(" inner join ownedGroup.members as owner on owner.role='owner'") + .append(" inner join re.groups as relGroup") + .append(" inner join relGroup.group as baseGroup") + .append(" inner join baseGroup.members as participant on participant.role='participant'") + .append(" inner join participant.identity as participantIdent") + .append(" inner join fetch participantIdent.user as participantUser") + .append(" where owner.identity.key=:coachKey and re.key=:repoKey"); + + List<Identity> identityKeys = dbInstance.getCurrentEntityManager() + .createQuery(sc.toString(), Identity.class) + .setParameter("coachKey", coach.getKey()) + .getResultList(); + + //owner see all participants + if(identityKeys.isEmpty()) { + StringBuilder sb = new StringBuilder(); + sb.append("select participantIdent from repoentrytogroup as relGroup ") + .append(" inner join relGroup.group as baseGroup") + .append(" inner join baseGroup.members as coach on coach.role = 'coach'") + .append(" inner join baseGroup.members as participant on participant.role='participant'") + .append(" inner join participant.identity as participantIdent") + .append(" inner join fetch participantIdent.user as participantUser") + .append(" where coach.identity.key=:coachKey and relGroup.entry.key=:repoKey"); + + identityKeys = dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Identity.class) + .setParameter("coachKey", coach.getKey()) + .getResultList(); + } + return new ArrayList<>(new HashSet<>(identityKeys)); + } + public List<Identity> getStudents(Identity coach, RepositoryEntry entry) { StringBuilder sc = new StringBuilder(); sc.append("select participantIdent from repositoryentry as re") diff --git a/src/main/java/org/olat/modules/coach/ui/CourseController.java b/src/main/java/org/olat/modules/coach/ui/CourseController.java index 5466fda9067..e70068e39ce 100644 --- a/src/main/java/org/olat/modules/coach/ui/CourseController.java +++ b/src/main/java/org/olat/modules/coach/ui/CourseController.java @@ -54,7 +54,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OresHelper; -import org.olat.course.assessment.ui.tool.AssessmentToolConstants; +import org.olat.course.assessment.bulk.PassedCellRenderer; import org.olat.course.certificate.CertificateEvent; import org.olat.course.certificate.CertificateLight; import org.olat.course.certificate.CertificatesManager; @@ -189,22 +189,20 @@ public class CourseController extends FormBasicController implements Activateabl 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", false, null)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", true, null)); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.repoName)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.passed)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.passed, new PassedCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.certificate, new DownloadCertificateCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.score, new ScoreCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification)); - model = new EfficiencyStatementEntryTableDataModel(columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); tableEl.setExportEnabled(true); tableEl.setEmtpyTableMessageKey("error.no.found"); tableEl.setAndLoadPersistedPreferences(ureq, "fCourseController"); - } @Override diff --git a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java index 96fbab0d385..01de0398cb9 100644 --- a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java +++ b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java @@ -24,9 +24,10 @@ import java.util.concurrent.ConcurrentMap; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; import org.olat.course.assessment.UserEfficiencyStatement; import org.olat.course.certificate.CertificateLight; import org.olat.modules.coach.model.EfficiencyStatementEntry; @@ -62,8 +63,8 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat } @Override - public void sort(SortKey sortKey) { - // + public void sort(SortKey orderBy) { + setObjects(new SortableFlexiTableModelDelegate<>(orderBy, this, null).sort()); } @Override public Object getValueAt(int row, int col) { @@ -132,7 +133,7 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat return new EfficiencyStatementEntryTableDataModel(getTableColumnModel()); } - public static enum Columns implements FlexiColumnDef { + public static enum Columns implements FlexiSortableColumnDef { name("student.name"), repoName("table.header.course.name"), score("table.header.score"), @@ -152,6 +153,16 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat return i18nKey; } + @Override + public boolean sortable() { + return true; + } + + @Override + public String sortKey() { + return name(); + } + public static Columns getValueAt(int ordinal) { if(ordinal >= 0 && ordinal < values().length) { return values()[ordinal]; diff --git a/src/main/java/org/olat/modules/coach/ui/GroupController.java b/src/main/java/org/olat/modules/coach/ui/GroupController.java index 8002804b2a1..3fe1b8bb902 100644 --- a/src/main/java/org/olat/modules/coach/ui/GroupController.java +++ b/src/main/java/org/olat/modules/coach/ui/GroupController.java @@ -55,6 +55,7 @@ import org.olat.core.util.StringHelper; import org.olat.core.util.coordinate.CoordinatorManager; import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.resource.OresHelper; +import org.olat.course.assessment.bulk.PassedCellRenderer; import org.olat.course.certificate.CertificateEvent; import org.olat.course.certificate.CertificateLight; import org.olat.course.certificate.CertificatesManager; @@ -190,16 +191,15 @@ public class GroupController extends FormBasicController implements Activateable 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", false, null)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", true, null)); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.repoName)); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.passed)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.passed, new PassedCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.certificate, new DownloadCertificateCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.score, new ScoreCellRenderer())); columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification)); - model = new EfficiencyStatementEntryTableDataModel(columnsModel); tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); tableEl.setExportEnabled(true); diff --git a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java index 312a07fb0a7..b3570ea3493 100644 --- a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java +++ b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java @@ -28,21 +28,22 @@ import org.olat.NewControllerFactory; import org.olat.basesecurity.BaseSecurityModule; 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.FormLayoutContainer; +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.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; -import org.olat.core.gui.components.table.BooleanColumnDescriptor; -import org.olat.core.gui.components.table.ColumnDescriptor; -import org.olat.core.gui.components.table.CustomRenderColumnDescriptor; -import org.olat.core.gui.components.table.DefaultColumnDescriptor; -import org.olat.core.gui.components.table.TableController; -import org.olat.core.gui.components.table.TableEvent; -import org.olat.core.gui.components.table.TableGuiConfiguration; import org.olat.core.gui.components.text.TextComponent; -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.controller.BasicController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; import org.olat.core.id.Identity; @@ -57,6 +58,7 @@ import org.olat.core.util.event.GenericEventListener; import org.olat.core.util.mail.ContactList; import org.olat.core.util.mail.ContactMessage; import org.olat.core.util.resource.OresHelper; +import org.olat.course.assessment.bulk.PassedCellRenderer; import org.olat.course.certificate.CertificateEvent; import org.olat.course.certificate.CertificateLight; import org.olat.course.certificate.CertificatesManager; @@ -83,15 +85,14 @@ import org.springframework.beans.factory.annotation.Autowired; * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class StudentCoursesController extends BasicController implements Activateable2, GenericEventListener { +public class StudentCoursesController extends FormBasicController implements Activateable2, GenericEventListener { private final Link backLink, next, previous; private final Link nextStudent, previousStudent; private final Link homeLink, contactLink; private final TextComponent detailsCmp, detailsStudentCmp; - private final TableController tableCtr; - private final VelocityContainer mainVC; - private final VelocityContainer detailsVC; + + private FlexiTableElement tableEl; private EfficiencyStatementEntryTableDataModel model; private CloseableModalController cmc; @@ -119,7 +120,7 @@ public class StudentCoursesController extends BasicController implements Activat public StudentCoursesController(UserRequest ureq, WindowControl wControl, StudentStatEntry statEntry, Identity student, int index, int numOfStudents, boolean fullAccess) { - super(ureq, wControl); + super(ureq, wControl, "student_course_list"); setTranslator(userManager.getPropertyHandlerTranslator(getTranslator())); isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles()); userPropertyHandlers = userManager.getUserPropertyHandlersFor(UserListController.usageIdentifyer, isAdministrativeUser); @@ -127,40 +128,16 @@ public class StudentCoursesController extends BasicController implements Activat this.student = student; this.statEntry = statEntry; this.fullAccess = fullAccess; - - TableGuiConfiguration tableConfig = new TableGuiConfiguration(); - tableConfig.setTableEmptyMessage(translate("error.no.found")); - tableConfig.setDownloadOffered(true); - tableConfig.setPreferencesOffered(true, "studentCourseListController"); - tableCtr = new TableController(tableConfig, ureq, getWindowControl(), null, null, null, null, true, getTranslator()); - tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("student.name", Columns.name.ordinal(), "select", getLocale())); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.course.name", Columns.repoName.ordinal(), "select", getLocale())); - tableCtr.addColumnDescriptor(new BooleanColumnDescriptor("table.header.passed", Columns.passed.ordinal(), translate("passed.true"), translate("passed.false"))); - tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.score", Columns.score.ordinal(), "select", getLocale(), - ColumnDescriptor.ALIGNMENT_RIGHT, new ScoreCellRenderer())); - tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.certificate", Columns.certificate.ordinal(), null, getLocale(), - ColumnDescriptor.ALIGNMENT_LEFT, new DownloadCertificateCellRenderer(student))); - tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.progress", Columns.progress.ordinal(), null, getLocale(), - ColumnDescriptor.ALIGNMENT_LEFT, new ProgressRenderer(true, getTranslator()))); - tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.lastScoreDate", Columns.lastModification.ordinal(), "select", getLocale())); + initForm(ureq); - listenTo(tableCtr); List<EfficiencyStatementEntry> statements = loadModel(); - - mainVC = createVelocityContainer("student_course_list"); - detailsVC = createVelocityContainer("student_details"); - String fullName = StringHelper.escapeHtml(userManager.getUserDisplayName(student)); - - detailsVC.contextPut("studentName", fullName); - mainVC.put("studentDetails", detailsVC); - mainVC.put("studentsTable", tableCtr.getInitialComponent()); - + toolbar = new ToolbarController(ureq, wControl, getTranslator()); listenTo(toolbar); + flc.getFormItemComponent().put("toolbar", toolbar.getInitialComponent()); - mainVC.put("toolbar", toolbar.getInitialComponent()); backLink = toolbar.addToolbarLink("back", this, Position.left); backLink.setIconLeftCSS("o_icon o_icon_back"); previous = toolbar.addToolbarLink("previous.course", this, Position.center); @@ -189,21 +166,54 @@ public class StudentCoursesController extends BasicController implements Activat nextStudent.setCustomDisabledLinkCSS("navbar-text"); nextStudent.setEnabled(numOfStudents > 1); - contactLink = LinkFactory.createButton("contact.link", detailsVC, this); + contactLink = LinkFactory.createButton("contact.link", flc.getFormItemComponent(), this); contactLink.setIconLeftCSS("o_icon o_icon_mail"); - detailsVC.put("contact", contactLink); + flc.getFormItemComponent().put("contact", contactLink); - homeLink = LinkFactory.createButton("home.link", detailsVC, this); + homeLink = LinkFactory.createButton("home.link", flc.getFormItemComponent(), this); homeLink.setIconLeftCSS("o_icon o_icon_home"); - detailsVC.put("home", homeLink); + flc.getFormItemComponent().put("home", homeLink); setDetailsToolbarVisible(false); - putInitialPanel(mainVC); CoordinatorManager.getInstance().getCoordinator().getEventBus() .registerFor(this, getIdentity(), CertificatesManager.ORES_CERTIFICATE_EVENT); } - + + @Override + protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { + if(formLayout instanceof FormLayoutContainer) { + FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; + String fullName = StringHelper.escapeHtml(userManager.getUserDisplayName(student)); + layoutCont.contextPut("studentName", StringHelper.escapeHtml(fullName)); + } + + //add the table + FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); + if(isAdministrativeUser) { + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, Columns.name, "select")); + } + + 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, null)); + } + + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.repoName)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.passed, new PassedCellRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.score, new ScoreCellRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.certificate, new DownloadCertificateCellRenderer())); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.progress, new ProgressRenderer(true, getTranslator()))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification)); + + model = new EfficiencyStatementEntryTableDataModel(columnsModel); + tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); + tableEl.setExportEnabled(true); + tableEl.setEmtpyTableMessageKey("error.no.found"); + tableEl.setAndLoadPersistedPreferences(ureq, "fStudentCourseListController"); + } + @Override protected void doDispose() { CoordinatorManager.getInstance().getCoordinator().getEventBus() @@ -241,8 +251,9 @@ public class StudentCoursesController extends BasicController implements Activat certificateMap.put(key, certificate); } - //model = new EfficiencyStatementEntryTableDataModel(statements, certificateMap); - //tableCtr.setTableDataModel(model); + model.setObjects(statements, certificateMap); + tableEl.reset(); + tableEl.reloadData(); return statements; } @@ -255,7 +266,27 @@ public class StudentCoursesController extends BasicController implements Activat } @Override - protected void event(UserRequest ureq, Component source, Event event) { + 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(); + EfficiencyStatementEntry selectedRow = model.getObject(se.getIndex()); + if("select".equals(cmd)) { + selectDetails(ureq, selectedRow); + } + } + } + super.formInnerEvent(ureq, source, event); + } + + @Override + public void event(UserRequest ureq, Component source, Event event) { if (source == next) { nextEntry(ureq); } else if (source == previous) { @@ -267,19 +298,12 @@ public class StudentCoursesController extends BasicController implements Activat } else if (source == contactLink) { contact(ureq); } + super.event(ureq, source, event); } @Override protected void event(UserRequest ureq, Controller source, Event event) { - if(source == tableCtr) { - if(event instanceof TableEvent) { - TableEvent e = (TableEvent) event; - if("select".equals(e.getActionId())) { - EfficiencyStatementEntry entry = (EfficiencyStatementEntry)tableCtr.getTableDataModel().getObject(e.getRowId()); - selectDetails(ureq, entry); - } - } - } else if (source == statementCtrl) { + if (source == statementCtrl) { if(event == Event.CHANGED_EVENT) { hasChanged = true; fireEvent(ureq, event); @@ -324,10 +348,9 @@ public class StudentCoursesController extends BasicController implements Activat ContextEntry ce = entries.get(0); OLATResourceable ores = ce.getOLATResourceable(); if("RepositoryEntry".equals(ores.getResourceableTypeName())) { - Long identityKey = ores.getResourceableId(); - for(int i=tableCtr.getRowCount(); i-->0; ) { - EfficiencyStatementEntry entry = (EfficiencyStatementEntry)tableCtr.getTableDataModel().getObject(i); - if(identityKey.equals(entry.getCourse().getKey())) { + Long entryKey = ores.getResourceableId(); + for(EfficiencyStatementEntry entry:model.getObjects()) { + if(entryKey.equals(entry.getCourse().getKey())) { selectDetails(ureq, entry); statementCtrl.activate(ureq, entries.subList(1, entries.size()), ce.getTransientState()); break; @@ -361,7 +384,7 @@ public class StudentCoursesController extends BasicController implements Activat } private void removeDetails(UserRequest ureq) { - mainVC.remove(statementCtrl.getInitialComponent()); + flc.getFormItemComponent().remove(statementCtrl.getInitialComponent()); removeAsListenerAndDispose(statementCtrl); statementCtrl = null; setDetailsToolbarVisible(false); @@ -378,21 +401,21 @@ public class StudentCoursesController extends BasicController implements Activat private void nextEntry(UserRequest ureq) { EfficiencyStatementEntry currentEntry = statementCtrl.getEntry(); - int nextIndex = tableCtr.getIndexOfSortedObject(currentEntry) + 1; - if(nextIndex < 0 || nextIndex >= tableCtr.getRowCount()) { + int nextIndex = model.getObjects().indexOf(currentEntry) + 1; + if(nextIndex < 0 || nextIndex >= model.getRowCount()) { nextIndex = 0; } - EfficiencyStatementEntry nextEntry = (EfficiencyStatementEntry)tableCtr.getSortedObjectAt(nextIndex); + EfficiencyStatementEntry nextEntry = model.getObject(nextIndex); selectDetails(ureq, nextEntry); } private void previousEntry(UserRequest ureq) { EfficiencyStatementEntry currentEntry = statementCtrl.getEntry(); - int previousIndex = tableCtr.getIndexOfSortedObject(currentEntry) - 1; - if(previousIndex < 0 || previousIndex >= tableCtr.getRowCount()) { - previousIndex = tableCtr.getRowCount() - 1; + int previousIndex = model.getObjects().indexOf(currentEntry) - 1; + if(previousIndex < 0 || previousIndex >= model.getRowCount()) { + previousIndex = model.getRowCount() - 1; } - EfficiencyStatementEntry previousEntry = (EfficiencyStatementEntry)tableCtr.getSortedObjectAt(previousIndex); + EfficiencyStatementEntry previousEntry = model.getObject(previousIndex); selectDetails(ureq, previousEntry); } @@ -400,6 +423,7 @@ public class StudentCoursesController extends BasicController implements Activat boolean selectAssessmentTool = false; if(statementCtrl != null) { selectAssessmentTool = statementCtrl.isAssessmentToolSelected(); + flc.getFormItemComponent().remove(statementCtrl.getInitialComponent()); removeAsListenerAndDispose(statementCtrl); } @@ -409,7 +433,7 @@ public class StudentCoursesController extends BasicController implements Activat listenTo(statementCtrl); detailsCmp.setText(entry.getCourse().getDisplayname()); - mainVC.put("efficiencyDetails", statementCtrl.getInitialComponent()); + flc.getFormItemComponent().put("efficiencyDetails", statementCtrl.getInitialComponent()); setDetailsToolbarVisible(true); } @@ -418,7 +442,7 @@ public class StudentCoursesController extends BasicController implements Activat ces.add(BusinessControlFactory.getInstance().createContextEntry(student)); BusinessControl bc = BusinessControlFactory.getInstance().createFromContextEntries(ces); - WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl()); + WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(bc, getWindowControl()); NewControllerFactory.getInstance().launch(ureq, bwControl); } } diff --git a/src/main/java/org/olat/modules/coach/ui/StudentListController.java b/src/main/java/org/olat/modules/coach/ui/StudentListController.java index 144a6d7515d..f2039c6885d 100644 --- a/src/main/java/org/olat/modules/coach/ui/StudentListController.java +++ b/src/main/java/org/olat/modules/coach/ui/StudentListController.java @@ -32,6 +32,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormEvent; 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.FlexiTableDataModelFactory; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableSearchEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; @@ -42,7 +43,6 @@ 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.resource.OresHelper; -import org.olat.course.assessment.ui.tool.AssessmentToolConstants; import org.olat.modules.coach.CoachingService; import org.olat.modules.coach.model.StudentStatEntry; import org.olat.modules.coach.ui.StudentsTableDataModel.Columns; @@ -99,11 +99,11 @@ public class StudentListController extends FormBasicController implements Activa columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.name, "select")); } - int colIndex = AssessmentToolConstants.USER_PROPS_OFFSET; + 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", false, null)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", true, null)); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.countCourse)); @@ -115,6 +115,8 @@ public class StudentListController extends FormBasicController implements Activa tableEl.setExportEnabled(true); tableEl.setEmtpyTableMessageKey("error.no.found"); tableEl.setAndLoadPersistedPreferences(ureq, "fStudentListController"); + tableEl.setSearchEnabled(new StudentListProvider(model, userManager), ureq.getUserSession()); + } @Override @@ -137,6 +139,12 @@ public class StudentListController extends FormBasicController implements Activa 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); diff --git a/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java b/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java new file mode 100644 index 00000000000..5708150b3e9 --- /dev/null +++ b/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java @@ -0,0 +1,79 @@ +/** + * <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; + +import java.util.Iterator; + +import org.olat.core.gui.control.generic.ajax.autocompletion.ListProvider; +import org.olat.core.gui.control.generic.ajax.autocompletion.ListReceiver; +import org.olat.core.gui.util.CSSHelper; +import org.olat.modules.coach.model.StudentStatEntry; +import org.olat.user.UserManager; + +/** + * + * Initial date: 02.06.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class StudentListProvider implements ListProvider { + + private final StudentsTableDataModel model; + private final UserManager userManager; + + public StudentListProvider(StudentsTableDataModel model, UserManager userManager) { + this.model = model; + this.userManager = userManager; + } + + @Override + public void getResult(String searchValue, ListReceiver receiver) { + int maxEntries = 10; + boolean hasMore = false; + for (Iterator<StudentStatEntry> it_res = model.getObjects().iterator(); (hasMore=it_res.hasNext()) && maxEntries > 0;) { + StudentStatEntry entry = it_res.next(); + if(contains(searchValue, entry)) { + maxEntries--; + String key = entry.getIdentityKey().toString(); + String displayKey = entry.getIdentityName(); + String displayText = userManager.getUserDisplayName(entry.getIdentityKey()); + receiver.addEntry(key, displayKey, displayText, CSSHelper.CSS_CLASS_USER); + } + } + + if(hasMore){ + receiver.addEntry(".....","....."); + } + } + + public static boolean contains(String searchValue, StudentStatEntry entry) { + if(entry.getIdentityName().contains(searchValue)) { + return true; + } + String[] userProperties = entry.getIdentityProps(); + for(int i=userProperties.length; i-->0; ) { + String userProp = userProperties[i]; + if(userProp != null && userProp.contains(searchValue)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/org/olat/modules/coach/ui/StudentsTableDataModel.java b/src/main/java/org/olat/modules/coach/ui/StudentsTableDataModel.java index bc17ffcaea7..79e0d17d801 100644 --- a/src/main/java/org/olat/modules/coach/ui/StudentsTableDataModel.java +++ b/src/main/java/org/olat/modules/coach/ui/StudentsTableDataModel.java @@ -19,11 +19,18 @@ */ package org.olat.modules.coach.ui; +import java.util.List; +import java.util.stream.Collectors; + import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnDef; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; +import org.olat.core.logging.OLog; +import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; import org.olat.modules.coach.model.StudentStatEntry; import org.olat.modules.coach.ui.LightedValue.Light; @@ -36,16 +43,44 @@ import org.olat.modules.coach.ui.LightedValue.Light; * * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com */ -public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentStatEntry> implements SortableFlexiTableDataModel<StudentStatEntry> { +public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentStatEntry> + implements SortableFlexiTableDataModel<StudentStatEntry> { + + private static final OLog log = Tracing.createLoggerFor(StudentsTableDataModel.class); + private List<StudentStatEntry> backupList; public StudentsTableDataModel(FlexiTableColumnModel columnModel) { super(columnModel); } + + public void search(final String searchString) { + if(StringHelper.containsNonWhitespace(searchString)) { + try { + List<StudentStatEntry> filteredList; + if(StringHelper.isLong(searchString)) { + Long identityKey = new Long(searchString); + filteredList = backupList.stream() + .filter(entry -> entry.getIdentityKey().equals(identityKey)) + .collect(Collectors.toList()); + } else { + filteredList = backupList.stream() + .filter(entry -> StudentListProvider.contains(searchString, entry)) + .collect(Collectors.toList()); + } + super.setObjects(filteredList); + } catch (Exception e) { + log.error("", e); + super.setObjects(backupList); + } + } else { + super.setObjects(backupList); + } + } @Override - public void sort(SortKey sortKey) { - // + public void sort(SortKey orderBy) { + super.setObjects(new SortableFlexiTableModelDelegate<>(orderBy, this, null).sort()); } @Override @@ -104,13 +139,19 @@ public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentSt int propPos = col - UserListController.USER_PROPS_OFFSET; return student.getIdentityProp(propPos); } + + @Override + public void setObjects(List<StudentStatEntry> objects) { + this.backupList = objects; + super.setObjects(objects); + } @Override public StudentsTableDataModel createCopyWithEmptyList() { return new StudentsTableDataModel(getTableColumnModel()); } - public static enum Columns implements FlexiColumnDef { + public static enum Columns implements FlexiSortableColumnDef { name("student.name"), countCourse("table.header.countCourses"), initialLaunch("table.header.login"), @@ -127,7 +168,17 @@ public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentSt public String i18nHeaderKey() { return i18nKey; } - + + @Override + public boolean sortable() { + return true; + } + + @Override + public String sortKey() { + return name(); + } + public static Columns getValueAt(int ordinal) { if(ordinal >= 0 && ordinal < values().length) { return values()[ordinal]; diff --git a/src/main/java/org/olat/modules/coach/ui/UserListController.java b/src/main/java/org/olat/modules/coach/ui/UserListController.java index 5ef4bc4b467..1d4096ac68d 100644 --- a/src/main/java/org/olat/modules/coach/ui/UserListController.java +++ b/src/main/java/org/olat/modules/coach/ui/UserListController.java @@ -44,7 +44,6 @@ 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.resource.OresHelper; -import org.olat.course.assessment.ui.tool.AssessmentToolConstants; import org.olat.modules.coach.CoachingService; import org.olat.modules.coach.model.SearchCoachedIdentityParams; import org.olat.modules.coach.model.StudentStatEntry; @@ -100,11 +99,11 @@ public class UserListController extends FormBasicController implements Activatea columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.name, "select")); } - int colIndex = AssessmentToolConstants.USER_PROPS_OFFSET; + 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", false, null)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex++, "select", true, null)); } columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.countCourse)); diff --git a/src/main/java/org/olat/modules/coach/ui/_content/student_course_list.html b/src/main/java/org/olat/modules/coach/ui/_content/student_course_list.html index c281965cc1f..df978d038f8 100644 --- a/src/main/java/org/olat/modules/coach/ui/_content/student_course_list.html +++ b/src/main/java/org/olat/modules/coach/ui/_content/student_course_list.html @@ -2,6 +2,14 @@ $r.render("toolbar") #if($r.available("efficiencyDetails")) $r.render("efficiencyDetails") #else - $r.render("studentDetails") - $r.render("studentsTable") + <div class="o_eff_statement_details"> + <h3><i class="o_icon o_icon_user"> </i> $studentName</h3> + #if($r.available("home")) + $r.render("home") + #end + #if($r.available("contact")) + $r.render("contact") + #end + </div> + $r.render("table") #end \ No newline at end of file diff --git a/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java b/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java index 466b5a170eb..6eaad9c4c10 100644 --- a/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java +++ b/src/main/java/org/olat/modules/reminder/manager/ReminderDAO.java @@ -193,7 +193,7 @@ public class ReminderDAO { } public List<SentReminder> getSendReminders(Reminder reminder) { - String q = "select sent from sentreminder sent inner join fetch sent.identity ident where sent.reminder.key=:reminderKey"; + String q = "select sent from sentreminder sent inner join fetch sent.identity ident inner join fetch ident.user as identUser where sent.reminder.key=:reminderKey"; return dbInstance.getCurrentEntityManager() .createQuery(q, SentReminder.class) .setParameter("reminderKey", reminder.getKey()) @@ -201,7 +201,7 @@ public class ReminderDAO { } public List<SentReminder> getSendReminders(RepositoryEntryRef entry) { - String q = "select sent from sentreminder sent inner join fetch sent.reminder rem inner join fetch sent.identity ident where rem.entry.key=:entryKey"; + String q = "select sent from sentreminder sent inner join fetch sent.reminder rem inner join fetch sent.identity ident inner join fetch ident.user as identUser where rem.entry.key=:entryKey"; return dbInstance.getCurrentEntityManager() .createQuery(q, SentReminder.class) .setParameter("entryKey", entry.getKey()) diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java index 5da215aa10b..9074a4a14f0 100644 --- a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java +++ b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java @@ -269,11 +269,13 @@ public class RepositoryEntryRelationDAO { public List<Identity> getIdentitiesWithRole(String role) { StringBuilder sb = new StringBuilder(); - sb.append("select distinct members.identity from ").append(RepositoryEntry.class.getName()).append(" as v") + sb.append("select distinct ident from ").append(RepositoryEntry.class.getName()).append(" as v") .append(" inner join v.groups as relGroup") .append(" inner join relGroup.group as baseGroup") - .append(" inner join baseGroup.members as members") - .append(" where members.role=:role"); + .append(" inner join baseGroup.members as memberships") + .append(" inner join memberships.identity as ident") + .append(" inner join fetch ident.user as identUser") + .append(" where memberships.role=:role"); return dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), Identity.class) @@ -382,13 +384,15 @@ public class RepositoryEntryRelationDAO { } StringBuilder sb = new StringBuilder(); - sb.append("select members.identity from ").append(RepositoryEntry.class.getName()).append(" as v") + sb.append("select ident from ").append(RepositoryEntry.class.getName()).append(" as v") .append(" inner join v.groups as relGroup").append(def) .append(" inner join relGroup.group as baseGroup") - .append(" inner join baseGroup.members as members") + .append(" inner join baseGroup.members as memberships") + .append(" inner join memberships.identity as ident") + .append(" inner join fetch ident.user as identUser") .append(" where v.key=:repoKey"); if(roleList.size() > 0) { - sb.append(" and members.role in (:roles)"); + sb.append(" and memberships.role in (:roles)"); } TypedQuery<Identity> query = dbInstance.getCurrentEntityManager() diff --git a/src/main/java/org/olat/user/UserImpl.java b/src/main/java/org/olat/user/UserImpl.java index b87a5f58e0c..00902f9f058 100644 --- a/src/main/java/org/olat/user/UserImpl.java +++ b/src/main/java/org/olat/user/UserImpl.java @@ -317,6 +317,11 @@ public class UserImpl implements Persistable, User { public Identity getIdentity() { return identity; } + + public void setIdentity(Identity identity) { + this.identity = identity; + } + public String getFirstName() { return firstName; diff --git a/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java b/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java index 28199332fbb..b602c06ebab 100644 --- a/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java +++ b/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java @@ -825,6 +825,18 @@ public class BaseSecurityManagerTest extends OlatTestCase { dbInstance.commitAndCloseSession(); } + @Test + public void findAuthenticationName() { + Identity ident = JunitTestHelper.createAndPersistIdentityAsRndUser("auth-d-"); + dbInstance.commitAndCloseSession(); + + Authentication auth = securityManager.findAuthentication(ident, "OLAT"); + Assert.assertNotNull(auth); + + String authName = securityManager.findAuthenticationName(ident, "OLAT"); + Assert.assertNotNull(authName); + } + @Test public void updateToSaltedAuthentication() { Identity ident = JunitTestHelper.createAndPersistIdentityAsUser("auth-c-" + UUID.randomUUID().toString()); -- GitLab