From dd8cfb0f58b32ac8fdd8cf6460e6f25fe03612c3 Mon Sep 17 00:00:00 2001
From: Sonia Zorba <sonia.zorba@inaf.it>
Date: Wed, 7 Oct 2020 18:17:09 +0200
Subject: [PATCH] Handled invited registration automatically if first login
 happens

---
 gms/pom.xml                                   |   2 +-
 .../gms/controller/HomePageController.java    |   4 +-
 .../InvitedRegistrationController.java        |  22 ++-
 .../controller/JWTWebServiceController.java   |  39 +++-
 .../manager/InvitedRegistrationManager.java   |  80 ++++++---
 .../persistence/InvitedRegistrationDAO.java   |  80 ++++++---
 gms/src/main/resources/application.properties |   2 +-
 .../InvitedRegistrationManagerTest.java       | 168 ++++++++++++++++++
 .../InvitedRegistrationDAOTest.java           |   5 +
 9 files changed, 336 insertions(+), 66 deletions(-)
 create mode 100644 gms/src/test/java/it/inaf/ia2/gms/manager/InvitedRegistrationManagerTest.java

diff --git a/gms/pom.xml b/gms/pom.xml
index c54b418..a141c02 100644
--- a/gms/pom.xml
+++ b/gms/pom.xml
@@ -165,7 +165,7 @@
             <plugin>
                 <groupId>org.jacoco</groupId>
                 <artifactId>jacoco-maven-plugin</artifactId>
-                <version>0.8.4</version>
+                <version>0.8.6</version>
                 <executions>
                     <execution>
                         <goals>
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java
index ab10140..d39135f 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/HomePageController.java
@@ -82,9 +82,9 @@ public class HomePageController {
     @GetMapping(value = "/", produces = MediaType.TEXT_HTML_VALUE)
     public String index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
-        Optional<InvitedRegistration> optReg = invitedRegistrationManager.completeInvitedRegistrationIfNecessary();
+        Optional<List<InvitedRegistration>> optReg = invitedRegistrationManager.completeInvitedRegistrationIfNecessary();
         if (optReg.isPresent()) {
-            request.setAttribute("invited-registration", optReg.get());
+            request.setAttribute("invited-registrations", optReg.get());
             return "/registration-completed";
         }
 
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/InvitedRegistrationController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/InvitedRegistrationController.java
index 82dd95a..e5c2a18 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/InvitedRegistrationController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/InvitedRegistrationController.java
@@ -5,6 +5,8 @@ import it.inaf.ia2.gms.persistence.model.InvitedRegistration;
 import it.inaf.ia2.gms.service.GroupNameService;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
 import java.util.Scanner;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -32,7 +34,7 @@ public class InvitedRegistrationController {
 
         String html = getFileContent("invited-registration.html")
                 .replace("#EMAIL#", invitedRegistration.getEmail())
-                .replace("#GROUPS#", getGroupsList(invitedRegistration))
+                .replace("#GROUPS#", getGroupsList(Collections.singletonList(invitedRegistration)))
                 .replace("#HOME#", request.getContextPath());
 
         response.getOutputStream().print(html);
@@ -43,14 +45,14 @@ public class InvitedRegistrationController {
 
         response.setContentType("text/html;charset=UTF-8");
 
-        InvitedRegistration invitedRegistration = (InvitedRegistration) request.getAttribute("invited-registration");
-        if (invitedRegistration == null) {
+        List<InvitedRegistration> invitedRegistrations = (List<InvitedRegistration>) request.getAttribute("invited-registrations");
+        if (invitedRegistrations == null) {
             // redirect to home
             String baseUrl = ServletUriComponentsBuilder.fromCurrentContextPath().build().toUriString();
             response.sendRedirect(baseUrl);
         } else {
             String html = getFileContent("registration-completed.html")
-                    .replace("#GROUPS#", getGroupsList(invitedRegistration))
+                    .replace("#GROUPS#", getGroupsList(invitedRegistrations))
                     .replace("#HOME#", request.getContextPath());
 
             response.getOutputStream().print(html);
@@ -64,17 +66,19 @@ public class InvitedRegistrationController {
     }
 
     private String getFileContent(String templateFileName) throws IOException {
-        try (InputStream in = InvitedRegistrationController.class.getClassLoader().getResourceAsStream("templates/" + templateFileName)) {
+        try ( InputStream in = InvitedRegistrationController.class.getClassLoader().getResourceAsStream("templates/" + templateFileName)) {
             Scanner s = new Scanner(in).useDelimiter("\\A");
             return s.hasNext() ? s.next() : "";
         }
     }
 
-    private String getGroupsList(InvitedRegistration invitedRegistration) {
+    private String getGroupsList(List<InvitedRegistration> invitedRegistrations) {
         String groups = "<ul>";
-        for (String groupName : groupNameService.getGroupsNamesFromIdentifiers(
-                invitedRegistration.getGroupsPermissions().keySet())) {
-            groups += "<li>" + groupName + "</li>";
+        for (InvitedRegistration invitedRegistration : invitedRegistrations) {
+            for (String groupName : groupNameService.getGroupsNamesFromIdentifiers(
+                    invitedRegistration.getGroupsPermissions().keySet())) {
+                groups += "<li>" + groupName + "</li>";
+            }
         }
         groups += "</ul>";
         return groups;
diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
index 64f838d..8607c4b 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java
@@ -12,6 +12,7 @@ import it.inaf.ia2.gms.model.response.UserPermission;
 import it.inaf.ia2.gms.persistence.GroupsDAO;
 import it.inaf.ia2.gms.persistence.PermissionsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.persistence.model.InvitedRegistration;
 import it.inaf.ia2.gms.persistence.model.PermissionEntity;
 import it.inaf.ia2.gms.service.GroupNameService;
 import it.inaf.ia2.gms.service.GroupsService;
@@ -89,7 +90,7 @@ public class JWTWebServiceController {
 
         List<String> names = groupNameService.getGroupsNames(memberships);
 
-        try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+        try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
 
             for (String name : names) {
                 pw.println(name);
@@ -127,7 +128,7 @@ public class JWTWebServiceController {
         }
 
         if (isMember) {
-            try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+            try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
                 pw.println(group);
             }
         }
@@ -154,7 +155,7 @@ public class JWTWebServiceController {
             });
         }
 
-        try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+        try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
             for (String groupName : groupNameService.getGroupsNames(visibleSubgroups)) {
                 pw.println(getShortGroupName(groupName, group));
             }
@@ -185,7 +186,7 @@ public class JWTWebServiceController {
         }
 
         response.setStatus(HttpServletResponse.SC_CREATED);
-        try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+        try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
             pw.println(groupParam);
         }
     }
@@ -204,7 +205,7 @@ public class JWTWebServiceController {
 
         List<GroupEntity> groups = membershipManager.getUserGroups(parent, userId);
 
-        try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+        try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
             for (String groupName : groupNameService.getGroupsNames(groups)) {
                 pw.println(getShortGroupName(groupName, group));
             }
@@ -239,7 +240,7 @@ public class JWTWebServiceController {
     public void getUserPermission(@PathVariable("group") Optional<String> groupNames, @RequestParam("user_id") Optional<String> userId, HttpServletRequest request, HttpServletResponse response) throws IOException {
 
         if (userId.isPresent()) {
-            try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+            try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
                 for (UserPermission userPermission : searchService.getUserPermission(userId.get(), permissionsManager.getCurrentUserPermissions(getRoot()))) {
                     String group = String.join(".", userPermission.getGroupCompleteName());
                     pw.println(group + " " + userPermission.getPermission());
@@ -247,7 +248,7 @@ public class JWTWebServiceController {
             }
         } else {
             GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames));
-            try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+            try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
                 for (it.inaf.ia2.gms.model.UserPermission up : permissionsManager.getAllPermissions(groupEntity)) {
                     pw.println(up.getUser().getId() + " " + up.getPermission());
                 }
@@ -277,6 +278,28 @@ public class JWTWebServiceController {
         response.setStatus(HttpServletResponse.SC_NO_CONTENT);
     }
 
+    @GetMapping(value = "/check-invited-registration", produces = MediaType.TEXT_PLAIN_VALUE)
+    public void completeInvitedRegistrationIfNecessary(Principal principal, HttpServletResponse response) throws IOException {
+
+        String userId = principal.getName();
+
+        Set<String> groupIds = new HashSet<>();
+        for (InvitedRegistration invitedRegistration : invitedRegistrationManager.completeInvitedRegistrationIfNecessary(userId)) {
+            groupIds.addAll(invitedRegistration.getGroupsPermissions().keySet());
+        }
+        List<GroupEntity> groups = groupsDAO.findGroupsByIds(groupIds);
+
+        if (!groups.isEmpty()) {
+            List<String> names = groupNameService.getGroupsNames(groups);
+            try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+
+                for (String name : names) {
+                    pw.println(name);
+                }
+            }
+        }
+    }
+
     @PostMapping(value = "/invited-registration", produces = MediaType.TEXT_PLAIN_VALUE)
     public void addInvitedRegistration(@RequestParam("token_hash") String tokenHash, @RequestParam("email") String email,
             @RequestParam("groups") String groupNamesAndPermissionsParam, HttpServletResponse response) {
@@ -314,7 +337,7 @@ public class JWTWebServiceController {
             }
         }
 
-        try (PrintWriter pw = new PrintWriter(response.getOutputStream())) {
+        try ( PrintWriter pw = new PrintWriter(response.getOutputStream())) {
             for (RapUser member : membershipManager.getMembers(groupEntity)) {
                 if (selectedUserIds == null || selectedUserIds.contains(member.getId())) {
                     pw.println(member.getPrimaryEmail());
diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/InvitedRegistrationManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/InvitedRegistrationManager.java
index f30dca3..dec9449 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/manager/InvitedRegistrationManager.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/manager/InvitedRegistrationManager.java
@@ -1,5 +1,6 @@
 package it.inaf.ia2.gms.manager;
 
+import it.inaf.ia2.gms.authn.SessionData;
 import it.inaf.ia2.gms.exception.BadRequestException;
 import it.inaf.ia2.gms.exception.NotFoundException;
 import it.inaf.ia2.gms.exception.UnauthorizedException;
@@ -12,6 +13,7 @@ import it.inaf.ia2.gms.persistence.MembershipsDAO;
 import it.inaf.ia2.gms.persistence.model.GroupEntity;
 import it.inaf.ia2.gms.persistence.model.InvitedRegistration;
 import it.inaf.ia2.gms.persistence.model.MembershipEntity;
+import it.inaf.ia2.gms.rap.RapClient;
 import it.inaf.ia2.gms.service.PermissionsService;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
@@ -23,6 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.UUID;
+import java.util.stream.Collectors;
 import javax.servlet.http.HttpSession;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -48,9 +51,15 @@ public class InvitedRegistrationManager extends UserAwareComponent {
     private InvitedRegistrationDAO invitedRegistrationDAO;
 
     @Autowired
-    private LoggingDAO loggingDAO;
+    private RapClient rapClient;
+
+    @Autowired
+    private SessionData sessionData;
 
     @Autowired
+    private LoggingDAO loggingDAO;
+
+    @Autowired(required = false)
     private HttpSession httpSession;
 
     public void addInvitedRegistration(String tokenHash, String email, Map<GroupEntity, Permission> groupsPermissions) {
@@ -93,35 +102,66 @@ public class InvitedRegistrationManager extends UserAwareComponent {
         }
     }
 
-    public Optional<InvitedRegistration> completeInvitedRegistrationIfNecessary() {
+    public Optional<List<InvitedRegistration>> completeInvitedRegistrationIfNecessary() {
 
-        InvitedRegistration invitedRegistration = (InvitedRegistration) httpSession.getAttribute(INVITED_REGISTRATION);
+        List<InvitedRegistration> invitedRegistrations = completeInvitedRegistrationIfNecessary(sessionData.getUserId());
 
-        if (invitedRegistration != null) {
+        InvitedRegistration invitedRegistrationFromToken = (InvitedRegistration) httpSession.getAttribute(INVITED_REGISTRATION);
 
-            for (Map.Entry<String, Permission> entry : invitedRegistration.getGroupsPermissions().entrySet()) {
-                String groupId = entry.getKey();
-                String userId = getCurrentUserId();
+        if (invitedRegistrationFromToken != null) {
 
-                GroupEntity groupEntity = groupsDAO.findGroupById(groupId).get();
+            boolean alreadyDone = invitedRegistrations.stream().map(reg -> reg.getId())
+                    .anyMatch(id -> id.equals(invitedRegistrationFromToken.getId()));
 
-                MembershipEntity membershipEntity = new MembershipEntity();
-                membershipEntity.setUserId(userId);
-                membershipEntity.setGroupId(groupId);
-                membershipsDAO.addMember(membershipEntity);
-
-                permissionsService.addPermission(groupEntity, userId, entry.getValue());
+            if (!alreadyDone) {
+                completeInvitedRegistration(invitedRegistrationFromToken);
+                invitedRegistrations.add(invitedRegistrationFromToken);
             }
+            httpSession.removeAttribute(INVITED_REGISTRATION);
+        }
 
-            invitedRegistration.setUserId(getCurrentUserId());
-            // FIXME (workaround): separated update for user and done in order to use triggers
-            invitedRegistrationDAO.setRegistrationUser(invitedRegistration);
-            invitedRegistrationDAO.setRegistrationDone(invitedRegistration);
+        return Optional.ofNullable(invitedRegistrations.isEmpty() ? null : invitedRegistrations);
+    }
 
-            httpSession.removeAttribute(INVITED_REGISTRATION);
+    /**
+     * This method can be called from web service, since it doesn't rely on
+     * session.
+     */
+    public List<InvitedRegistration> completeInvitedRegistrationIfNecessary(String userId) {
+
+        List<InvitedRegistration> invitedRegistrations = new ArrayList<>();
+
+        List<String> emailAddresses = rapClient.getUser(userId).getIdentities().stream()
+                .map(identity -> identity.getEmail())
+                .collect(Collectors.toList());
+
+        for (InvitedRegistration invitedRegistration : invitedRegistrationDAO.getInvitedRegistrationsFromEmailAddresses(emailAddresses)) {
+            completeInvitedRegistration(invitedRegistration);
+            invitedRegistrations.add(invitedRegistration);
+        }
+
+        return invitedRegistrations;
+    }
+
+    private void completeInvitedRegistration(InvitedRegistration invitedRegistration) {
+        for (Map.Entry<String, Permission> entry : invitedRegistration.getGroupsPermissions().entrySet()) {
+            String groupId = entry.getKey();
+            String userId = getCurrentUserId();
+
+            GroupEntity groupEntity = groupsDAO.findGroupById(groupId).get();
+
+            MembershipEntity membershipEntity = new MembershipEntity();
+            membershipEntity.setUserId(userId);
+            membershipEntity.setGroupId(groupId);
+            membershipsDAO.addMember(membershipEntity);
+
+            permissionsService.addPermission(groupEntity, userId, entry.getValue());
         }
 
-        return Optional.ofNullable(invitedRegistration);
+        invitedRegistration.setUserId(getCurrentUserId());
+        // FIXME (workaround): separated update for user and done in order to use triggers
+        invitedRegistrationDAO.setRegistrationUser(invitedRegistration);
+        invitedRegistrationDAO.setRegistrationDone(invitedRegistration);
     }
 
     public List<InvitedRegistrationItem> getInvitedRegistrationsForGroup(GroupEntity group) {
diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java
index 43415d6..89698eb 100644
--- a/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java
+++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAO.java
@@ -3,6 +3,8 @@ package it.inaf.ia2.gms.persistence;
 import it.inaf.ia2.gms.model.Permission;
 import it.inaf.ia2.gms.persistence.model.InvitedRegistration;
 import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -150,7 +152,7 @@ public class InvitedRegistrationDAO {
 
     public List<InvitedRegistration> getPendingInvitedRegistrationsForGroup(String groupId) {
 
-        String sql = "SELECT id, email, creation_time, permission\n"
+        String sql = "SELECT id, email, creation_time, group_id, permission\n"
                 + "FROM invited_registration_request r\n"
                 + "JOIN invited_registration_request_group rg ON r.id = rg.request_id\n"
                 + "WHERE done IS NOT TRUE AND rg.group_id = ?";
@@ -160,39 +162,67 @@ public class InvitedRegistrationDAO {
                     ps.setString(1, groupId);
                 },
                 rs -> {
-                    // key: id
-                    Map<String, InvitedRegistration> map = new HashMap<>();
+                    List<InvitedRegistration> registrations = getInvitedRegistrationsFromResultSet(rs);
+                    Collections.sort(registrations, (reg1, reg2) -> reg1.getEmail().compareToIgnoreCase(reg2.getEmail()));
+                    return registrations;
+                });
+    }
+
+    public List<InvitedRegistration> getInvitedRegistrationsFromEmailAddresses(List<String> addresses) {
+
+        if (addresses.isEmpty()) {
+            throw new IllegalArgumentException("List of email addresses is empty");
+        }
+
+        String sql = "SELECT id, email, creation_time, group_id, permission\n"
+                + "FROM invited_registration_request r\n"
+                + "JOIN invited_registration_request_group rg ON r.id = rg.request_id\n"
+                + "WHERE done IS NOT TRUE AND ("
+                + String.join(" OR ", Collections.nCopies(addresses.size(), "email ILIKE ?"))
+                + ")";
+
+        return jdbcTemplate.query(sql,
+                ps -> {
+                    for (int i = 0; i < addresses.size(); i++) {
+                        ps.setString(i + 1, addresses.get(i));
+                    }
+                },
+                rs -> {
+                    return getInvitedRegistrationsFromResultSet(rs);
+                });
+    }
 
-                    while (rs.next()) {
+    private List<InvitedRegistration> getInvitedRegistrationsFromResultSet(ResultSet rs) throws SQLException {
 
-                        String id = rs.getString("id");
+        // key: invited registration id
+        Map<String, InvitedRegistration> map = new HashMap<>();
 
-                        InvitedRegistration reg = map.get(id);
-                        if (reg == null) {
-                            String email = rs.getString("email");
-                            Date creationTime = new Date(rs.getDate("creation_time").getTime());
-                            reg = new InvitedRegistration()
-                                    .setId(id)
-                                    .setEmail(email)
-                                    .setCreationTime(creationTime);
-                            map.put(id, reg);
-                        }
+        while (rs.next()) {
 
-                        if (reg.getGroupsPermissions() == null) {
-                            reg.setGroupsPermissions(new HashMap<>());
-                        }
+            String id = rs.getString("id");
 
-                        Permission permission = Permission.valueOf(rs.getString("permission"));
+            InvitedRegistration reg = map.get(id);
+            if (reg == null) {
+                String email = rs.getString("email");
+                Date creationTime = new Date(rs.getDate("creation_time").getTime());
+                reg = new InvitedRegistration()
+                        .setId(id)
+                        .setEmail(email)
+                        .setCreationTime(creationTime);
+                map.put(id, reg);
+            }
 
-                        reg.getGroupsPermissions().put(groupId, permission);
-                    }
+            if (reg.getGroupsPermissions() == null) {
+                reg.setGroupsPermissions(new HashMap<>());
+            }
 
-                    List<InvitedRegistration> registrations = new ArrayList<>(map.values());
+            Permission permission = Permission.valueOf(rs.getString("permission"));
 
-                    Collections.sort(registrations, (reg1, reg2) -> reg1.getEmail().compareToIgnoreCase(reg2.getEmail()));
+            String groupId = rs.getString("group_id");
+            reg.getGroupsPermissions().put(groupId, permission);
+        }
 
-                    return registrations;
-                });
+        return new ArrayList<>(map.values());
     }
 
     public void deleteInvitedRegistrationRequest(String requestId, String groupId) {
diff --git a/gms/src/main/resources/application.properties b/gms/src/main/resources/application.properties
index b096d05..1091bba 100644
--- a/gms/src/main/resources/application.properties
+++ b/gms/src/main/resources/application.properties
@@ -17,7 +17,7 @@ logging.level.org.springframework.security=DEBUG
 logging.level.org.springframework.jdbc=TRACE
 logging.level.org.springframework.web=TRACE
 
-spring.datasource.url=jdbc:postgresql://localhost:5432/gms2
+spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
 spring.datasource.username=gms
 spring.datasource.password=gms
 
diff --git a/gms/src/test/java/it/inaf/ia2/gms/manager/InvitedRegistrationManagerTest.java b/gms/src/test/java/it/inaf/ia2/gms/manager/InvitedRegistrationManagerTest.java
new file mode 100644
index 0000000..13cf87d
--- /dev/null
+++ b/gms/src/test/java/it/inaf/ia2/gms/manager/InvitedRegistrationManagerTest.java
@@ -0,0 +1,168 @@
+package it.inaf.ia2.gms.manager;
+
+import it.inaf.ia2.gms.authn.SessionData;
+import it.inaf.ia2.gms.model.Identity;
+import it.inaf.ia2.gms.model.IdentityType;
+import it.inaf.ia2.gms.model.Permission;
+import it.inaf.ia2.gms.model.RapUser;
+import it.inaf.ia2.gms.persistence.GroupsDAO;
+import it.inaf.ia2.gms.persistence.InvitedRegistrationDAO;
+import it.inaf.ia2.gms.persistence.LoggingDAO;
+import it.inaf.ia2.gms.persistence.MembershipsDAO;
+import it.inaf.ia2.gms.persistence.model.GroupEntity;
+import it.inaf.ia2.gms.persistence.model.InvitedRegistration;
+import it.inaf.ia2.gms.rap.RapClient;
+import it.inaf.ia2.gms.service.PermissionsService;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import javax.servlet.http.HttpSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class InvitedRegistrationManagerTest {
+
+    private static final String USER_ID = "USER_ID";
+    private static final String EMAIL = "user@inaf.it";
+
+    @Mock
+    private GroupsDAO groupsDAO;
+    @Mock
+    private MembershipsDAO membershipsDAO;
+    @Mock
+    private PermissionsService permissionsService;
+    @Mock
+    private PermissionsManager permissionsManager;
+    @Mock
+    private InvitedRegistrationDAO invitedRegistrationDAO;
+    @Mock
+    private RapClient rapClient;
+    @Mock
+    private SessionData sessionData;
+    @Mock
+    private LoggingDAO loggingDAO;
+    @Mock
+    private HttpSession httpSession;
+
+    @InjectMocks
+    private InvitedRegistrationManager invitedRegistrationManager;
+
+    @Before
+    public void setUp() {
+        UserAwareComponentTestUtil.setUser(invitedRegistrationManager, USER_ID);
+    }
+
+    @Test
+    public void testAddInvitedRegistration() {
+
+        Map<GroupEntity, Permission> groupsPermissions = new HashMap<>();
+        GroupEntity groupEntity = new GroupEntity();
+        groupEntity.setId("b");
+        groupEntity.setPath("a.b");
+        groupEntity.setName("B");
+        groupsPermissions.put(groupEntity, Permission.MANAGE_MEMBERS);
+
+        when(permissionsManager.getCurrentUserPermission(any())).thenReturn(Permission.ADMIN);
+
+        invitedRegistrationManager.addInvitedRegistration("token_hash", EMAIL, groupsPermissions);
+
+        verify(invitedRegistrationDAO, times(1)).addInvitedRegistration(any());
+    }
+
+    @Test
+    public void testCompleteInvitedRegistrationIfNecessaryGetByEmail() {
+
+        Map<String, Permission> map1 = new HashMap<>();
+        map1.put("g1", Permission.MANAGE_MEMBERS);
+
+        InvitedRegistration regFromToken = new InvitedRegistration()
+                .setId("reg1")
+                .setEmail(EMAIL)
+                .setGroupsPermissions(map1);
+
+        when(httpSession.getAttribute(eq("invited-registration"))).thenReturn(regFromToken);
+
+        when(sessionData.getUserId()).thenReturn(USER_ID);
+
+        RapUser user = new RapUser();
+        user.setId(USER_ID);
+        Identity identity = new Identity();
+        identity.setType(IdentityType.EDU_GAIN);
+        identity.setEmail(EMAIL);
+        user.setIdentities(Collections.singletonList(identity));
+
+        when(rapClient.getUser(eq(USER_ID))).thenReturn(user);
+
+        Map<String, Permission> map2 = new HashMap<>();
+        map2.put("g2", Permission.MANAGE_MEMBERS);
+
+        InvitedRegistration reg2 = new InvitedRegistration()
+                .setId("reg2")
+                .setEmail(EMAIL)
+                .setGroupsPermissions(map2);
+
+        List<InvitedRegistration> registrations = new ArrayList<>();
+        registrations.add(regFromToken);
+        registrations.add(reg2);
+        when(invitedRegistrationDAO.getInvitedRegistrationsFromEmailAddresses(any())).thenReturn(registrations);
+
+        GroupEntity g1 = new GroupEntity();
+        g1.setId("g1");
+        GroupEntity g2 = new GroupEntity();
+        g2.setId("g2");
+        when(groupsDAO.findGroupById(eq("g1"))).thenReturn(Optional.of(g1));
+        when(groupsDAO.findGroupById(eq("g2"))).thenReturn(Optional.of(g2));
+
+        invitedRegistrationManager.completeInvitedRegistrationIfNecessary();
+
+        verify(membershipsDAO, times(2)).addMember(any());
+        verify(permissionsService, times(2)).addPermission(any(), any(), any());
+    }
+
+    @Test
+    public void testCompleteInvitedRegistrationIfNecessaryGetByToken() {
+
+        Map<String, Permission> map1 = new HashMap<>();
+        map1.put("g1", Permission.MANAGE_MEMBERS);
+
+        InvitedRegistration regFromToken = new InvitedRegistration()
+                .setId("reg1")
+                .setEmail(EMAIL)
+                .setGroupsPermissions(map1);
+
+        when(httpSession.getAttribute(eq("invited-registration"))).thenReturn(regFromToken);
+
+        when(sessionData.getUserId()).thenReturn(USER_ID);
+
+        RapUser user = new RapUser();
+        user.setId(USER_ID);
+        Identity identity = new Identity();
+        identity.setType(IdentityType.EDU_GAIN);
+        identity.setEmail("different-email");
+        user.setIdentities(Collections.singletonList(identity));
+
+        when(rapClient.getUser(eq(USER_ID))).thenReturn(user);
+
+        GroupEntity g1 = new GroupEntity();
+        g1.setId("g1");
+        when(groupsDAO.findGroupById(eq("g1"))).thenReturn(Optional.of(g1));
+
+        invitedRegistrationManager.completeInvitedRegistrationIfNecessary();
+
+        verify(membershipsDAO, times(1)).addMember(any());
+        verify(permissionsService, times(1)).addPermission(any(), any(), any());
+    }
+}
diff --git a/gms/src/test/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAOTest.java b/gms/src/test/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAOTest.java
index 555f27b..f13c03d 100644
--- a/gms/src/test/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAOTest.java
+++ b/gms/src/test/java/it/inaf/ia2/gms/persistence/InvitedRegistrationDAOTest.java
@@ -80,6 +80,11 @@ public class InvitedRegistrationDAOTest {
         assertEquals(reg.getEmail(), regFromGroup.getEmail());
         assertNotNull(regFromGroup.getCreationTime());
 
+        List<String> addresses = new ArrayList<>();
+        addresses.add("test@inaf.it");
+        addresses.add("test2@inaf.it");
+        assertEquals(1, dao.getInvitedRegistrationsFromEmailAddresses(addresses).size());
+
         dao.setRegistrationDone(regFromGroup);
 
         assertTrue(dao.getPendingInvitedRegistrationsForGroup("group1").isEmpty());
-- 
GitLab