Skip to content

Commit

Permalink
Merge branch 'main' into feature/objectives
Browse files Browse the repository at this point in the history
  • Loading branch information
samgibsonmoj committed Aug 20, 2024
2 parents ae7822a + faf3863 commit 93cb96c
Show file tree
Hide file tree
Showing 16 changed files with 105 additions and 35 deletions.
23 changes: 21 additions & 2 deletions src/Application/Features/Assessments/Commands/BeginAssessment.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Text.Json.Serialization;
using Cfo.Cats.Application.Common.Security;
using Cfo.Cats.Application.Common.Validators;
using Cfo.Cats.Application.Features.Assessments.Caching;
using Cfo.Cats.Application.Features.Assessments.DTOs;
using Cfo.Cats.Application.Features.Assessments.DTOs.V1.Pathways.Education;
Expand Down Expand Up @@ -78,12 +79,30 @@ public async Task<Result<Guid>> Handle(Command request, CancellationToken cancel

public class Validator : AbstractValidator<Command>
{
public Validator()
private readonly IUnitOfWork _unitOfWork;

public Validator(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;

RuleFor(c => c.ParticipantId)
.MinimumLength(9)
.MaximumLength(9);
.MaximumLength(9)
.Matches(ValidationConstants.AlphaNumeric)
.WithMessage(string.Format(ValidationConstants.AlphaNumericMessage, "Participant Id"));

RuleFor(c => c.ParticipantId)
.MustAsync(Exist)
.WithMessage("Participant not found")
.MustAsync(HaveEnrolmentLocation)
.WithMessage("Participant must have an enrolment location");
}

private async Task<bool> Exist(string participantId, CancellationToken cancellationToken)
=> await _unitOfWork.DbContext.Participants.AnyAsync(e => e.Id == participantId, cancellationToken);

private async Task<bool> HaveEnrolmentLocation(string participantId, CancellationToken cancellationToken)
=> await _unitOfWork.DbContext.Participants.AnyAsync(e => e.Id == participantId && e.EnrolmentLocation != null, cancellationToken);
}

}
30 changes: 30 additions & 0 deletions src/Application/Features/Assessments/Commands/SaveAssessment.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Cfo.Cats.Application.Common.Security;
using Cfo.Cats.Application.Common.Validators;
using Cfo.Cats.Application.Features.Assessments.Caching;
using Cfo.Cats.Application.Features.Assessments.DTOs;
using Cfo.Cats.Application.SecurityConstants;
Expand Down Expand Up @@ -75,4 +76,33 @@ public async Task<Result> Handle(Command request, CancellationToken cancellation
}
}

public class Validator : AbstractValidator<Command>
{
private readonly IUnitOfWork _unitOfWork;

public Validator(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;

RuleFor(c => c.Assessment.Id)
.MustAsync(Exist)
.WithMessage("Assessment not found");

RuleFor(c => c.Assessment.ParticipantId)
.MustAsync(Exist)
.WithMessage("Participant not found")
.MustAsync(HaveEnrolmentLocation)
.WithMessage("Participant must have an enrolment location");
}

private async Task<bool> Exist(Guid assessmentId, CancellationToken cancellationToken)
=> await _unitOfWork.DbContext.ParticipantAssessments.AnyAsync(e => e.Id == assessmentId, cancellationToken);

private async Task<bool> Exist(string participantId, CancellationToken cancellationToken)
=> await _unitOfWork.DbContext.Participants.AnyAsync(e => e.Id == participantId, cancellationToken);

private async Task<bool> HaveEnrolmentLocation(string participantId, CancellationToken cancellationToken)
=> await _unitOfWork.DbContext.Participants.AnyAsync(e => e.Id == participantId && e.EnrolmentLocation != null, cancellationToken);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ public CandidateSearchQueryValidator()

RuleFor(q => q.ExternalIdentifier)
.NotEmpty()
.NotNull()
.WithMessage("External identifier is required")
.Matches(ValidationConstants.AlphaNumeric)
.WithMessage(string.Format(ValidationConstants.AlphaNumericMessage, "External Identifier"));
.WithMessage(string.Format(ValidationConstants.AlphaNumericMessage, "External Identifier"))
.Length(7) // CRN and NOMIS Number (both 7 chars)
.WithMessage("Unrecognised format for External Identifier");

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ public Mapping()
.ForMember(x => x.SuperiorName, s => s.MapFrom(y => y.Superior!.UserName))
.ForMember(x => x.TenantName, s => s.MapFrom(y => y.Tenant!.Name))
.ForMember(x => x.AssignedRoles, s => s.MapFrom(y => y.UserRoles.Select(r => r.Role.Name)))
.ForMember(x => x.PhoneNumber, s => s.MapFrom(x => x.PhoneNumber))
.ReverseMap()
.ForMember(x => x.UserName, s => s.MapFrom(y => y.Email))
.ForMember(x => x.Notes, s => s.Ignore())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,14 @@ public A_IsValidRequest()
.NotNull()
.WithMessage("You must accept or return the request");

When(x => x.Accept == false, () => {
When(x => x.Accept is false, () =>
{
RuleFor(x => x.Message)
.NotNull()
.WithMessage("A message is required when returning")
.NotEmpty()
.WithMessage("A message is required when returning")
.Matches(ValidationConstants.Notes)
.WithMessage(string.Format(ValidationConstants.NotesMessage, "Message"));
});

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ public A_IsValidRequest()
.NotNull()
.WithMessage("You must accept or return the request");

When(x => x.Accept == false, () => {
When(x => x.Accept is false, () => {
RuleFor(x => x.Message)
.NotNull()
.WithMessage("A message is required when returning")
.NotEmpty()
.WithMessage("A message is required when returning")
.Matches(ValidationConstants.Notes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ public A_IsValidRequest()
.NotNull()
.WithMessage("You must accept or return the request");

When(x => x.Accept == false, () => {
When(x => x.Accept is false, () => {
RuleFor(x => x.Message)
.NotNull()
.WithMessage("A message is required when returning")
.NotEmpty()
.WithMessage("A message is required when returning")
.Matches(ValidationConstants.Notes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public static class SubmitToProviderQa
public class Command : IRequest<Result>
{
public required string ParticipantId { get; set; }

}

public class Handler(IUnitOfWork unitOfWork) : IRequestHandler<Command, Result>
Expand All @@ -36,9 +35,9 @@ public A_ParticipantMustExistValidator(IUnitOfWork unitOfWork)
.MinimumLength(9)
.MaximumLength(9)
.WithMessage("Invalid Participant Id")
.Matches(ValidationConstants.AlphaNumeric).WithMessage(string.Format(ValidationConstants.AlphaNumericMessage, "Participant Id"))
.MustAsync(MustExist)
.WithMessage("Participant does not exist")
.Matches(ValidationConstants.AlphaNumeric).WithMessage(string.Format(ValidationConstants.AlphaNumericMessage, "Participant Id"));
.WithMessage("Participant does not exist");
}
private async Task<bool> MustExist(string identifier, CancellationToken cancellationToken)
=> await _unitOfWork.DbContext.Participants.AnyAsync(e => e.Id == identifier, cancellationToken);
Expand Down Expand Up @@ -80,6 +79,7 @@ private async Task<bool> MustBeScored(string identifier, CancellationToken cance
{
var assessments = await _unitOfWork.DbContext.ParticipantAssessments
.Include(pa => pa.Scores)
.Where(pa => pa.ParticipantId == identifier)
.ToArrayAsync(cancellationToken);

var latest = assessments.MaxBy(a => a.Created);
Expand All @@ -106,13 +106,13 @@ private async Task<bool> MustHaveTwoReds(string identifier, CancellationToken ca
{
var assessments = await _unitOfWork.DbContext.ParticipantAssessments
.Include(pa => pa.Scores)
.Where(pa=>pa.ParticipantId == identifier)
.ToArrayAsync(cancellationToken);

var latest = assessments.MaxBy(a => a.Created);

return latest is not null
&& latest.Scores.Count(s => s.Score is > 0 and < 10) > 1;
&& latest.Scores.Count(s => s.Score is >= 0 and < 10) > 1;
}
}

}
7 changes: 5 additions & 2 deletions src/Server.UI/Pages/Candidates/Components/MatchFound.razor
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,14 @@

<MudContainer Class="d-flex px-0 mt-8 justify-space-between">
<MudButton Color="Color.Error" Variant="Variant.Filled" OnClick="BackToSearch">Back to Search</MudButton>
<MudButton Color="Color.Success" Variant="Variant.Filled"
<MudLoadingButton
Loading="loading"
Color="Color.Success"
Variant="Variant.Filled"
OnClick="EnrolCandidate"
Disabled="@(_confirmation == false)">
Enrol Candidate
</MudButton>
</MudLoadingButton>
</MudContainer>

</MudContainer>
Expand Down
23 changes: 18 additions & 5 deletions src/Server.UI/Pages/Candidates/Components/MatchFound.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public partial class MatchFound
[Inject]
private IPicklistService PicklistService { get; set; } = default!;

private bool loading;

private MudForm? _form;

private CreateParticipant.Command? Model;
Expand Down Expand Up @@ -65,14 +67,25 @@ private Task BackToSearch()

private async Task EnrolCandidate()
{
await _form!.Validate().ConfigureAwait(false);
if (_form!.IsValid)
try
{
var result = await GetNewMediator().Send(Model!);
if (result.Succeeded)
loading = true;

await _form!.Validate().ConfigureAwait(false);

if (_form!.IsValid)
{
await OnParticipantEnrolled.InvokeAsync();
var result = await GetNewMediator().Send(Model!);
if (result.Succeeded)
{
await OnParticipantEnrolled.InvokeAsync();
}
}

}
finally
{
loading = false;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Server.UI/Pages/Identity/Authentication/Login.razor
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
<div class="mud-input-control-input-container">
<!--!--><!--!-->
<div class="mud-input mud-input-outlined mud-shrink">
<InputText type="password" @bind-Value="Input.Password" class="mud-input-slot mud-input-root mud-input-root-outlined" autocomplete="current-password" aria-required="true" placeholder="password" />
<InputText type="password" @bind-Value="Input.Password" class="mud-input-slot mud-input-root mud-input-root-outlined" autocomplete="off" aria-required="true" placeholder="password" />
<div class="mud-input-slot mud-input-root mud-input-root-outlined" style="display:none"></div>
<!--!-->
<div class="mud-input-outlined-border"></div>
Expand Down
8 changes: 6 additions & 2 deletions src/Server.UI/Pages/Identity/Users/Users.razor
Original file line number Diff line number Diff line change
Expand Up @@ -389,8 +389,8 @@
policies ??= new()
{
{ SecurityPolicies.SystemFunctionsWrite, (await AuthService.AuthorizeAsync(state.User, SecurityPolicies.SystemFunctionsWrite)).Succeeded },
{ SecurityPolicies.Import, (await AuthService.AuthorizeAsync(state.User, SecurityPolicies.Import)).Succeeded },
{ SecurityPolicies.Export, (await AuthService.AuthorizeAsync(state.User, SecurityPolicies.Export)).Succeeded }
{ SecurityPolicies.Import, false /*(await AuthService.AuthorizeAsync(state.User, SecurityPolicies.Import)).Succeeded */ },
{ SecurityPolicies.Export, false /* (await AuthService.AuthorizeAsync(state.User, SecurityPolicies.Export)).Succeeded */ }
};

_canCreate = policies.GetValueOrDefault(SecurityPolicies.SystemFunctionsWrite);
Expand Down Expand Up @@ -533,6 +533,8 @@
var applicationUser = Mapper.Map<ApplicationUser>(model);
applicationUser.EmailConfirmed = true;
applicationUser.IsActive = true;
applicationUser.TwoFactorEnabled = true;
applicationUser.PhoneNumberConfirmed = string.IsNullOrWhiteSpace(applicationUser.PhoneNumber) == false;

var identityResult = await UserManager.CreateAsync(applicationUser);
if (!identityResult.Succeeded)
Expand All @@ -556,6 +558,8 @@

Mapper.Map(model, user);

user.PhoneNumberConfirmed = string.IsNullOrWhiteSpace(user.PhoneNumber) == false;

var identityResult = await UserManager.UpdateAsync(user);
if (identityResult.Succeeded)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ public async Task BeginAssessment()
{
ParticipantId = ParticipantSummaryDto.Id
};

var result = await GetNewMediator().Send(command);

if (result.Succeeded)
{
Navigation.NavigateTo($"/pages/participants/{ParticipantSummaryDto.Id}/assessment/{result.Data}");
}
else
{
Snackbar.Add(result.ErrorMessage, Severity.Error);
}
}

public void ContinueAssessment()
Expand Down
4 changes: 2 additions & 2 deletions src/Server.UI/Pages/QA/Enrolments/PQA.razor
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
{
<MudForm Model="@Command" @ref="_form" Validation="@(Validator.ValidateValue(Command))">
<MudItem xs="12">
<MudRadioGroup T="bool?" @bind-Value="Command.Accept" Required="true">
<MudRadioGroup T="bool?" @bind-Value="Command.Accept" For="@(() => Command.Accept)" Required="true">
<MudRadio T="bool?" Value="true" Color="Color.Primary">
Accept
</MudRadio>
Expand All @@ -97,7 +97,7 @@
</MudRadioGroup>
</MudItem>

<MudTextField T="string" Label="Message" For="(() => Command.Message)" />
<MudTextField @bind-Value="Command.Message" Label="Message" For="(() => Command.Message)" />
</MudForm>
<MudContainer Class="d-flex px-0 pt-8">
<MudButton Color="Color.Primary" OnClick="SubmitToQa" Variant="Variant.Filled">Submit</MudButton>
Expand Down
4 changes: 2 additions & 2 deletions src/Server.UI/Pages/QA/Enrolments/QA1.razor
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
{
<MudForm Model="@Command" @ref="_form" Validation="@(Validator.ValidateValue(Command))">
<MudItem xs="12">
<MudRadioGroup T="bool?" @bind-Value="Command.Accept" Required="true">
<MudRadioGroup T="bool?" @bind-Value="Command.Accept" For="@(() => Command.Accept)" Required="true">
<MudRadio T="bool?" Value="true" Color="Color.Primary">
Accept
</MudRadio>
Expand All @@ -97,7 +97,7 @@
</MudRadioGroup>
</MudItem>

<MudTextField T="string" Label="Message" For="(() => Command.Message)" />
<MudTextField @bind-Value="Command.Message" Label="Message" For="(() => Command.Message)" />
</MudForm>
<MudContainer Class="d-flex px-0 pt-8">
<MudButton Color="Color.Primary" OnClick="SubmitToQa" Variant="Variant.Filled">Submit</MudButton>
Expand Down
4 changes: 2 additions & 2 deletions src/Server.UI/Pages/QA/Enrolments/QA2.razor
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@
</MudRadio>
</MudRadioGroup>
</MudItem>
<MudTextField T="string" Label="Message" For="(() => Command.Message)" @bind-Value="Command.Message" Immediate="true" />

<MudTextField @bind-Value="Command.Message" Label="Message" For="(() => Command.Message)" />
</MudForm>
<MudContainer Class="d-flex px-0 pt-8">
<MudButton Color="Color.Primary" OnClick="SubmitToQa" Variant="Variant.Filled">Submit</MudButton>
Expand Down

0 comments on commit 93cb96c

Please sign in to comment.