InviteController.java

package access.api;

import access.exception.InvalidInputException;
import access.exception.UserRestrictionException;
import access.invite.InviteClient;
import access.manage.Manage;
import access.model.Organization;
import access.model.User;
import access.repository.OrganizationRepository;
import access.repository.UserRepository;
import io.hypersistence.utils.spring.repository.BaseJpaRepository;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

import static access.manage.Manage.INSTITUTION_GUID;
import static access.manage.ManageData.getData;
import static access.manage.ManageData.getMetaDataFields;

@RestController
@RequestMapping(value = {"/api/v1/invite"}, produces = MediaType.APPLICATION_JSON_VALUE)
@Transactional
public class InviteController implements UserAccessRights {

    private static final Log LOG = LogFactory.getLog(InviteController.class);

    private final InviteClient inviteClient;
    private final Manage manage;
    private final UserRepository userRepository;
    private final OrganizationRepository organizationRepository;

    public InviteController(InviteClient inviteClient,
                            Manage manage,
                            UserRepository userRepository,
                            OrganizationRepository organizationRepository) {
        this.inviteClient = inviteClient;
        this.manage = manage;
        this.userRepository = userRepository;
        this.organizationRepository = organizationRepository;
    }

    /*
     * The GUID of the organization is coin:institution_guid of the IdP in Manage. In the Invite domain, every role
     * has an organizationGUID (the coin:institution_guid of the IdP of the institution admin).
     *
     * The applicationManageId is the manage identifier of the Application (e.g., SP or RP)
     */
    @GetMapping("/roles/{organizationGUID}/{applicationManageId}")
    public ResponseEntity<List<Map<String, Object>>> rolesPerOrganizationInviteApplication(
            User user,
            @PathVariable String organizationGUID,
            @PathVariable String applicationManageId) {

        LOG.debug("/rolesPerOrganizationApplicationId");

        User userFromDB = reinitializeUser(user, userRepository);

        if (!userFromDB.isSuperUser() &&
                (!StringUtils.hasText(userFromDB.getOrganizationGUID()) || !StringUtils.hasText(organizationGUID))) {
            LOG.warn("Not fetching invite roles as there is no institution GUID for user: " + user.getEmail());
            return ResponseEntity.ok(List.of());
        }

        if (!userFromDB.isSuperUser() && !organizationGUID.equals(userFromDB.getOrganizationGUID())) {
            throw new UserRestrictionException(
                    String.format("User %s is not authorized for organizationGUID %s",
                            user.getEmail(), organizationGUID));
        }
        boolean noOrganizationGUID = !StringUtils.hasText(organizationGUID) ||
                "undefined".equals(organizationGUID) || "null".equalsIgnoreCase(organizationGUID);
        if (noOrganizationGUID && userFromDB.isSuperUser()) {
            //We use the authenticating authority
            Map<String, Object> identityProvider = manage.identityProviderByEntityID(userFromDB.getAuthenticatingAuthority());
            String idpInstitutionGUID = (String) getMetaDataFields(getData(identityProvider)).get(INSTITUTION_GUID);
            if (StringUtils.hasText(idpInstitutionGUID)) {
                organizationGUID = idpInstitutionGUID;
            } else {
                LOG.warn("Not fetching invite roles as there is no institution GUID for IdP: " + user.getAuthenticatingAuthority());
                return ResponseEntity.ok(List.of());
            }
        }
        if (!applicationManageId.matches("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$")
                && !applicationManageId.matches("^\\d+$")) {
            throw new InvalidInputException(
                    String.format("ApplicationManageId %s is not a valid UUID or number", applicationManageId));
        }
        List<Map<String, Object>> inviteRoles = this.inviteClient.rolesPerOrganizationApplicationId(organizationGUID, applicationManageId);
        return ResponseEntity.ok(inviteRoles);
    }


    @GetMapping("/roles-summary")
    @Transactional(readOnly = true)
    public ResponseEntity<List<Map<String, Object>>> rolesSummary(User user, @RequestParam("organizationId") Long organizationId) {
        LOG.debug("/rolesSummary called by: " + user.getEmail());
        Organization organization = organizationRepository.getReferenceById(organizationId);

        confirmInstitutionAdmin(user, organization);

        List<Map<String, Object>> inviteRoles = this.inviteClient.rolesSummary();
        return ResponseEntity.ok(inviteRoles);
    }

}