From f52be179dff96da6bce2960a5f5f942e3950c11e Mon Sep 17 00:00:00 2001
From: srosse <stephane.rosse@frentix.com>
Date: Fri, 14 Aug 2020 06:11:31 +0200
Subject: [PATCH] OO-4754: optimize several search form and user name in prefs

---
 .../den/_i18n/LocalStrings_fr.properties      | 94 +++++++------------
 .../admin/user/UserSearchFlexiController.java | 11 ++-
 .../admin/user/UserSearchListProvider.java    |  5 +-
 .../org/olat/basesecurity/IdentityShort.java  | 12 +++
 .../IdentityPowerSearchQueriesImpl.java       | 26 ++---
 .../impl/elements/AutoCompleterRenderer.java  | 11 +--
 .../table/FlexiTableCustomRenderer.java       |  3 +-
 .../elements/table/FlexiTableElementImpl.java |  3 +-
 .../ui/tool/AssessedIdentityListProvider.java |  2 +-
 .../modules/coach/ui/StudentListProvider.java |  1 -
 .../coach/ui/StudentsTableDataModel.java      |  6 +-
 .../manager/LectureBlockRollCallDAO.java      | 35 ++-----
 .../coach/LecturesSearchFormController.java   | 17 +++-
 .../olat/user/PreferencesFormController.java  | 20 +++-
 .../database/mysql/alter_15_1_x_to_15_2_0.sql | 16 ++++
 .../database/mysql/setupDatabase.sql          |  2 +
 .../oracle/alter_15_1_x_to_15_2_0.sql         | 17 ++++
 .../database/oracle/setupDatabase.sql         |  2 +
 .../postgresql/alter_15_1_x_to_15_2_0.sql     | 16 ++++
 .../database/postgresql/setupDatabase.sql     |  2 +
 20 files changed, 166 insertions(+), 135 deletions(-)

diff --git a/src/main/java/de/bps/course/nodes/den/_i18n/LocalStrings_fr.properties b/src/main/java/de/bps/course/nodes/den/_i18n/LocalStrings_fr.properties
index 590ae5563d8..8f39bfe3654 100644
--- a/src/main/java/de/bps/course/nodes/den/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/de/bps/course/nodes/den/_i18n/LocalStrings_fr.properties
@@ -1,85 +1,60 @@
 #Sat Jan 08 13:09:53 CET 2011
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-config.create.dates=cr\u00E9er rendez-vous
+config.create.dates=Cr\u00E9er rendez-vous
 config.dates=G\u00E9rer les rendez-vous
-config.dates.begin=d\u00E9but de rendez-vous
+config.dates.begin=D\u00E9but de rendez-vous
 config.dates.begin.example=(dd.MM.yyyy HH\:mm)
-config.dates.comment=remarque
-config.dates.duration=dur\u00E9e d'un rendez-vous
+config.dates.comment=Remarque
+config.dates.duration=Dur\u00E9e d'un rendez-vous
 config.dates.duration.example=(hh\:mm)
-config.dates.duration.single=dur\u00E9e du rendez-vous
-config.dates.location=lieu
-config.dates.move=diff\u00E9rer rendez-vous
+config.dates.duration.single=Dur\u00E9e du rendez-vous
+config.dates.location=Lieu
+config.dates.move=Diff\u00E9rer rendez-vous
 config.dates.move.example=(+/-hh\:mm)
 config.dates.participants=Nombre de participants par rendez-vous
 config.dates.pause=Pause
 config.dates.pause.example=(hh\:mm)
-config.dates.retakes=nombre rendez-vous
+config.dates.retakes=Nombre rendez-vous
 config.dates.save=Enregistrer et fermer
-config.dates.subject=titre de rendez-vous
-config.default.values=valeurs par d\u00E9faut
-config.header=distribution de rendez-vous
+config.dates.subject=Titre du rendez-vous
+config.default.values=Valeurs par d\u00E9faut
+config.header=Distribution de rendez-vous
 config.nodates.long=Vous n'avez pas encore cr\u00E9\u00E9 des rendez-vous pour lesquels les participants peuvent s'inscrire.
 config.nodates.short=Pas de rendez-vous disponible
-config.tasks=devoirs
-config.type.date=distribution de rendez-vous
-config.type.group=inscription de groupe
+config.tasks=Devoirs
+config.type.date=Distribution de rendez-vous
+config.type.group=Inscription de groupe
 dates.edit=Editer rendez-vous
-dates.table.begin=d\u00E9but
-dates.table.comment=remarque
-dates.table.date=rendez-vous
+dates.table.begin=D\u00E9but
+dates.table.comment=Remarque
+dates.table.date=Rendez-vous
 dates.table.duration=Dur\u00E9e
 dates.table.edit.change=Editer
 dates.table.edit.delete=Effacer
-dates.table.edit.save=enregistrer
+dates.table.edit.save=Enregistrer
 dates.table.empty=Aucune date ne peut \u00EAtre affich\u00E9es
-dates.table.end=fin
-dates.table.list=liste des participants pour la distribution de rendez-vous
+dates.table.end=Fin
+dates.table.list=Liste des participants pour la distribution de rendez-vous
 dates.table.list.delete=Enlever des participants
-dates.table.list.email=Envoyer e-mail
-dates.table.location=lieu
+dates.table.list.email=Envoyer courriel
+dates.table.location=Lieu
 dates.table.participant.email=E-mail
-dates.table.participant.email.send=\u00C9crire e-mail
+dates.table.participant.email.send=\u00C9crire courriel
 dates.table.participant.firstname=Pr\u00E9nom
 dates.table.participant.lastname=Nom
-dates.table.participant.manage=administrer
+dates.table.participant.manage=Administrer
 dates.table.participant.name=Nom
 dates.table.participant.username=Nom d'utilisateur
 dates.table.participants.num=Anz. participants
 dates.table.reserved=Places
-dates.table.run.enrolled=inscrit(e)
+dates.table.run.enrolled=Inscrit(e)
 dates.table.run.full=Occup\u00E9
 dates.table.run.no_action=-
 dates.table.run.notenrolled=Non inscrit(e)
 dates.table.sign.in=Inscription
 dates.table.sign.out=Se d\u00E9sinscrire
 dates.table.status=Statut
-dates.table.subject=titre de rendez-vous
-dates.table.timeframe=d\u00E9but - fin
+dates.table.subject=Titre de rendez-vous
+dates.table.timeframe=D\u00E9but - fin
 enrollment.error.enrolled=Inscription impossible. Un seul participant ne peut \u00EAtre inscrit que dans un seul rendez-vous.
 enrollment.error.full=Votre inscription n'a pas pu \u00EAtre compl\u00E9t\u00E9e. Cette date est d\u00E9j\u00E0 r\u00E9serv\u00E9e.
 enrollment.error.general=Une erreur inattendue s'est produite.
@@ -87,24 +62,23 @@ enrollment.error.notenrolled=Le participant ne peut pas \u00EAtre d\u00E9sinscri
 enrollment.error.persisting=Une erreur s'est produite lors de l'enregistrement. Veuillez v\u00E9rifier votre derni\u00E8re activit\u00E9.
 enrollment.warning.manual=Au moins un participant n'a pas pu \u00EAtre inscrit. Probablement le participant est d\u00E9j\u00E0 inscrit dans un autre rendez-vous.
 form.enableCancelEnroll=d\u00E9sinscription autoris\u00E9e
-form.error.format=mauvaise entr\u00E9e
+form.error.format=Mauvaise entr\u00E9e
 form.error.notempty=Veuillez remplir
 guestnoaccess.message=Cette partie du cours n'est pas accessible pour les invit\u00E9s. <p> Pour aqu\u00E9rir un acc\u00E8s vers cette partie, vous devez vous identifier via une universit\u00E9 ou vous enregistrer dans OLAT.
 guestnoaccess.title=Pas d'acc\u00E8s pour les invit\u00E9s
-
 mail.participants.add.body=*** Ceci est un message g\u00E9n\u00E9r\u00E9 automatiquement. Veuillez ne pas y r\u00E9pondre. *** \n\nVous avez \u00E9t\u00E9 inscrit par {0} {1} ({2}) \u00E0 un rendez-vous \: \n\nNomDuRendezVous\: {4}
 mail.participants.add.subject=distribution de rendez-vous\: {4}. vous avez \u00E9t\u00E9 inscrit(e).
 mail.participants.remove.body=*** Ceci est un message g\u00E9n\u00E9r\u00E9 automatiquement. Veuillez ne pas y r\u00E9pondre. *** \n\nVous avez \u00E9t\u00E9 d\u00E9sinscrit par {0} {1} ({2}) \u00E0 un rendez-vous \: \n\nNomDuRendezVous\: {4}\n\nEn cas de questions, veuillez contacter s.v.p. {0} {1} ({2}).
 mail.participants.remove.subject=distribution de rendez-vous\: {4}. vous avez \u00E9t\u00E9 d\u00E9sinscrit(e).
 notifications.entry=Modification d'utilisateur le {0}
 notifications.header=Attribution de la date dans le cours "{0}"
-pane.tab.denconfig=configuration
-participants=participants
-participants.add=ajouter participants
-participants.manage=g\u00E9rer participants
-participants.message=E-mail \u00E0 tous les participants
+pane.tab.denconfig=Configuration
+participants=Participants
+participants.add=Ajouter des participants
+participants.manage=G\u00E9rer les participants
+participants.message=Courriel \u00E0 tous les participants
 participants.message.empty=Veuillez faire un choix, s.v.p..
-participants.message.to=participants choisis
+participants.message.to=Participants choisis
 run.dates.enrollment=Inscription au rendez-vous
 run.enrollment.list=G\u00E9rer participants 
 table.model.duration.day=Jour
diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
index 3abdc121642..b1a69164a77 100644
--- a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
+++ b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
@@ -26,6 +26,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.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityModule;
@@ -139,7 +140,14 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController {
 		this.multiSelection = multiSelection;
 		Roles roles = ureq.getUserSession().getRoles();
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles);
-		userSearchFormPropertyHandlers = userManager.getUserPropertyHandlersFor(UserSearchForm.class.getCanonicalName(), isAdministrativeUser);
+		List<UserPropertyHandler> allSearchFormPropertyHandlers = userManager.getUserPropertyHandlersFor(UserSearchForm.class.getCanonicalName(), isAdministrativeUser);
+		if(isAdministrativeUser) {
+			userSearchFormPropertyHandlers = allSearchFormPropertyHandlers.stream()
+					.filter(prop -> !UserConstants.NICKNAME.equals(prop.getName()))
+					.collect(Collectors.toList());
+		} else {
+			userSearchFormPropertyHandlers = allSearchFormPropertyHandlers;
+		}
 		
 		searchableOrganisations = organisationService.getOrganisations(getIdentity(), roles,
 				OrganisationRoles.valuesWithoutGuestAndInvitee());
@@ -185,7 +193,6 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController {
 			loginEl = uifactory.addTextElement("login", "search.form.login", 128, "", searchFormContainer);
 			loginEl.setVisible(isAdministrativeUser);
 
-			
 			propFormItems = new HashMap<>();
 			for (UserPropertyHandler userPropertyHandler : userSearchFormPropertyHandlers) {
 				if (userPropertyHandler == null) continue;
diff --git a/src/main/java/org/olat/admin/user/UserSearchListProvider.java b/src/main/java/org/olat/admin/user/UserSearchListProvider.java
index 86a2685af0b..04e024030ee 100644
--- a/src/main/java/org/olat/admin/user/UserSearchListProvider.java
+++ b/src/main/java/org/olat/admin/user/UserSearchListProvider.java
@@ -30,6 +30,7 @@ import org.olat.basesecurity.IdentityShort;
 import org.olat.core.CoreSpringFactory;
 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.core.id.Organisation;
 import org.olat.core.id.UserConstants;
 import org.olat.user.UserManager;
@@ -81,9 +82,9 @@ public class UserSearchListProvider implements ListProvider {
 			maxEntries--;
 			IdentityShort ident = it_res.next();
 			String key = ident.getKey().toString();
-			String displayKey = ident.getName();
+			String displayKey = ident.getNickName();
 			String displayText = userManager.getUserDisplayName(ident);
-			receiver.addEntry(key, displayKey, displayText, null);
+			receiver.addEntry(key, displayKey, displayText, CSSHelper.CSS_CLASS_USER);
 		}
 		if(hasMore){
 			receiver.addEntry(".....",".....");
diff --git a/src/main/java/org/olat/basesecurity/IdentityShort.java b/src/main/java/org/olat/basesecurity/IdentityShort.java
index 4dbbea36613..80fcfbe1024 100644
--- a/src/main/java/org/olat/basesecurity/IdentityShort.java
+++ b/src/main/java/org/olat/basesecurity/IdentityShort.java
@@ -71,10 +71,14 @@ public class IdentityShort implements Persistable, IdentityNames {
 	private Date lastLogin;
 	@Column(name="id_status", nullable=true, unique=false, insertable=false, updatable=false)
 	private int status;
+	@Column(name="id_external", nullable=true, unique=false, insertable=false, updatable=false)
+	private String externalId;
 	@Column(name="first_name", nullable=true, unique=false, insertable=false, updatable=false)
 	private String firstName;
 	@Column(name="last_name", nullable=true, unique=false, insertable=false, updatable=false)
 	private String lastName;
+	@Column(name="nick_name", nullable=true, unique=false, insertable=false, updatable=false)
+	private String nickName;
 	@Column(name="email", nullable=true, unique=false, insertable=false, updatable=false)
 	private String email;
 
@@ -92,6 +96,10 @@ public class IdentityShort implements Persistable, IdentityNames {
 		return name;
 	}
 
+	public String getExternalId() {
+		return externalId;
+	}
+
 	public Date getLastLogin() {
 		return lastLogin;
 	}
@@ -110,6 +118,10 @@ public class IdentityShort implements Persistable, IdentityNames {
 		return lastName;
 	}
 
+	public String getNickName() {
+		return nickName;
+	}
+
 	public String getEmail() {
 		return email;
 	}
diff --git a/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java b/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java
index 15fd5fd2a53..d4d1493d79b 100644
--- a/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java
+++ b/src/main/java/org/olat/basesecurity/manager/IdentityPowerSearchQueriesImpl.java
@@ -370,28 +370,14 @@ public class IdentityPowerSearchQueriesImpl implements IdentityPowerSearchQuerie
 		}
 		// append query for login
 		if (params.getLogin() != null) {
-			if (params.getLogin().contains("_") && dbInstance.isOracle()) {
-				//oracle needs special ESCAPE sequence to search for escaped strings
-				sb.append(" lower(ident.name) like :login ESCAPE '\\'");
-			} else if (dbInstance.isMySQL()) {
-				sb.append(" ident.name like :login");
-			} else {
-				sb.append(" lower(ident.name) like :login");
-			}
-			
+			sb.append("(");
+			PersistenceHelper.appendFuzzyLike(sb, "ident.name", "login", dbInstance.getDbVendor());
+			sb.append(" or ");
+			PersistenceHelper.appendFuzzyLike(sb, "user.nickName", "login", dbInstance.getDbVendor());
 			sb.append(" or exists (select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
 			  .append("  where ident.key=auth.identity.key and");
-			
-			if (params.getLogin().contains("_") && dbInstance.isOracle()) {
-				//oracle needs special ESCAPE sequence to search for escaped strings
-				sb.append(" lower(auth.authusername) like :login ESCAPE '\\'");
-			} else if (dbInstance.isMySQL()) {
-				sb.append(" auth.authusername like :login");
-			} else {
-				sb.append(" lower(auth.authusername) like :login");
-			}
-			
-			sb.append(")");
+			PersistenceHelper.appendFuzzyLike(sb, "auth.authusername", "login", dbInstance.getDbVendor());
+			sb.append("))");
 			
 			// if user fields follow a join element is needed
 			needsUserPropertiesJoin = true;
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/AutoCompleterRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/AutoCompleterRenderer.java
index cba7f1a74f3..6404937b90c 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/AutoCompleterRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/AutoCompleterRenderer.java
@@ -54,7 +54,6 @@ public class AutoCompleterRenderer extends DefaultComponentRenderer {
 		final int inputSize = 72;
 		String id = autoCompleter.getFormDispatchId();
 		if(autoCompleter.isEnabled()) {
-			boolean showDisplayKey = false;
 			String mapperUri = autoCompleter.getMapperUri();
 			int minLength = autoCompleter.getMinLength();
 			StringOutput command = new StringOutput(64);
@@ -80,13 +79,9 @@ public class AutoCompleterRenderer extends DefaultComponentRenderer {
 			  .append("     filter: function ( response ) {\n")
 			  .append("      return jQuery.map(response, function (object) {\n")
 			  .append("		  return {\n")
-			  .append("			value: '' + object.key,\n");
-			if(showDisplayKey) {
-				sb.append("       fullName: object.displayKey + ': ' + object.value\n");
-			} else {
-				sb.append("       fullName: object.value\n");
-			}
-			sb.append("         };\n")
+			  .append("			value: '' + object.key,\n")
+			  .append("         fullName: object.value\n")
+			  .append("         };\n")
 			  .append("       });\n")
 			  .append("     }\n")
 			  .append("   }\n")
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java
index 7ce7eb7722a..f3f8ee400eb 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableCustomRenderer.java
@@ -21,7 +21,6 @@ package org.olat.core.gui.components.form.flexible.impl.elements.table;
 
 
 import org.olat.core.gui.components.Component;
-import org.olat.core.gui.components.ComponentRenderer;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.impl.FormDecorator;
 import org.olat.core.gui.components.form.flexible.impl.FormJSHelper;
@@ -39,7 +38,7 @@ import org.olat.core.util.StringHelper;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-class FlexiTableCustomRenderer extends AbstractFlexiTableRenderer implements ComponentRenderer {
+class FlexiTableCustomRenderer extends AbstractFlexiTableRenderer {
 
 	@Override
 	public void render(Renderer renderer, StringOutput sb, Component source, URLBuilder ubu, Translator translator,
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
index f91f0ee3319..3c9c8d470c2 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/FlexiTableElementImpl.java
@@ -40,7 +40,6 @@ import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.ComponentEventListener;
 import org.olat.core.gui.components.choice.Choice;
 import org.olat.core.gui.components.form.flexible.FormItem;
-import org.olat.core.gui.components.form.flexible.FormItemCollection;
 import org.olat.core.gui.components.form.flexible.elements.AutoCompleter;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
@@ -80,7 +79,7 @@ import org.olat.core.util.prefs.Preferences;
  * @author Christian Guretzki
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
-public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableElement, FormItemCollection,
+public class FlexiTableElementImpl extends FormItemImpl implements FlexiTableElement,
 	ControllerEventListener, ComponentEventListener, Disposable {
 	
 	//settings
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListProvider.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListProvider.java
index 2d65f8cd4a8..ff34e922b2b 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListProvider.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListProvider.java
@@ -84,7 +84,7 @@ public class AssessedIdentityListProvider implements ListProvider {
 			maxEntries--;
 			IdentityShort ident = it_res.next();
 			String key = ident.getKey().toString();
-			String displayKey = ident.getName();//TODO username
+			String displayKey = ident.getNickName();
 			String displayText = userManager.getUserDisplayName(ident);
 			receiver.addEntry(key, displayKey, displayText, CSSHelper.CSS_CLASS_USER);
 		}					
diff --git a/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java b/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java
index bfc7f5f448f..b4c6c9c40aa 100644
--- a/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java
+++ b/src/main/java/org/olat/modules/coach/ui/StudentListProvider.java
@@ -60,7 +60,6 @@ public class StudentListProvider implements ListProvider {
 			if(contains(searchValue, entry)) {
 				maxEntries--;
 				String key = entry.getIdentityKey().toString();
-				String displayKey = null;//TODO username was name
 				String displayText = userManager.getUserDisplayName(entry.getIdentityKey());
 				receiver.addEntry(key, null, displayText, CSSHelper.CSS_CLASS_USER);
 			}
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 aef29ab595f..d0872c6a0fb 100644
--- a/src/main/java/org/olat/modules/coach/ui/StudentsTableDataModel.java
+++ b/src/main/java/org/olat/modules/coach/ui/StudentsTableDataModel.java
@@ -47,6 +47,7 @@ public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentSt
 	implements SortableFlexiTableDataModel<StudentStatEntry> {
 	
 	private static final Logger log = Tracing.createLoggerFor(StudentsTableDataModel.class);
+	private static final Columns[] COLS = Columns.values();
 
 	private List<StudentStatEntry> backupList;
 	
@@ -92,9 +93,9 @@ public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentSt
 	
 	@Override
 	public Object getValueAt(StudentStatEntry student, int col) {
-		if(col >= 0 && col < Columns.values().length) {
+		if(col >= 0 && col < COLS.length) {
 			int countRepo = student.getCountRepo();
-			switch(Columns.getValueAt(col)) {
+			switch(COLS[col]) {
 				case countCourse: return Integer.valueOf(countRepo);
 				case initialLaunch: {
 					if(countRepo == 0) {
@@ -134,6 +135,7 @@ public class StudentsTableDataModel extends DefaultFlexiTableDataModel<StudentSt
 					}
 					return new LightedValue(passed, light);
 				}
+				default: return "ERROR";
 			}
 		}
 
diff --git a/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java b/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java
index e50a7b4205d..0d1da581f97 100644
--- a/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java
+++ b/src/main/java/org/olat/modules/lecture/manager/LectureBlockRollCallDAO.java
@@ -852,28 +852,13 @@ public class LectureBlockRollCallDAO {
 		if(StringHelper.containsNonWhitespace(params.getLogin())) {
 			String login = PersistenceHelper.makeFuzzyQueryString(params.getLogin());
 			
-			sb.append(" and (");
-			if (login.contains("_") && dbInstance.isOracle()) {
-				//oracle needs special ESCAPE sequence to search for escaped strings
-				sb.append("lower(ident.name) like :login ESCAPE '\\'");
-			} else if (dbInstance.isMySQL()) {
-				sb.append("ident.name like :login");
-			} else {
-				sb.append("lower(ident.name) like :login");
-			}
-			
+			sb.append(" and (");	
+			PersistenceHelper.appendFuzzyLike(sb, "ident.name", "login", dbInstance.getDbVendor());
+			sb.append(" or ");
+			PersistenceHelper.appendFuzzyLike(sb, "user.nickName", "login", dbInstance.getDbVendor());
 			sb.append(" or exists (select auth from ").append(AuthenticationImpl.class.getName()).append(" as auth")
 			  .append("  where ident.key=auth.identity.key and");
-			
-			if (params.getLogin().contains("_") && dbInstance.isOracle()) {
-				//oracle needs special ESCAPE sequence to search for escaped strings
-				sb.append(" lower(auth.authusername) like :login ESCAPE '\\'");
-			} else if (dbInstance.isMySQL()) {
-				sb.append(" auth.authusername like :login");
-			} else {
-				sb.append(" lower(auth.authusername) like :login");
-			}
-			
+			PersistenceHelper.appendFuzzyLike(sb, "auth.authusername", "login", dbInstance.getDbVendor());
 			sb.append("))");
 			
 			queryParams.put("login", login);
@@ -897,14 +882,8 @@ public class LectureBlockRollCallDAO {
 					}
 				}
 				
-				if(dbInstance.isMySQL()) {
-					sb.append(" and user.").append(handler.getName()).append(" like :").append(qName);
-				} else {
-					sb.append(" and lower(user.").append(handler.getName()).append(") like :").append(qName);
-					if(dbInstance.isOracle()) {
-						sb.append(" escape '\\'");
-					}
-				}
+				sb.append(" and ");
+				PersistenceHelper.appendFuzzyLike(sb, "user.".concat(handler.getName()), qName, dbInstance.getDbVendor());
 				queryParams.put(qName, PersistenceHelper.makeFuzzyQueryString(propValue));
 			}
 		}
diff --git a/src/main/java/org/olat/modules/lecture/ui/coach/LecturesSearchFormController.java b/src/main/java/org/olat/modules/lecture/ui/coach/LecturesSearchFormController.java
index ee7bec4197b..d10fef867e3 100644
--- a/src/main/java/org/olat/modules/lecture/ui/coach/LecturesSearchFormController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/coach/LecturesSearchFormController.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.OrganisationModule;
@@ -42,6 +43,7 @@ import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.OrganisationRef;
 import org.olat.core.id.Roles;
+import org.olat.core.id.UserConstants;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.modules.lecture.model.LectureStatisticsSearchParameters;
@@ -67,9 +69,11 @@ public class LecturesSearchFormController extends FormBasicController {
 	private TextElement login;
 	private TextElement bulkEl;
 	private FormLink searchButton;
-	private DateChooser startDateEl, endDateEl;
+	private DateChooser startDateEl;
+	private DateChooser endDateEl;
 	private FormLayoutContainer privateDatesCont;
-	private SingleSelection dateTypesEl, publicDatesEl;
+	private SingleSelection dateTypesEl;
+	private SingleSelection publicDatesEl;
 
 	private final boolean admin;
 	private final boolean adminProps;
@@ -110,7 +114,14 @@ public class LecturesSearchFormController extends FormBasicController {
 		login = uifactory.addTextElement("login", "search.form.login", 128, "", formLayout);
 		login.setVisible(adminProps);
 		
-		userPropertyHandlers = userManager.getUserPropertyHandlersFor(PROPS_IDENTIFIER, adminProps);
+		List<UserPropertyHandler> allPropertyHandlers = userManager.getUserPropertyHandlersFor(PROPS_IDENTIFIER, adminProps);
+		if(adminProps) {
+			userPropertyHandlers = allPropertyHandlers.stream()
+					.filter(prop -> !UserConstants.NICKNAME.equals(prop.getName()))
+					.collect(Collectors.toList());
+		} else {
+			userPropertyHandlers = allPropertyHandlers;
+		}
 
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
 			if (userPropertyHandler != null) {
diff --git a/src/main/java/org/olat/user/PreferencesFormController.java b/src/main/java/org/olat/user/PreferencesFormController.java
index 5da21938aee..a7758c48e24 100644
--- a/src/main/java/org/olat/user/PreferencesFormController.java
+++ b/src/main/java/org/olat/user/PreferencesFormController.java
@@ -27,6 +27,7 @@ import java.util.Set;
 
 import org.olat.admin.user.SystemRolesAndRightsController;
 import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.core.commons.services.notifications.NotificationsManager;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -63,7 +64,12 @@ import org.springframework.beans.factory.annotation.Autowired;
  */
 public class PreferencesFormController extends FormBasicController {
 	private Identity tobeChangedIdentity;
-	private SingleSelection language, charset, notificationInterval, mailSystem;
+	
+	private SingleSelection charset;
+	private SingleSelection language;
+	private SingleSelection mailSystem;
+	private SingleSelection notificationInterval;
+	
 	private static final String[] mailIntern = new String[]{"intern.only","send.copy"};
 	
 	@Autowired
@@ -77,6 +83,8 @@ public class PreferencesFormController extends FormBasicController {
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
+	private BaseSecurityModule securityModule;
+	@Autowired
 	private NotificationsManager notificiationMgr;
 
 	/**
@@ -132,9 +140,13 @@ public class PreferencesFormController extends FormBasicController {
 		
 		// load preferences
 		Preferences prefs = tobeChangedIdentity.getUser().getPreferences();
-
+		
 		// Username
-		StaticTextElement username = uifactory.addStaticTextElement("form.username", tobeChangedIdentity.getName(), formLayout);
+		String name = securityManager.findAuthenticationName(tobeChangedIdentity);
+		if(!StringHelper.containsNonWhitespace(name) && !securityModule.isIdentityNameAutoGenerated()) {
+			name = tobeChangedIdentity.getName();
+		}
+		StaticTextElement username = uifactory.addStaticTextElement("form.username", name, formLayout);
 		username.setElementCssClass("o_sel_home_settings_username");
 		username.setEnabled(false);
 		
@@ -227,8 +239,8 @@ public class PreferencesFormController extends FormBasicController {
 		final FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("button_layout", getTranslator());
 		formLayout.add(buttonLayout);
 		buttonLayout.setElementCssClass("o_sel_home_settings_prefs_buttons");
-		uifactory.addFormSubmitButton("submit", buttonLayout);
 		uifactory.addFormCancelButton("cancel", buttonLayout, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("submit", buttonLayout);
 	}
 
 	@Override
diff --git a/src/main/resources/database/mysql/alter_15_1_x_to_15_2_0.sql b/src/main/resources/database/mysql/alter_15_1_x_to_15_2_0.sql
index fb3b2fa6aa6..fdd3b6f7beb 100644
--- a/src/main/resources/database/mysql/alter_15_1_x_to_15_2_0.sql
+++ b/src/main/resources/database/mysql/alter_15_1_x_to_15_2_0.sql
@@ -1,5 +1,21 @@
 alter table o_user add column u_nickname varchar(255);
 
+drop view o_bs_identity_short_v;
+create view o_bs_identity_short_v as (
+   select
+      ident.id as id_id,
+      ident.name as id_name,
+      ident.external_id as id_external,
+      ident.lastlogin as id_lastlogin,
+      ident.status as id_status,
+      us.user_id as us_id,
+      us.u_firstname as first_name,
+      us.u_lastname as last_name,
+      us.u_nickname as nick_name,
+      us.u_email as email
+   from o_bs_identity as ident
+   inner join o_user as us on (ident.id = us.fk_identity)
+);
 
 -- BigBlueButton
 create table o_bbb_attendee (
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index 8aa1db8c8d3..5e4256bc4fa 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -3130,11 +3130,13 @@ create view o_bs_identity_short_v as (
    select
       ident.id as id_id,
       ident.name as id_name,
+      ident.external_id as id_external,
       ident.lastlogin as id_lastlogin,
       ident.status as id_status,
       us.user_id as us_id,
       us.u_firstname as first_name,
       us.u_lastname as last_name,
+      us.u_nickname as nick_name,
       us.u_email as email
    from o_bs_identity as ident
    inner join o_user as us on (ident.id = us.fk_identity)
diff --git a/src/main/resources/database/oracle/alter_15_1_x_to_15_2_0.sql b/src/main/resources/database/oracle/alter_15_1_x_to_15_2_0.sql
index c828293c178..84c2a3397ff 100644
--- a/src/main/resources/database/oracle/alter_15_1_x_to_15_2_0.sql
+++ b/src/main/resources/database/oracle/alter_15_1_x_to_15_2_0.sql
@@ -1,5 +1,22 @@
 alter table o_user add u_nickname varchar2(255 char);
 
+drop view o_bs_identity_short_v;
+create view o_bs_identity_short_v as (
+   select
+      ident.id as id_id,
+      ident.name as id_name,
+      ident.external_id as id_external,
+      ident.lastlogin as id_lastlogin,
+      ident.status as id_status,
+      us.user_id as us_id,
+      us.u_firstname as first_name,
+      us.u_lastname as last_name,
+      us.u_nickname as nick_name,
+      us.u_email as email
+   from o_bs_identity ident
+   inner join o_user us on (ident.id = us.fk_identity)
+);
+
 
 -- BigBlueButton
 create table o_bbb_attendee (
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 2fca15fa30c..30d2e6129cb 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -3211,11 +3211,13 @@ create view o_bs_identity_short_v as (
    select
       ident.id as id_id,
       ident.name as id_name,
+      ident.external_id as id_external,
       ident.lastlogin as id_lastlogin,
       ident.status as id_status,
       us.user_id as us_id,
       us.u_firstname as first_name,
       us.u_lastname as last_name,
+      us.u_nickname as nick_name,
       us.u_email as email
    from o_bs_identity ident
    inner join o_user us on (ident.id = us.fk_identity)
diff --git a/src/main/resources/database/postgresql/alter_15_1_x_to_15_2_0.sql b/src/main/resources/database/postgresql/alter_15_1_x_to_15_2_0.sql
index ef307a74c64..c5842cbe3b4 100644
--- a/src/main/resources/database/postgresql/alter_15_1_x_to_15_2_0.sql
+++ b/src/main/resources/database/postgresql/alter_15_1_x_to_15_2_0.sql
@@ -1,5 +1,21 @@
 alter table o_user add column u_nickname varchar(255);
 
+drop view o_bs_identity_short_v;
+create view o_bs_identity_short_v as (
+   select
+      ident.id as id_id,
+      ident.name as id_name,
+      ident.external_id as id_external,
+      ident.lastlogin as id_lastlogin,
+      ident.status as id_status,
+      us.user_id as us_id,
+      us.u_firstname as first_name,
+      us.u_lastname as last_name,
+      us.u_nickname as nick_name,
+      us.u_email as email
+   from o_bs_identity as ident
+   inner join o_user as us on (ident.id = us.fk_identity)
+);
 
 -- BigBlueButton
 create table o_bbb_attendee (
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 151cc376f0f..3fa447c61e9 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -3152,11 +3152,13 @@ create view o_bs_identity_short_v as (
    select
       ident.id as id_id,
       ident.name as id_name,
+      ident.external_id as id_external,
       ident.lastlogin as id_lastlogin,
       ident.status as id_status,
       us.user_id as us_id,
       us.u_firstname as first_name,
       us.u_lastname as last_name,
+      us.u_nickname as nick_name,
       us.u_email as email
    from o_bs_identity as ident
    inner join o_user as us on (ident.id = us.fk_identity)
-- 
GitLab