private static IEnumerable <Claim> ExtractGuestClaims(ProjectGuestContext projectGuestContext)
        {
            yield return(new Claim(ClaimTypes.GuestTenant, projectGuestContext.TenantId.ToString()));

            yield return(new Claim(ClaimTypes.GuestProject, projectGuestContext.ProjectId.ToString()));

            yield return(new Claim(ClaimTypes.GuestSession, projectGuestContext.GuestSessionId.ToString()));

            yield return(new Claim(ClaimTypes.GuestState, projectGuestContext.GuestState.ToString()));
        }
        public async Task <CurrentProjectState> SetProjectGuestContextAsync(Guid projectId, string accessCode, Guid currentUserId, Guid?currentUserTenantId, Guid principalId)
        {
            if (projectId.Equals(Guid.Empty))
            {
                return(await ClearGuestSessionState(currentUserId));
            }

            var projectResponse = await _serviceToServiceProjectApi.GetProjectByIdAsync(projectId);

            if (!projectResponse.IsSuccess() || projectResponse.Payload == null)
            {
                throw new InvalidOperationException($"Error fetching project {projectId} with service to service client, {projectResponse?.ResponseCode} - {projectResponse?.ReasonPhrase}");
            }

            var projectTenantId = projectResponse.Payload.TenantId;

            (ProjectGuestContext guestContext,
             MicroserviceResponse <IEnumerable <Guid> > projectUsersResponse) = await LoadDataAsync(projectId, projectTenantId);


            if (!projectUsersResponse.IsSuccess() || projectUsersResponse.Payload == null)
            {
                throw new InvalidOperationException($"Error fetching project users {projectId}, {projectUsersResponse.ResponseCode} - {projectUsersResponse.ReasonPhrase}");
            }

            var project = projectResponse?.Payload;
            var userIsFullProjectMember = projectUsersResponse.Payload.Any(userId => userId == currentUserId);

            if (UserHasActiveProjectGuestContext(guestContext) && userIsFullProjectMember)
            {
                //User is in project's account and was a guest who was promoted to a full
                //member, clear guest properties. This changes the return value of ProjectGuestContextService.IsGuestAsync() to false.
                guestContext = new ProjectGuestContext();
                await _projectGuestContextService.SetProjectGuestContextAsync(guestContext);
            }

            var userHasAccess = UserHasActiveProjectGuestContext(guestContext) ?
                                await IsGuestCurrentlyAdmittedToProjectAsync(guestContext.GuestSessionId) :
                                userIsFullProjectMember;

            if (userHasAccess)
            {
                return(await CreateCurrentProjectState(project, true));
            }

            if (UserHasActiveProjectGuestContext(guestContext) && guestContext?.ProjectId == project?.Id)
            {
                return(await CreateCurrentProjectState(project, false));
            }

            var userResponse = await _userApi.GetUserAsync(currentUserId);

            if (!userResponse.IsSuccess() || userResponse?.Payload == null)
            {
                throw new InvalidOperationException($"Error fetching user for {currentUserId}, {userResponse?.ResponseCode} - {userResponse?.ReasonPhrase}");
            }

            var userName      = !string.IsNullOrEmpty(userResponse.Payload.Email) ? userResponse.Payload.Email : userResponse.Payload.Username;
            var verifyRequest = new GuestVerificationRequest {
                Username = userName, ProjectAccessCode = accessCode, ProjectId = projectId
            };

            var guestVerifyResponse = await _guestSessionController.VerifyGuestAsync(verifyRequest, project, currentUserTenantId);

            if (guestVerifyResponse.ResultCode != VerifyGuestResponseCode.Success)
            {
                throw new InvalidOperationException($"Failed to verify guest for User.Id = {currentUserId}, Project.Id = {projectId}. ResponseCode = {guestVerifyResponse.ResultCode}. Reason = {guestVerifyResponse.Message}");
            }

            var newSession = await _guestSessionController.CreateGuestSessionAsync(new GuestSession
            {
                UserId            = currentUserId,
                ProjectId         = projectId,
                ProjectAccessCode = project.GuestAccessCode,
                GuestSessionState = InternalApi.Enums.GuestState.InLobby
            }, principalId, projectTenantId);

            await _projectGuestContextService.SetProjectGuestContextAsync(new ProjectGuestContext()
            {
                GuestSessionId = newSession.Id,
                ProjectId      = project.Id,
                GuestState     = Guest.ProjectContext.Enums.GuestState.InLobby,
                TenantId       = project.TenantId
            });


            if (!userIsFullProjectMember)
            {
                var request = new GrantProjectMembershipRequest
                {
                    UserId    = currentUserId,
                    ProjectId = project.Id,
                    Role      = MemberRole.GuestUser
                };
                var grantUserResponse = await _serviceToServiceProjectAccessApi.GrantProjectMembershipAsync(request, new List <KeyValuePair <string, string> > {
                    HeaderKeys.CreateTenantHeaderKey(projectTenantId)
                });

                if (!grantUserResponse.IsSuccess())
                {
                    throw new InvalidOperationException("Failed to add user to project");
                }
            }

            return(await CreateCurrentProjectState(project, false));
        }
 private bool UserHasActiveProjectGuestContext(ProjectGuestContext context)
 {
     return(context != null && context.ProjectId != Guid.Empty && context.TenantId != Guid.Empty &&
            context.GuestSessionId != Guid.Empty && context.GuestState != GuestState.Ended);
 }
        public ProjectGuestContextControllerTests()
        {
            _defaultProject = new Project()
            {
                Id = _defaultProjectId, TenantId = _projectTenantId, GuestAccessCode = _defaultAccessCode
            };
            _defaultPrincipalId          = Guid.NewGuid();
            _defaultProjectTenantHeaders = new List <KeyValuePair <string, string> >()
            {
                new KeyValuePair <string, string>(HeaderKeys.Tenant, _defaultProject.TenantId.ToString())
            };
            _defaultUser = new User {
                Id = _currentUserId, Username = "******"
            };
            var defaultProjectLobbyState = new ProjectLobbyState {
                LobbyState = LobbyState.Normal, ProjectId = _defaultProjectId
            };

            _defaultGuestSession = new GuestSession {
                Id = Guid.NewGuid(), ProjectId = _defaultProjectId, UserId = _currentUserId, ProjectAccessCode = _defaultAccessCode, GuestSessionState = GuestState.InLobby, SessionId = _defaultUserSessionId
            };
            _defaultProjectGuestContext = new ProjectGuestContext
            {
                GuestSessionId = _defaultGuestSession.Id,
                GuestState     = Guest.ProjectContext.Enums.GuestState.InLobby,
                ProjectId      = _defaultProjectId,
                TenantId       = _projectTenantId
            };

            var repositoryFactoryMock = new Mock <IRepositoryFactory>();

            repositoryFactoryMock
            .Setup(x => x.CreateRepository <GuestSession>())
            .Returns(_guestSessionRepositoryMock.Object);

            _projectGuestContextServiceMock
            .Setup(x => x.GetProjectGuestContextAsync(It.IsAny <string>()))
            .ReturnsAsync(_defaultProjectGuestContext);

            _projectAccessApiMock
            .Setup(x => x.GrantProjectMembershipAsync(It.IsAny <GrantProjectMembershipRequest>(), _defaultProjectTenantHeaders))
            .ReturnsAsync(MicroserviceResponse.Create(HttpStatusCode.OK));

            _guestSessionControllerMock
            .Setup(x => x.UpdateGuestSessionStateAsync(It.IsAny <UpdateGuestSessionStateRequest>(), It.IsAny <Guid>()))
            .ReturnsAsync(new UpdateGuestSessionStateResponse());

            _guestSessionControllerMock
            .Setup(x => x.VerifyGuestAsync(It.IsAny <GuestVerificationRequest>(), It.IsAny <Project>(), It.IsAny <Guid?>()))
            .ReturnsAsync(new GuestVerificationResponse()
            {
                ResultCode = VerifyGuestResponseCode.Success
            });

            _guestSessionControllerMock
            .Setup(x => x.CreateGuestSessionAsync(It.IsAny <GuestSession>(), _defaultPrincipalId, It.IsAny <Guid>()))
            .ReturnsAsync(_defaultGuestSession);

            _userApiMock
            .Setup(x => x.GetUserAsync(_currentUserId))
            .ReturnsAsync(MicroserviceResponse.Create(HttpStatusCode.OK, _defaultUser));

            _serviceToServiceProjectApiMock
            .Setup(x => x.GetProjectByIdAsync(_defaultProjectId, null))
            .ReturnsAsync(MicroserviceResponse.Create(HttpStatusCode.OK, _defaultProject));

            _projectAccessApiMock
            .Setup(x => x.GetProjectMemberUserIdsAsync(_defaultProjectId, MemberRoleFilter.FullUser, _defaultProjectTenantHeaders))
            .ReturnsAsync(MicroserviceResponse.Create(HttpStatusCode.OK, (new List <Guid>()
            {
                _currentUserId
            }).AsEnumerable()));

            _projectLobbyStateControllerMock
            .Setup(x => x.GetProjectLobbyStateAsync(_defaultProjectId))
            .ReturnsAsync(defaultProjectLobbyState);

            _target = new ProjectGuestContextController(repositoryFactoryMock.Object,
                                                        _guestSessionControllerMock.Object,
                                                        _projectLobbyStateControllerMock.Object,
                                                        _projectGuestContextServiceMock.Object,
                                                        _projectAccessApiMock.Object,
                                                        _serviceToServiceProjectApiMock.Object,
                                                        _userApiMock.Object);
        }