From c03e2cb1f84b72424cb029edbf7a65b8d133db04 Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Mon, 19 Jun 2017 14:22:03 +0200
Subject: [PATCH] OO-2636: add absence informations in the list of course of a
 specific user

---
 .../model/IdentityRepositoryEntryKey.java     | 69 +++++++++++++++++++
 ...fficiencyStatementEntryTableDataModel.java | 60 +++++++++++++---
 .../coach/ui/StudentCoursesController.java    | 27 +++++++-
 .../coach/ui/_i18n/LocalStrings_de.properties |  4 ++
 .../coach/ui/_i18n/LocalStrings_en.properties |  4 ++
 5 files changed, 152 insertions(+), 12 deletions(-)
 create mode 100644 src/main/java/org/olat/modules/coach/model/IdentityRepositoryEntryKey.java

diff --git a/src/main/java/org/olat/modules/coach/model/IdentityRepositoryEntryKey.java b/src/main/java/org/olat/modules/coach/model/IdentityRepositoryEntryKey.java
new file mode 100644
index 00000000000..2504fcdd934
--- /dev/null
+++ b/src/main/java/org/olat/modules/coach/model/IdentityRepositoryEntryKey.java
@@ -0,0 +1,69 @@
+/**
+ * <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.model;
+
+/**
+ * 
+ * Initial date: 19 juin 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class IdentityRepositoryEntryKey {
+	
+	private final Long identityKey;
+	private final Long repositoryEntryKey;
+	
+	public IdentityRepositoryEntryKey(Long identityKey, Long repositoryEntryKey) {
+		this.identityKey = identityKey;
+		this.repositoryEntryKey = repositoryEntryKey;
+	}
+	
+	public IdentityRepositoryEntryKey(EfficiencyStatementEntry entry) {
+		identityKey = entry.getIdentityKey();
+		repositoryEntryKey = entry.getCourse().getKey();
+	}
+	
+	public Long getIdentityKey() {
+		return identityKey;
+	}
+	
+	public Long getRepositoryEntryKey() {
+		return repositoryEntryKey;
+	}
+	
+	@Override
+	public int hashCode() {
+		return (identityKey == null ? 98268 : identityKey.hashCode())
+				+ (repositoryEntryKey == null ? -2634785 : repositoryEntryKey.hashCode());
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if(this == obj) {
+			return true;
+		}
+		if(obj instanceof IdentityRepositoryEntryKey) {
+			IdentityRepositoryEntryKey key = (IdentityRepositoryEntryKey)obj;
+			return identityKey != null && identityKey.equals(key.getIdentityKey())
+					&& repositoryEntryKey != null && repositoryEntryKey.equals(key.getRepositoryEntryKey());
+		}
+		return false;
+	}
+}
\ No newline at end of file
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 0f3575c069a..d1ca2387fbd 100644
--- a/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java
+++ b/src/main/java/org/olat/modules/coach/ui/EfficiencyStatementEntryTableDataModel.java
@@ -31,7 +31,9 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl
 import org.olat.course.assessment.UserEfficiencyStatement;
 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.lecture.model.LectureBlockStatistics;
 import org.olat.repository.RepositoryEntry;
 
 /**
@@ -46,6 +48,7 @@ import org.olat.repository.RepositoryEntry;
 public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDataModel<EfficiencyStatementEntry> implements SortableFlexiTableDataModel<EfficiencyStatementEntry> {
 	
 	private ConcurrentMap<IdentityResourceKey, CertificateLight> certificateMap;
+	private ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesStatisticsMap;
 	
 	public EfficiencyStatementEntryTableDataModel(FlexiTableColumnModel columnModel) {
 		super(columnModel);
@@ -91,19 +94,11 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat
 					return s == null ? null : s.getPassed();
 				}
 				case certificate: {
-					CertificateLight certificate = null;
-					if(certificateMap != null) {
-						IdentityResourceKey key = new IdentityResourceKey(entry.getIdentityKey(), entry.getCourse().getOlatResource().getKey());
-						certificate = certificateMap.get(key);
-					}
+					CertificateLight certificate = getCertificate(entry);
 					return certificate;
 				}
 				case recertification: {
-					CertificateLight certificate = null;
-					if(certificateMap != null) {
-						IdentityResourceKey key = new IdentityResourceKey(entry.getIdentityKey(), entry.getCourse().getOlatResource().getKey());
-						certificate = certificateMap.get(key);
-					}
+					CertificateLight certificate = getCertificate(entry);
 					return certificate == null ? null : certificate.getNextRecertificationDate();
 				}
 				case progress: {
@@ -124,16 +119,55 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat
 					UserEfficiencyStatement s = entry.getUserEfficencyStatement();
 					return s == null ? null : s.getLastModified();
 				}
+				case plannedLectures: {
+					LectureBlockStatistics statistics = getLectureBlockStatistics(entry);
+					return statistics == null ? null : statistics.getTotalPlannedLectures();
+				}
+				case attendedLectures: {
+					LectureBlockStatistics statistics = getLectureBlockStatistics(entry);
+					return statistics == null ? null : statistics.getTotalAttendedLectures();
+				}
+				case absentLectures: {
+					LectureBlockStatistics statistics = getLectureBlockStatistics(entry);
+					return statistics == null ? null : statistics.getTotalAbsentLectures();
+				}
+				case authorizedAbsenceLectures: {
+					LectureBlockStatistics statistics = getLectureBlockStatistics(entry);
+					return statistics == null ? null : statistics.getTotalAuthorizedAbsentLectures();
+				}
 			}
 		}
 		
 		int propPos = col - UserListController.USER_PROPS_OFFSET;
 		return entry.getIdentityProp(propPos);
 	}
+	
+	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<EfficiencyStatementEntry> objects, ConcurrentMap<IdentityResourceKey, CertificateLight> certificates) {
+		setObjects(objects, certificates, null);
+	}
+	
+	public void setObjects(List<EfficiencyStatementEntry> objects,
+			ConcurrentMap<IdentityResourceKey, CertificateLight> certificates,
+			ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesStatisticsMap) {
 		setObjects(objects);
 		this.certificateMap = certificates;
+		this.lecturesStatisticsMap = lecturesStatisticsMap;
 	}
 
 	@Override
@@ -149,7 +183,11 @@ public class EfficiencyStatementEntryTableDataModel extends DefaultFlexiTableDat
 		certificate("table.header.certificate"),
 		recertification("table.header.recertification"),
 		progress("table.header.progress"),
-		lastModification("table.header.lastScoreDate");
+		lastModification("table.header.lastScoreDate"),
+		plannedLectures("table.header.planned.lectures"),
+		attendedLectures("table.header.attended.lectures"),
+		absentLectures("table.header.absent.lectures"),
+		authorizedAbsenceLectures("table.header.authorized.absence");
 		
 		private final String i18nKey;
 		
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 4b177fdb8a1..1803bf62ab2 100644
--- a/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
+++ b/src/main/java/org/olat/modules/coach/ui/StudentCoursesController.java
@@ -70,10 +70,14 @@ import org.olat.modules.assessment.ui.ScoreCellRenderer;
 import org.olat.modules.co.ContactFormController;
 import org.olat.modules.coach.CoachingService;
 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.model.StudentStatEntry;
 import org.olat.modules.coach.ui.EfficiencyStatementEntryTableDataModel.Columns;
 import org.olat.modules.coach.ui.UserDetailsController.Segment;
+import org.olat.modules.lecture.LectureModule;
+import org.olat.modules.lecture.LectureService;
+import org.olat.modules.lecture.model.LectureBlockStatistics;
 import org.olat.repository.RepositoryEntry;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
@@ -116,6 +120,10 @@ public class StudentCoursesController extends FormBasicController implements Act
 	@Autowired
 	private UserManager userManager;
 	@Autowired
+	private LectureModule lectureModule;
+	@Autowired
+	private LectureService lectureService;
+	@Autowired
 	private CoachingService coachingService;
 	@Autowired
 	private BaseSecurityModule securityModule;
@@ -200,6 +208,14 @@ public class StudentCoursesController extends FormBasicController implements Act
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.certificate, new DownloadCertificateCellRenderer()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.recertification, new DateFlexiCellRenderer(getLocale())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.progress, new ProgressRenderer(true, getTranslator())));
+		if(lectureModule.isEnabled()) {
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.plannedLectures));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.attendedLectures));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.absentLectures));
+			if(lectureModule.isAuthorizedAbsenceEnabled()) {
+				columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.authorizedAbsenceLectures));
+			}
+		}
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Columns.lastModification));
 		
 		model = new EfficiencyStatementEntryTableDataModel(columnsModel);
@@ -247,7 +263,16 @@ public class StudentCoursesController extends FormBasicController implements Act
 			certificateMap.put(key, certificate);
 		}
 
-		model.setObjects(statements, certificateMap);
+		ConcurrentMap<IdentityRepositoryEntryKey, LectureBlockStatistics> lecturesMap = new ConcurrentHashMap<>();
+		if(lectureModule.isEnabled()) {
+			List<LectureBlockStatistics> lectureStats = lectureService.getParticipantLecturesStatistics(student);
+			for(LectureBlockStatistics lectureStat:lectureStats) {
+				IdentityRepositoryEntryKey key = new IdentityRepositoryEntryKey(student.getKey(), lectureStat.getRepoKey());
+				lecturesMap.put(key, lectureStat);
+			}
+		}
+
+		model.setObjects(statements, certificateMap, lecturesMap);
 		tableEl.reset();
 		tableEl.reloadData();
 		return statements;
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 7bbe6356bec..87310e56f26 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
@@ -60,4 +60,8 @@ table.header.progress=Fortschritt
 table.header.recertification=Rezertifizierung
 table.header.score=$org.olat.course.assessment\:table.header.score
 table.header.show=$org.olat.course.assessment\:table.header.show
+table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned.lectures
+table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures
+table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures
+table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence
 tooltip.of={0} von {1}
\ No newline at end of file
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 992686f67f5..4d6a0bd8bca 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
@@ -60,4 +60,8 @@ table.header.progress=Progress
 table.header.recertification=Recertification
 table.header.score=$org.olat.course.assessment\:table.header.score
 table.header.show=$org.olat.course.assessment\:table.header.show
+table.header.planned.lectures=$org.olat.modules.lecture.ui\:table.header.planned.lectures
+table.header.attended.lectures=$org.olat.modules.lecture.ui\:table.header.attended.lectures
+table.header.absent.lectures=$org.olat.modules.lecture.ui\:table.header.absent.lectures
+table.header.authorized.absence=$org.olat.modules.lecture.ui\:table.header.authorized.absence
 tooltip.of={0} of {1}
-- 
GitLab