From fe787123f1cff46f9e3af385ce72cf84d072da10 Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Thu, 25 Apr 2019 11:09:47 +0200
Subject: [PATCH] OO-4032: add filter for active curriculum in "My courses"

---
 .../modules/curriculum/CurriculumService.java |  8 +++
 .../curriculum/manager/CurriculumDAO.java     | 18 +++++++
 .../manager/CurriculumServiceImpl.java        |  8 +++
 .../ui/CurriculumListController.java          | 25 +++++++--
 .../ui/CurriculumManagerDataModel.java        | 39 +++++++++++++-
 .../modules/curriculum/ui/CurriculumRow.java  | 15 +++++-
 .../ui/_i18n/LocalStrings_de.properties       |  2 +
 .../ui/_i18n/LocalStrings_en.properties       |  2 +
 .../CurriculumActiveCellRenderer.java         | 54 +++++++++++++++++++
 9 files changed, 165 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/org/olat/modules/curriculum/ui/component/CurriculumActiveCellRenderer.java

diff --git a/src/main/java/org/olat/modules/curriculum/CurriculumService.java b/src/main/java/org/olat/modules/curriculum/CurriculumService.java
index f9b4ce0e901..6237bbd9069 100644
--- a/src/main/java/org/olat/modules/curriculum/CurriculumService.java
+++ b/src/main/java/org/olat/modules/curriculum/CurriculumService.java
@@ -81,6 +81,14 @@ public interface CurriculumService {
 	 */
 	public List<Curriculum> getMyCurriculums(Identity identity);
 	
+	/**
+	 * The list of curriculums the identity participates.
+	 * 
+	 * @param identity The identity
+	 * @return A list of curriculums
+	 */
+	public List<CurriculumRef> getMyActiveCurriculumRefs(Identity identity);
+	
 	/**
 	 * Get the list of members of the specified curriculum with their roles.
 	 * 
diff --git a/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java b/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java
index 4b925a44234..735988d98a1 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumDAO.java
@@ -45,6 +45,7 @@ import org.olat.modules.curriculum.CurriculumRoles;
 import org.olat.modules.curriculum.model.CurriculumImpl;
 import org.olat.modules.curriculum.model.CurriculumInfos;
 import org.olat.modules.curriculum.model.CurriculumSearchParameters;
+import org.olat.repository.RepositoryEntryStatusEnum;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -122,6 +123,23 @@ public class CurriculumDAO {
 				.getResultList();
 	}
 	
+	public List<Long> getMyActiveCurriculumKeys(IdentityRef identity) {
+		QueryBuilder sb = new QueryBuilder(256);
+		sb.append("select curElement.curriculum.key from curriculumelement curElement")
+		  .append(" inner join curElement.group as bGroup")
+		  .append(" inner join bGroup.members membership")
+		  .append(" where membership.identity.key=:memberKey and membership.role ").in(CurriculumRoles.participant, CurriculumRoles.coach, CurriculumRoles.owner)
+		  .append(" and curElement.status='active' and exists (select v from repoentrytogroup as rel")
+		  .append("  inner join rel.entry as v")
+		  .append("  where curElement.group.key=rel.group.key and v.status ").in(RepositoryEntryStatusEnum.published)
+		  .append(" )");
+	
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(sb.toString(), Long.class)
+				.setParameter("memberKey", identity.getKey())
+				.getResultList();
+	}
+	
 	public List<Curriculum> search(CurriculumSearchParameters params) {
 		QueryBuilder sb = new QueryBuilder(256);
 		sb.append("select cur from curriculum cur")
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 a509c633d12..5159c8ea214 100644
--- a/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
+++ b/src/main/java/org/olat/modules/curriculum/manager/CurriculumServiceImpl.java
@@ -28,6 +28,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import org.olat.basesecurity.GroupMembershipInheritance;
 import org.olat.basesecurity.GroupRoles;
@@ -68,6 +69,7 @@ import org.olat.modules.curriculum.model.CurriculumElementSearchParams;
 import org.olat.modules.curriculum.model.CurriculumElementWebDAVInfos;
 import org.olat.modules.curriculum.model.CurriculumInfos;
 import org.olat.modules.curriculum.model.CurriculumMember;
+import org.olat.modules.curriculum.model.CurriculumRefImpl;
 import org.olat.modules.curriculum.model.CurriculumSearchParameters;
 import org.olat.modules.curriculum.model.SearchMemberParameters;
 import org.olat.modules.taxonomy.TaxonomyLevel;
@@ -256,6 +258,12 @@ public class CurriculumServiceImpl implements CurriculumService, OrganisationDat
 		return curriculumDao.getMyCurriculums(identity);
 	}
 
+	@Override
+	public List<CurriculumRef> getMyActiveCurriculumRefs(Identity identity) {
+		List<Long> curriculumKeys = curriculumDao.getMyActiveCurriculumKeys(identity);
+		return curriculumKeys.stream().map(CurriculumRefImpl::new).collect(Collectors.toList());
+	}
+
 	@Override
 	public CurriculumElement createCurriculumElement(String identifier, String displayName,  CurriculumElementStatus status,
 			Date beginDate, Date endDate, CurriculumElementRef parentRef, CurriculumElementType elementType,
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java
index 833dc2250e4..3acaeadb333 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumListController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.modules.curriculum.ui;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -26,6 +27,7 @@ import org.olat.core.gui.UserRequest;
 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.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
@@ -41,8 +43,10 @@ import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.modules.curriculum.Curriculum;
+import org.olat.modules.curriculum.CurriculumRef;
 import org.olat.modules.curriculum.CurriculumService;
 import org.olat.modules.curriculum.ui.CurriculumManagerDataModel.CurriculumCols;
+import org.olat.modules.curriculum.ui.component.CurriculumActiveCellRenderer;
 import org.springframework.beans.factory.annotation.Autowired;
 
 /**
@@ -81,6 +85,7 @@ public class CurriculumListController extends FormBasicController implements Act
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, CurriculumCols.key));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CurriculumCols.active, new CurriculumActiveCellRenderer(getTranslator())));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CurriculumCols.displayName, "select"));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(CurriculumCols.identifier, "select"));
 		DefaultFlexiColumnModel toolsCol = new DefaultFlexiColumnModel(CurriculumCols.tools);
@@ -92,15 +97,29 @@ public class CurriculumListController extends FormBasicController implements Act
 		tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
 		tableEl.setCustomizeColumns(true);
 		tableEl.setEmtpyTableMessageKey("table.curriculum.empty");
-		tableEl.setAndLoadPersistedPreferences(ureq, "cur-curriculum-list");
+		tableEl.setFilters("activity", getFilters(), false);
+		tableEl.setSelectedFilterKey("active");
+		tableEl.setAndLoadPersistedPreferences(ureq, "cur-curriculum-list-v2");
+	}
+	
+	private List<FlexiTableFilter> getFilters() {
+		List<FlexiTableFilter> filters = new ArrayList<>(5);
+		filters.add(new FlexiTableFilter(translate("filter.active"), "active"));
+		filters.add(new FlexiTableFilter(translate("filter.inactive"), "inactive"));
+		filters.add(FlexiTableFilter.SPACER);
+		filters.add(new FlexiTableFilter(translate("show.all"), "all", true));
+		return filters;
 	}
 	
 	private void loadModel() {
 		List<Curriculum> curriculums = curriculumService.getMyCurriculums(getIdentity());
+		List<CurriculumRef> activeRefs = curriculumService.getMyActiveCurriculumRefs(getIdentity());
+		List<Long> activeKeys = activeRefs.stream().map(CurriculumRef::getKey).collect(Collectors.toList());
 		List<CurriculumRow> rows = curriculums.stream()
-				.map(CurriculumRow::new).collect(Collectors.toList());
+				.map(c -> new CurriculumRow(c, activeKeys.contains(c.getKey())))
+				.collect(Collectors.toList());
 		tableModel.setObjects(rows);
-		tableEl.reset(false, false, true);
+		tableEl.reset(true, true, true);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java
index c0add519624..4c73aab75dd 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumManagerDataModel.java
@@ -19,11 +19,15 @@
  */
 package org.olat.modules.curriculum.ui;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.stream.Collectors;
 
 import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FilterableFlexiTableModel;
 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;
@@ -35,9 +39,10 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl
  *
  */
 public class CurriculumManagerDataModel extends DefaultFlexiTableDataModel<CurriculumRow>
-implements SortableFlexiTableDataModel<CurriculumRow> {
+implements SortableFlexiTableDataModel<CurriculumRow>, FilterableFlexiTableModel {
 	
 	private final Locale locale;
+	private List<CurriculumRow> backups;
 	
 	public CurriculumManagerDataModel(FlexiTableColumnModel columnsModel, Locale locale) {
 		super(columnsModel);
@@ -51,7 +56,29 @@ implements SortableFlexiTableDataModel<CurriculumRow> {
 			super.setObjects(rows);
 		}
 	}
-	
+
+	@Override
+	public void filter(String searchString, List<FlexiTableFilter> filters) {
+		FlexiTableFilter filter = filters == null || filters.isEmpty() || filters.get(0) == null ? null : filters.get(0);
+		if(filter != null && !filter.isShowAll()) {
+			List<CurriculumRow> filteredRows;
+			if("active".equals(filter.getFilter())) {
+				filteredRows = backups.stream()
+						.filter(CurriculumRow::isActive)
+						.collect(Collectors.toList());
+			} else if("inactive".equals(filter.getFilter())) {
+				filteredRows = backups.stream()
+						.filter(node -> !node.isActive())
+						.collect(Collectors.toList());
+			} else {
+				filteredRows = new ArrayList<>(backups);
+			}
+			super.setObjects(filteredRows);
+		} else {
+			super.setObjects(backups);
+		}
+	}
+
 	@Override
 	public Object getValueAt(int row, int col) {
 		CurriculumRow curriculum = getObject(row);
@@ -62,6 +89,7 @@ implements SortableFlexiTableDataModel<CurriculumRow> {
 	public Object getValueAt(CurriculumRow row, int col) {
 		switch(CurriculumCols.values()[col]) {
 			case key: return row.getKey();
+			case active: return row.isActive();
 			case displayName: return row.getDisplayName();
 			case identifier: return row.getIdentifier();
 			case externalId: return row.getExternalId();
@@ -71,6 +99,12 @@ implements SortableFlexiTableDataModel<CurriculumRow> {
 			default: return "ERROR";
 		}
 	}
+	
+	@Override
+	public void setObjects(List<CurriculumRow> objects) {
+		super.setObjects(objects);
+		backups = objects;
+	}
 
 	@Override
 	public CurriculumManagerDataModel createCopyWithEmptyList() {
@@ -79,6 +113,7 @@ implements SortableFlexiTableDataModel<CurriculumRow> {
 	
 	public enum CurriculumCols implements FlexiSortableColumnDef {
 		key("table.header.key"),
+		active("table.header.active"),
 		displayName("table.header.displayName"),
 		identifier("table.header.identifier"),
 		externalId("table.header.external.id"),
diff --git a/src/main/java/org/olat/modules/curriculum/ui/CurriculumRow.java b/src/main/java/org/olat/modules/curriculum/ui/CurriculumRow.java
index 6936fd77a62..7ed28e85b59 100644
--- a/src/main/java/org/olat/modules/curriculum/ui/CurriculumRow.java
+++ b/src/main/java/org/olat/modules/curriculum/ui/CurriculumRow.java
@@ -35,11 +35,13 @@ public class CurriculumRow implements CurriculumRef {
 	private final Curriculum curriculum;
 	private final long numOfElements;
 	private final boolean canManage;
+	private final boolean active;
 	
 	private final FormLink toolsLink;
 	
-	public CurriculumRow(Curriculum curriculum) {
+	public CurriculumRow(Curriculum curriculum, boolean active) {
 		this.curriculum = curriculum;
+		this.active = active;
 		numOfElements = -1l;
 		toolsLink = null;
 		canManage = false;
@@ -50,6 +52,7 @@ public class CurriculumRow implements CurriculumRef {
 		numOfElements = infos.getNumOfElements();
 		toolsLink = null;
 		canManage = false;
+		active = false;
 	}
 	
 	public CurriculumRow(CurriculumInfos infos, FormLink toolsLink, boolean canManage) {
@@ -57,6 +60,7 @@ public class CurriculumRow implements CurriculumRef {
 		numOfElements = infos.getNumOfElements();
 		this.toolsLink = toolsLink;
 		this.canManage = canManage;
+		active = false;
 	}
 	
 	@Override
@@ -87,6 +91,15 @@ public class CurriculumRow implements CurriculumRef {
 	public boolean canManage() {
 		return canManage;
 	}
+	
+	/**
+	 * The value must be explicitly loaded.
+	 * 
+	 * @return True if active
+	 */
+	public boolean isActive() {
+		return active;
+	}
 
 	@Override
 	public int hashCode() {
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 f75e85cc558..27bd2a1f9f8 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
@@ -47,6 +47,7 @@ curriculum.element.types=Typen
 curriculum.external.id=Externe ID
 curriculum.identifier=Bezeichnung
 curriculum.in.my.courses.enabled=Curriculum in "Meine Kurse"
+curriculum.inactive.explain=Sie haben kein aktives Curriculum Element mit einem publizierten Kurs in diesem Curriculum.
 curriculum.key=ID
 curriculum.metadata=Metadaten
 curriculum.organisation=Organisation
@@ -92,6 +93,7 @@ tab.resources=Kurse
 tab.user.management=Benutzerverwaltung
 table.curriculum.element.empty=Curriculum ist leer
 table.curriculum.empty=Es steht kein Curriculum zur Verf\u00FCgung
+table.header.active=Aktiv
 table.header.begin.date=Beginn
 table.header.calendars=Stundenplan
 table.header.curriculum=Curriculum
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 8ca8727dffa..2fcefb7a7e6 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
@@ -47,6 +47,7 @@ curriculum.element.types=Types
 curriculum.external.id=External ID
 curriculum.identifier=Identifier
 curriculum.in.my.courses.enabled=Curriculum in "My courses"
+curriculum.inactive.explain=You don't have an active curriculum element in this curriculum with a published course.
 curriculum.key=ID
 curriculum.metadata=Metadata
 curriculum.organisation=Organisation
@@ -92,6 +93,7 @@ tab.resources=Courses
 tab.user.management=User management
 table.curriculum.element.empty=Curriculum is empty
 table.curriculum.empty=There are no curriculum available
+table.header.active=Active
 table.header.begin.date=Begin
 table.header.calendars=Calendar
 table.header.curriculum=Curriculum
diff --git a/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumActiveCellRenderer.java b/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumActiveCellRenderer.java
new file mode 100644
index 00000000000..36ade0af782
--- /dev/null
+++ b/src/main/java/org/olat/modules/curriculum/ui/component/CurriculumActiveCellRenderer.java
@@ -0,0 +1,54 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.curriculum.ui.component;
+
+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.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: 25 avr. 2019<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CurriculumActiveCellRenderer implements FlexiCellRenderer {
+	
+	private final Translator translator;
+	
+	public CurriculumActiveCellRenderer(Translator translator) {
+		this.translator = translator;
+	}
+
+	@Override
+	public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
+			URLBuilder ubu, Translator trans) {
+		if(cellValue instanceof Boolean) {
+			Boolean active = (Boolean)cellValue;
+			if(!active.booleanValue()) {
+				String title = translator.translate("curriculum.inactive.explain");
+				target.append("<i class='o_icon o_icon_repo_status_closed' title=\"").append(title).append("\"> </i>");
+			}
+		}
+	}
+}
-- 
GitLab