Beispiel #1
0
        public void MatchCandidate_WithExistingCandidateRequest_MatchesOnNewestCandidateWithEmail(
            string email,
            string firstName,
            string lastName,
            string expectedFirstName
            )
        {
            var request = new ExistingCandidateRequest {
                Email = email, FirstName = firstName, LastName = lastName
            };

            _mockService.Setup(mock => mock.CreateQuery("contact", _context)).Returns(MockCandidates());
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("dfe_contact_dfe_candidatequalification_ContactId"), _context));
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("dfe_contact_dfe_candidatepastteachingposition_ContactId"), _context));
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("dfe_contact_dfe_servicesubscription_contact"), _context));
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("msevtmgt_contact_msevtmgt_eventregistration_Contact"), _context));

            var result = _crm.MatchCandidate(request);

            result?.FirstName.Should().Be(expectedFirstName);
        }
        public IActionResult CreateAccessToken([FromBody, SwaggerRequestBody("Candidate access token request (must match an existing candidate).", Required = true)] ExistingCandidateRequest request)
        {
            if (!ModelState.IsValid)
            {
                return(BadRequest(this.ModelState));
            }

            if (_appSettings.IsCrmIntegrationPaused)
            {
                return(NotFound());
            }

            var candidate = _crm.MatchCandidate(request);

            if (candidate == null)
            {
                return(NotFound());
            }

            var token           = _accessTokenService.GenerateToken(request, (Guid)candidate.Id);
            var personalisation = new Dictionary <string, dynamic> {
                { "pin_code", token }
            };

            // We respond immediately/assume this will be successful.
            _notifyService.SendEmailAsync(request.Email, NotifyService.NewPinCodeEmailTemplateId, personalisation);

            return(NoContent());
        }
        public void Validate_SpecifyNoAdditionalRequiredAttributes_HasError()
        {
            var request = new ExistingCandidateRequest();

            var result = _validator.TestValidate(request);

            result.ShouldHaveValidationErrorFor(request => request).WithErrorMessage("You must specify values for 2 additional attributes (from birthdate, firstname and lastname).");
        }
        public string GenerateToken(ExistingCandidateRequest request, Guid candidateId)
        {
            var totp = CreateTotp(request).ComputeTotp();

            _metrics.GeneratedTotps.Inc();

            return(totp);
        }
        public void Slugify_WithMixedCasing_ReturnsLowerCase()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "FIrst"
            };

            request.Slugify().Should().Be("[email protected]");
        }
        public void Slugify_WithNullAdditionalAttribute_OmitsNull()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "first"
            };

            request.Slugify().Should().Be("[email protected]");
        }
        public void Validate_SpecifyTwoAdditionalRequiredAttributes_HasNoError()
        {
            var request = new ExistingCandidateRequest {
                FirstName = "first", LastName = "last"
            };

            var result = _validator.TestValidate(request);

            result.ShouldNotHaveValidationErrorFor(request => request);
        }
        public void Validate_WhenValid_HasNoErrors()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "first", DateOfBirth = DateTime.UtcNow.AddDays(-18)
            };

            var result = _validator.TestValidate(request);

            result.IsValid.Should().BeTrue();
        }
        public void Validate_SpecifyThreeAdditionalRequiredAttributes_HasNoError()
        {
            var request = new ExistingCandidateRequest {
                FirstName = "first", LastName = "last", DateOfBirth = DateTime.UtcNow.AddDays(-18)
            };

            var result = _validator.TestValidate(request);

            result.ShouldNotHaveValidationErrorFor(request => request);
        }
 public ExistingCandidateRequestTests()
 {
     _request = new ExistingCandidateRequest
     {
         Email       = "*****@*****.**",
         FirstName   = "first",
         LastName    = "last",
         DateOfBirth = new DateTime(2000, 1, 1)
     };
 }
        public void GenerateToken_SameRequestInSameStep_ReturnSameToken()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };
            var token1 = _service.GenerateToken(request, _candidateId);
            var token2 = _service.GenerateToken(request, _candidateId);

            token1.Should().Be(token2);
        }
 public CandidatesControllerTests()
 {
     _mockTokenService = new Mock <ICandidateAccessTokenService>();
     _mockCrm          = new Mock <ICrmService>();
     _mockJobClient    = new Mock <IBackgroundJobClient>();
     _request          = new ExistingCandidateRequest {
         Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
     };
     _controller = new CandidatesController(_mockTokenService.Object, _mockCrm.Object, _mockJobClient.Object);
 }
        public void GenerateToken_ReturnsAValidToken(string email, string firstName, string lastName)
        {
            var generatedTotpsCount = _metrics.GeneratedTotps.Value;
            var verifiedTotpsCount  = _metrics.VerifiedTotps.WithLabels(new[] { true.ToString() }).Value;
            var request             = new ExistingCandidateRequest {
                Email = email, FirstName = firstName, LastName = lastName
            };
            var token = _service.GenerateToken(request, _candidateId);

            _service.IsValid(token, request, _candidateId).Should().BeTrue();
            _metrics.GeneratedTotps.Value.Should().Be(generatedTotpsCount + 1);
            _metrics.VerifiedTotps.WithLabels(new[] { true.ToString() }).Value.Should().Be(verifiedTotpsCount + 1);
        }
        public void GenerateToken_DifferentFirstNameInSameStep_ReturnDifferentTokens()
        {
            var request1 = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John1", LastName = "Doe"
            };
            var request2 = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John2", LastName = "Doe"
            };
            var token1 = _service.GenerateToken(request1, _candidateId);
            var token2 = _service.GenerateToken(request2, _candidateId);

            token1.Should().NotBe(token2);
        }
        public IActionResult ExchangeAccessTokenForAttendee(
            [FromRoute, SwaggerParameter("Access token (PIN code).", Required = true)] string accessToken,
            [FromBody, SwaggerRequestBody("Candidate access token request (must match an existing candidate).", Required = true)] ExistingCandidateRequest request)
        {
            var candidate = _crm.MatchCandidate(request);

            if (candidate == null || !_tokenService.IsValid(accessToken, request, (Guid)candidate.Id))
            {
                return(Unauthorized());
            }

            return(Ok(new TeachingEventAddAttendee(candidate)));
        }
        public void IsValid_WithExpiredToken_ReturnsFalse()
        {
            var verifiedTotpsCount = _metrics.VerifiedTotps.WithLabels(new[] { false.ToString() }).Value;
            var request            = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };
            var secondsToOutsideOfWindow = (CandidateAccessTokenService.StepInSeconds * CandidateAccessTokenService.VerificationWindow) + 1;
            var dateTimeOutsideOfWindow  = DateTime.UtcNow.AddSeconds(-secondsToOutsideOfWindow);

            var token = _service.GenerateToken(request, _candidateId);

            _service.IsValid(token, request, _candidateId, dateTimeOutsideOfWindow).Should().BeFalse();
            _metrics.VerifiedTotps.WithLabels(new[] { false.ToString() }).Value.Should().Be(verifiedTotpsCount + 1);
        }
Beispiel #17
0
        public CandidatesControllerTests()
        {
            _mockTokenService = new Mock <ICandidateAccessTokenService>();
            _mockCrm          = new Mock <ICrmService>();
            _mockJobClient    = new Mock <IBackgroundJobClient>();
            _mockDateTime     = new Mock <IDateTimeProvider>();
            _request          = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };
            _controller = new CandidatesController(_mockTokenService.Object, _mockCrm.Object, _mockJobClient.Object, _mockDateTime.Object);

            // Freeze time.
            _mockDateTime.Setup(m => m.UtcNow).Returns(DateTime.UtcNow);
        }
 public TeachingEventsControllerTests()
 {
     _request = new ExistingCandidateRequest {
         Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
     };
     _mockTokenService = new Mock <ICandidateAccessTokenService>();
     _mockCrm          = new Mock <ICrmService>();
     _mockStore        = new Mock <IStore>();
     _mockJobClient    = new Mock <IBackgroundJobClient>();
     _mockLogger       = new Mock <ILogger <TeachingEventsController> >();
     _metrics          = new MetricService();
     _controller       = new TeachingEventsController(_mockStore.Object, _mockJobClient.Object,
                                                      _mockTokenService.Object, _mockCrm.Object, _mockLogger.Object, _metrics);
 }
Beispiel #19
0
        public void CreateAccessToken_InvalidRequest_RespondsWithValidationErrors()
        {
            var request = new ExistingCandidateRequest {
                Email = "invalid-email@"
            };

            _controller.ModelState.AddModelError("Email", "Email is invalid.");

            var response = _controller.CreateAccessToken(request);

            var badRequest = response.Should().BeOfType <BadRequestObjectResult>().Subject;
            var errors     = badRequest.Value.Should().BeOfType <SerializableError>().Subject;

            errors.Should().ContainKey("Email").WhichValue.Should().BeOfType <string[]>().Which.Should().Contain("Email is invalid.");
        }
        public void IsValid_WithInvalidToken_ReturnsFalse(string invalidToken)
        {
            var verifiedTotpsCount = _metrics.VerifiedTotps.WithLabels(new[] { false.ToString() }).Value;

            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };

            _service.IsValid(invalidToken, request, _candidateId).Should().BeFalse();

            if (!string.IsNullOrWhiteSpace(invalidToken))
            {
                _metrics.VerifiedTotps.WithLabels(new[] { false.ToString() }).Value.Should().Be(verifiedTotpsCount + 1);
            }
        }
Beispiel #21
0
        public void CreateAccessToken_MismatchedCandidate_ReturnsNotFound()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };

            _mockCrm.Setup(mock => mock.MatchCandidate(request)).Returns <Candidate>(null);

            var response = _controller.CreateAccessToken(request);

            response.Should().BeOfType <NotFoundResult>();

            _mockNotifyService.Verify(mock =>
                                      mock.SendEmailAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Dictionary <string, dynamic> >()),
                                      Times.Never()
                                      );
        }
Beispiel #22
0
        public void CreateAccessToken_CrmIntegrationIsPaused_ReturnsNotFound()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };

            _mockAppSettings.Setup(m => m.IsCrmIntegrationPaused).Returns(true);

            var response = _controller.CreateAccessToken(request);

            response.Should().BeOfType <NotFoundResult>();

            _mockNotifyService.Verify(mock =>
                                      mock.SendEmailAsync(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <Dictionary <string, dynamic> >()),
                                      Times.Never()
                                      );
        }
        public bool IsValid(string token, ExistingCandidateRequest request, Guid candidateId, DateTime timestamp)
        {
            if (string.IsNullOrWhiteSpace(token))
            {
                return(false);
            }

            var totp = CreateTotp(request);

            var valid = totp.VerifyTotp(
                timestamp,
                token,
                out _,
                new VerificationWindow(previous: VerificationWindow, future: 0));

            _metrics.VerifiedTotps.WithLabels(valid.ToString()).Inc();

            return(valid);
        }
Beispiel #24
0
        public void CreateAccessToken_ValidRequest_SendsPINCodeEmail()
        {
            var request = new ExistingCandidateRequest {
                Email = "*****@*****.**", FirstName = "John", LastName = "Doe"
            };
            var candidate = new Candidate {
                Id = Guid.NewGuid(), Email = request.Email, FirstName = request.FirstName, LastName = request.LastName
            };

            _mockAccessTokenService.Setup(mock => mock.GenerateToken(request, (Guid)candidate.Id)).Returns("123456");
            _mockCrm.Setup(mock => mock.MatchCandidate(request)).Returns(candidate);

            var response = _controller.CreateAccessToken(request);

            response.Should().BeOfType <NoContentResult>();
            _mockNotifyService.Verify(
                mock => mock.SendEmailAsync(
                    "*****@*****.**",
                    NotifyService.NewPinCodeEmailTemplateId,
                    It.Is <Dictionary <string, dynamic> >(personalisation => personalisation["pin_code"] as string == "123456")
                    )
                );
        }
Beispiel #25
0
        public void MatchCandidate_WithMasterChildRecords_ReturnsMasterRecord()
        {
            var request = new ExistingCandidateRequest
            {
                Email       = "*****@*****.**",
                LastName    = "Record",
                DateOfBirth = new DateTime(2000, 1, 1)
            };

            _mockService.Setup(mock => mock.CreateQuery("contact", _context)).Returns(MockCandidates());
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("dfe_contact_dfe_candidatequalification_ContactId"), _context));
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("dfe_contact_dfe_candidatepastteachingposition_ContactId"), _context));
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("dfe_contact_dfe_servicesubscription_contact"), _context));
            _mockService.Setup(mock => mock.LoadProperty(It.IsAny <Entity>(),
                                                         new Relationship("msevtmgt_contact_msevtmgt_eventregistration_Contact"), _context));

            var result = _crm.MatchCandidate(request);

            result?.FirstName.Should().Be("Master");
        }
        public Candidate MatchCandidate(ExistingCandidateRequest request)
        {
            var context = Context();
            var entity  = _service.CreateQuery("contact", context)
                          .Where(e =>
                                 e.GetAttributeValue <int>("statecode") == (int)Candidate.Status.Active &&

                                 // Will perform a case-insensitive comparison.
                                 // Contains is used to ensure we match emails with white space (request.Match does an exact match in-memory).
                                 e.GetAttributeValue <string>("emailaddress1").Contains(request.Email))
                          .OrderByDescending(e => e.GetAttributeValue <double>("dfe_duplicatescorecalculated"))
                          .ThenByDescending(e => e.GetAttributeValue <DateTime>("modifiedon"))
                          .Take(MaximumNumberOfCandidatesToMatch)
                          .FirstOrDefault(request.Match);

            if (entity == null)
            {
                return(null);
            }

            LoadCandidateRelationships(entity, context);

            return(new Candidate(entity, this, _validatorFactory));
        }
 private Totp CreateTotp(ExistingCandidateRequest request)
 {
     return(new Totp(CompoundSharedSecretBytes(request.Slugify()), totpSize: Length, step: StepInSeconds));
 }
Beispiel #28
0
        /// <summary>
        /// Retrieves an existing candidate for the Teacher Training Adviser service.   Retrieves an existing candidate for the Teacher Training Adviser service. The &#x60;accessToken&#x60; is obtained from a   &#x60;POST /candidates/access_tokens&#x60; request (you must also ensure the &#x60;ExistingCandidateRequest&#x60; payload you   exchanged for your token matches the request payload here).
        /// </summary>
        /// <exception cref="GetIntoTeachingApi.Client.Client.ApiException">Thrown when fails to make API call</exception>
        /// <param name="accessToken">Access token (PIN code).</param>
        /// <param name="body">Candidate access token request (must match an existing candidate).</param>
        /// <returns>Task of ApiResponse (Candidate)</returns>
        public async System.Threading.Tasks.Task <ApiResponse <Candidate> > GetExistingTeacherTrainingAdviserCandidateAsyncWithHttpInfo(string accessToken, ExistingCandidateRequest body)
        {
            // verify the required parameter 'accessToken' is set
            if (accessToken == null)
            {
                throw new ApiException(400, "Missing required parameter 'accessToken' when calling TeacherTrainingAdviserApi->GetExistingTeacherTrainingAdviserCandidate");
            }
            // verify the required parameter 'body' is set
            if (body == null)
            {
                throw new ApiException(400, "Missing required parameter 'body' when calling TeacherTrainingAdviserApi->GetExistingTeacherTrainingAdviserCandidate");
            }

            var    localVarPath         = "/api/teacher_training_adviser/candidates/{accessToken}";
            var    localVarPathParams   = new Dictionary <String, String>();
            var    localVarQueryParams  = new List <KeyValuePair <String, String> >();
            var    localVarHeaderParams = new Dictionary <String, String>(this.Configuration.DefaultHeader);
            var    localVarFormParams   = new Dictionary <String, String>();
            var    localVarFileParams   = new Dictionary <String, FileParameter>();
            Object localVarPostBody     = null;

            // to determine the Content-Type header
            String[] localVarHttpContentTypes = new String[] {
                "application/json",
                "text/json",
                "application/_*+json"
            };
            String localVarHttpContentType = this.Configuration.ApiClient.SelectHeaderContentType(localVarHttpContentTypes);

            // to determine the Accept header
            String[] localVarHttpHeaderAccepts = new String[] {
                "text/plain",
                "application/json",
                "text/json"
            };
            String localVarHttpHeaderAccept = this.Configuration.ApiClient.SelectHeaderAccept(localVarHttpHeaderAccepts);

            if (localVarHttpHeaderAccept != null)
            {
                localVarHeaderParams.Add("Accept", localVarHttpHeaderAccept);
            }

            if (accessToken != null)
            {
                localVarPathParams.Add("accessToken", this.Configuration.ApiClient.ParameterToString(accessToken));                      // path parameter
            }
            if (body != null && body.GetType() != typeof(byte[]))
            {
                localVarPostBody = this.Configuration.ApiClient.Serialize(body); // http body (model) parameter
            }
            else
            {
                localVarPostBody = body; // byte array
            }

            // authentication (apiKey) required
            if (!String.IsNullOrEmpty(this.Configuration.GetApiKeyWithPrefix("Authorization")))
            {
                localVarHeaderParams["Authorization"] = this.Configuration.GetApiKeyWithPrefix("Authorization");
            }

            // make the HTTP request
            IRestResponse localVarResponse = (IRestResponse)await this.Configuration.ApiClient.CallApiAsync(localVarPath,
                                                                                                            Method.POST, localVarQueryParams, localVarPostBody, localVarHeaderParams, localVarFormParams, localVarFileParams,
                                                                                                            localVarPathParams, localVarHttpContentType);

            int localVarStatusCode = (int)localVarResponse.StatusCode;

            if (ExceptionFactory != null)
            {
                Exception exception = ExceptionFactory("GetExistingTeacherTrainingAdviserCandidate", localVarResponse);
                if (exception != null)
                {
                    throw exception;
                }
            }

            return(new ApiResponse <Candidate>(localVarStatusCode,
                                               localVarResponse.Headers.ToDictionary(x => x.Name, x => x.Value.ToString()),
                                               (Candidate)this.Configuration.ApiClient.Deserialize(localVarResponse, typeof(Candidate))));
        }
Beispiel #29
0
        /// <summary>
        /// Retrieves an existing candidate for the Teacher Training Adviser service.   Retrieves an existing candidate for the Teacher Training Adviser service. The &#x60;accessToken&#x60; is obtained from a   &#x60;POST /candidates/access_tokens&#x60; request (you must also ensure the &#x60;ExistingCandidateRequest&#x60; payload you   exchanged for your token matches the request payload here).
        /// </summary>
        /// <exception cref="GetIntoTeachingApi.Client.Client.ApiException">Thrown when fails to make API call</exception>
        /// <param name="accessToken">Access token (PIN code).</param>
        /// <param name="body">Candidate access token request (must match an existing candidate).</param>
        /// <returns>Task of Candidate</returns>
        public async System.Threading.Tasks.Task <Candidate> GetExistingTeacherTrainingAdviserCandidateAsync(string accessToken, ExistingCandidateRequest body)
        {
            ApiResponse <Candidate> localVarResponse = await GetExistingTeacherTrainingAdviserCandidateAsyncWithHttpInfo(accessToken, body);

            return(localVarResponse.Data);
        }
Beispiel #30
0
        /// <summary>
        /// Retrieves an existing candidate for the Teacher Training Adviser service.   Retrieves an existing candidate for the Teacher Training Adviser service. The &#x60;accessToken&#x60; is obtained from a   &#x60;POST /candidates/access_tokens&#x60; request (you must also ensure the &#x60;ExistingCandidateRequest&#x60; payload you   exchanged for your token matches the request payload here).
        /// </summary>
        /// <exception cref="GetIntoTeachingApi.Client.Client.ApiException">Thrown when fails to make API call</exception>
        /// <param name="accessToken">Access token (PIN code).</param>
        /// <param name="body">Candidate access token request (must match an existing candidate).</param>
        /// <returns>Candidate</returns>
        public Candidate GetExistingTeacherTrainingAdviserCandidate(string accessToken, ExistingCandidateRequest body)
        {
            ApiResponse <Candidate> localVarResponse = GetExistingTeacherTrainingAdviserCandidateWithHttpInfo(accessToken, body);

            return(localVarResponse.Data);
        }