From 533817849a85f69f7e22343d63c22f4b8443083c Mon Sep 17 00:00:00 2001
From: Jorrit Schaap <schaap@astron.nl>
Date: Thu, 24 Mar 2022 13:29:15 +0100
Subject: [PATCH] TMSS-1628: Implemented a reverse lookup from unique-email to
 multiple-persons-with-that-email, and pick the 'best' user display name from
 that. Show the list of best names in the api

---
 .../src/tmss/tmssapp/adapters/keycloak.py     | 36 +++++++++++++++++++
 .../tmss/tmssapp/viewsets/specification.py    |  4 +--
 2 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/keycloak.py b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/keycloak.py
index 00641dc862f..e162fd5632a 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/adapters/keycloak.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/adapters/keycloak.py
@@ -131,3 +131,39 @@ def get_user_mapping():
                 user_map['%s, %s' % (user['lastName'], user['firstName'])] = user['email']
 
     return user_map
+
+
+@cachetools.func.ttl_cache(ttl=600)
+def get_email_to_name_mapping():
+    # first create a reverse map of unique-email to multiple-usernames-for-the-same-person
+    reverse_users_map = {}
+    for name, email in get_user_mapping().items():
+        if email not in reverse_users_map:
+            reverse_users_map[email] = []
+        reverse_users_map[email].append(name)
+    email_to_name_map = {}
+    for email, names in reverse_users_map.items():
+        if len(names) == 1:
+            # just one username for this unique email address, so use it
+            email_to_name_map[email] = names[0]
+        elif len(names) > 1:
+            # multiple usernames for this unique email address, so determine the 'best' one
+            # filter out the 'ugly' local ldap name
+            names2 = [n for n in names if 'cn=' not in n]
+            if names2:
+                # pick the first not 'ugly' local ldap name
+                email_to_name_map[email] = names2[0]
+            else:
+                # just pick the first, we have to choose something
+                email_to_name_map[email] = names[0]
+    return email_to_name_map
+
+
+def get_names_by_role_in_project(role, project):
+    """
+    returns the list of user display names that have the specified role in the specified project
+    """
+    emails = get_users_by_role_in_project(role, project)
+    map = get_email_to_name_mapping()
+    return [map.get(email, email) for email in emails]
+
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py
index 6e074f536e3..b288ccf0013 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py
@@ -29,7 +29,7 @@ from lofar.sas.tmss.tmss.tmssapp.viewsets.lofar_viewset import LOFARViewSet, LOF
 from lofar.sas.tmss.tmss.tmssapp import models
 from lofar.sas.tmss.tmss.tmssapp import serializers
 from lofar.sas.tmss.tmss.tmssapp.adapters.reports import create_cycle_report, create_project_report
-from lofar.sas.tmss.tmss.tmssapp.adapters.keycloak import get_users_by_role_in_project
+from lofar.sas.tmss.tmss.tmssapp.adapters.keycloak import get_names_by_role_in_project
 from django.http import JsonResponse
 
 from datetime import datetime
@@ -484,7 +484,7 @@ class ProjectViewSet(LOFARViewSet):
     @action(methods=['get'], detail=True, url_name="friend", name="Friend(s) of this project")
     def friend(self, request, pk=None):
         project = get_object_or_404(models.Project, pk=pk)
-        result = get_users_by_role_in_project(models.ProjectRole.Choices.FRIEND_OF_PROJECT.value, project.name)
+        result = get_names_by_role_in_project(models.ProjectRole.Choices.FRIEND_OF_PROJECT.value, project.name)
         return Response(result, status=status.HTTP_200_OK)
 
     @swagger_auto_schema(responses={200: 'List of roles that the requesting user has in this project',
-- 
GitLab