Skip to content

Commit

Permalink
Merge pull request #1025 from DFE-Digital/feature/158735-Associate-FAM
Browse files Browse the repository at this point in the history
Feature/158735 associate fam
  • Loading branch information
paullocknimble authored Apr 2, 2024
2 parents a56bfcd + 1f0c4f8 commit 56ceddf
Show file tree
Hide file tree
Showing 17 changed files with 483 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,24 @@ public void GivenDeliveryOfficers_GetsNoProjects_WhenDeliveryOfficerHasNoneAssig
[AutoMoqData]
public async Task GivenAValidProject_PostToApi([Frozen] Mock<IHttpClientService> httpService, AcademyConversionProjectRepository subject)
{
httpService.Setup(m => m.Post<CreateNewProject, string>(
httpService.Setup(m => m.Post<CreateNewProject, AcademyConversionProject>(
It.IsAny<HttpClient>(), @"legacy/project/new-conversion-project", It.IsAny<CreateNewProject>()))
.ReturnsAsync(new ApiResponse<string>(HttpStatusCode.OK, string.Empty));
.ReturnsAsync(new ApiResponse<AcademyConversionProject>(HttpStatusCode.OK, It.IsAny<AcademyConversionProject>()));

CreateNewProject project = new(null, null, null, null, false);
await subject.CreateProject(project);

httpService.Verify(m => m.Post<CreateNewProject, string>(
httpService.Verify(m => m.Post<CreateNewProject, AcademyConversionProject>(
It.IsAny<HttpClient>(), @"legacy/project/new-conversion-project", project), Times.Once);
}

[Theory]
[AutoMoqData]
public async Task GivenAFailedResponse_ThrowAnException([Frozen] Mock<IHttpClientService> httpService, AcademyConversionProjectRepository subject)
{
httpService.Setup(m => m.Post<CreateNewProject, string>(
httpService.Setup(m => m.Post<CreateNewProject, AcademyConversionProject>(
It.IsAny<HttpClient>(), @"legacy/project/new-conversion-project", It.IsAny<CreateNewProject>()))
.ReturnsAsync(new ApiResponse<string>(HttpStatusCode.InternalServerError, string.Empty));
.ReturnsAsync(new ApiResponse<AcademyConversionProject>(HttpStatusCode.InternalServerError, null));

CreateNewProject project = new(null, null, null, null, false);
ApiResponseException exception = await Assert.ThrowsAsync<ApiResponseException>(() => subject.CreateProject(project));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;

namespace Dfe.PrepareConversions.Data.Extensions
{
public static class DictionaryQuerystringExtensions
{
/// <summary>
/// Converts a <see cref="IDictionary{string, string}" /> to an encoded querystring.
/// </summary>
/// <param name="parameters">
/// An <see cref="IDictionary{string, string}" /> containing parameter names (of
/// <see cref="string" />) and values (of <see cref="string" />)
/// </param>
/// <param name="prefix">A <see cref="bool" /> defining whether the querystring should have a '?' prefix (default: true)</param>
/// <param name="keepEmpty">
/// A <see cref="bool" /> defining whether keys with null/empty values should be kept (default:
/// true)
/// </param>
/// <returns>A string representing the parameters combined, UrlEncoded and (optionally) prefixed ready to be used in a URI</returns>
public static string ToQueryString(this IDictionary<string, string> parameters, bool prefix = true,
bool keepEmpty = true)
{
IList<string> parameterPairs = parameters
.Where(x => keepEmpty || string.IsNullOrWhiteSpace(x.Value) is false)
.Select(x => $"{Encode(x.Key)}={Encode(x.Value)}")
.ToList();

var prefixContent = prefix ? "?" : string.Empty;

return parameterPairs.Count > 0
? $"{prefixContent}{string.Join("&", parameterPairs)}"
: string.Empty;

string Encode(string x)
{
return string.IsNullOrWhiteSpace(x) ? string.Empty : UrlEncoder.Default.Encode(x);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Dfe.PrepareConversions.Data.Models;
using Dfe.PrepareConversions.Data.Extensions;
using Dfe.PrepareConversions.Data.Models;
using Dfe.PrepareConversions.Data.Services;
using Microsoft.FeatureManagement;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
Expand Down Expand Up @@ -143,4 +145,18 @@ public async Task<HttpResponseMessage> GetFormAMatProjectsAsync(AcademyConversio
return await AcademisationClient.PostAsync(PathFor.GetFormAMatProjects, JsonContent.Create(searchModel));
}

public async Task<HttpResponseMessage> SearchFormAMatProjects(string searchTerm)
{
var queryParameters = new Dictionary<string, string>
{
{ "searchTerm", searchTerm },
};

return await ActiveApplicationClient.GetAsync($"{PathFor.SearchFormAMatProjects}{queryParameters.ToQueryString()}");
}

public async Task<HttpResponseMessage> SetFormAMatProjectReference(int id, SetFormAMatProjectReference setFormAMatProjectReference)
{
return await AcademisationClient.PutAsync(string.Format(PathFor.SetFormAMatProjectReference, id), JsonContent.Create(setFormAMatProjectReference));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,6 @@ public interface IApiClient
Task<HttpResponseMessage> SetPerformanceData(int id, SetPerformanceDataModel setPerformanceDataModel);
Task<HttpResponseMessage> SetIncomingTrust(int id, SetIncomingTrustDataModel setIncomingTrustDataModel);
Task<HttpResponseMessage> GetFormAMatProjectsAsync(AcademyConversionSearchModelV2 searchModel);
Task<HttpResponseMessage> SearchFormAMatProjects(string searchTerm);
Task<HttpResponseMessage> SetFormAMatProjectReference(int id, SetFormAMatProjectReference setFormAMatProjectReference);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,7 @@ public PathFor(IFeatureManager features)

public static string GetAllProjectsV2 => "/conversion-project/projects";
public static string GetFormAMatProjects => "/conversion-project/FormAMatProjects";
public static string SearchFormAMatProjects => "/conversion-project/search-formamatprojects";
public static string SetFormAMatProjectReference => "/conversion-project/{0}/SetFormAMatProjectReference";

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Dfe.PrepareConversions.Data.Models
{
public class SetFormAMatProjectReference
{
public int ProjectId { get; set; }
public int FormAMatProjectId { get; set; }


public SetFormAMatProjectReference() { }

public SetFormAMatProjectReference(
int projectId,
int formAMatProjectId)
{
ProjectId = projectId;
FormAMatProjectId = formAMatProjectId;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,22 @@ public async Task<ApiResponse<AcademyConversionProject>> UpdateProject(int id, U
return new ApiResponse<AcademyConversionProject>(updateResponse.StatusCode, project);
}

public async Task CreateProject(CreateNewProject newProject)
public async Task<ApiResponse<AcademyConversionProject>> CreateProject(CreateNewProject newProject)
{
HttpClient httpClient = _httpClientFactory.CreateAcademisationClient();

ApiResponse<string> result = await _httpClientService.Post<CreateNewProject, string>(
ApiResponse<AcademyConversionProject> result = await _httpClientService.Post<CreateNewProject, AcademyConversionProject>(
httpClient,
@"legacy/project/new-conversion-project",
newProject);

if (result.Success is false) throw new ApiResponseException($"Request to Api failed | StatusCode - {result.StatusCode}");
if (result.Success is false)
{
throw new ApiResponseException($"Request to Api failed | StatusCode - {result.StatusCode}");
}

return new ApiResponse<AcademyConversionProject>(result.StatusCode, result.Body);

}
public async Task CreateFormAMatProject(CreateNewFormAMatProject newProject)
{
Expand Down Expand Up @@ -323,4 +329,23 @@ public async Task SetIncomingTrust(int id, SetIncomingTrustDataModel setIncoming
HttpResponseMessage result = await _apiClient.SetIncomingTrust(id, setIncomingTrustDataModel);
if (result.IsSuccessStatusCode is false) throw new ApiResponseException($"Request to Api failed | StatusCode - {result.StatusCode}");
}

public async Task<ApiResponse<IEnumerable<FormAMatProject>>> SearchFormAMatProjects(string searchTerm)
{
HttpResponseMessage response = await _apiClient.SearchFormAMatProjects(searchTerm);
if (!response.IsSuccessStatusCode)
{
return new ApiResponse<IEnumerable<FormAMatProject>>(response.StatusCode, Enumerable.Empty<FormAMatProject>());
}

IEnumerable<FormAMatProject> outerResponse = await response.Content.ReadFromJsonAsync<IEnumerable<FormAMatProject>>();

return new ApiResponse<IEnumerable<FormAMatProject>>(response.StatusCode, outerResponse);
}

public async Task SetFormAMatProjectReference(int id, SetFormAMatProjectReference setFormAMatProjectReference)
{
HttpResponseMessage result = await _apiClient.SetFormAMatProjectReference(id, setFormAMatProjectReference);
if (result.IsSuccessStatusCode is false) throw new ApiResponseException($"Request to Api failed | StatusCode - {result.StatusCode}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Task<ApiResponse<ApiV2Wrapper<IEnumerable<FormAMatProject>>>> GetFormAMatProject
Task<ApiResponse<AcademyConversionProject>> GetProjectById(int id);
Task<ApiResponse<FormAMatProject>> GetFormAMatProjectById(int id);
Task<ApiResponse<AcademyConversionProject>> UpdateProject(int id, UpdateAcademyConversionProject updateProject);
Task CreateProject(CreateNewProject newProject);
Task<ApiResponse<AcademyConversionProject>> CreateProject(CreateNewProject newProject);
Task CreateFormAMatProject(CreateNewFormAMatProject newProject);
Task SetProjectExternalApplicationForm(int id, bool externalApplicationFormSaved, string externalApplicationFormUrl);
Task SetAssignedUser(int id, SetAssignedUserModel updatedAssignedUser);
Expand All @@ -63,4 +63,6 @@ Task<ApiResponse<ApiV2Wrapper<IEnumerable<FormAMatProject>>>> GetFormAMatProject
Task SetIncomingTrust(int id, SetIncomingTrustDataModel setIncomingTrustDataModel);
Task<ApiResponse<ProjectFilterParameters>> GetFilterParameters();
Task<ApiResponse<ProjectNote>> AddProjectNote(int id, AddProjectNote addProjectNote);
Task<ApiResponse<IEnumerable<FormAMatProject>>> SearchFormAMatProjects(string searchTerm);
Task SetFormAMatProjectReference(int id, SetFormAMatProjectReference setFormAMatProjectReference);
}
2 changes: 2 additions & 0 deletions Dfe.PrepareConversions/Dfe.PrepareConversions/Models/Links.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ public static class NewProject
public static readonly LinkItem SearchTrusts = AddLinkItem(page: "/NewProject/SearchTrust");
public static readonly LinkItem PreferredTrust = AddLinkItem(page: "/NewProject/PreferredTrust");
public static readonly LinkItem IsThisFormAMat = AddLinkItem(page: "/NewProject/IsThisFormAMat");
public static readonly LinkItem IsProjectAlreadyInPrepare = AddLinkItem(page: "/NewProject/IsProjectAlreadyInPreprare");
public static readonly LinkItem LinkFormAMatProject = AddLinkItem(page: "/NewProject/LinkFormAMatProject");
public static readonly LinkItem CreateNewFormAMat = AddLinkItem(page: "/NewProject/CreateNewFormAMat");
public static readonly LinkItem Summary = AddLinkItem(page: "/NewProject/Summary");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@page "/start-new-project/is-project-already-in-prepare"
@using Dfe.PrepareConversions.Pages.Shared
@model Dfe.PrepareConversions.Pages.SponsoredProject.IsProjectAlreadyInPreprareModel

@{
Layout = "_Layout";
ViewBag.Title = (!ViewData.ModelState.IsValid ? "Error: " : "") + "Is the form a MAT/SAT project already in Prepare?";
var routeParams = new Dictionary<string, string>
{
{ "urn", Request.Query["urn"] },
{ "ukprn", Request.Query["ukprn"] },
{ "hasSchoolApplied", Request.Query["hasSchoolApplied"] },
{ "isFormAMat" , Request.Query["isFormAMat"]},
{ "isProjectInPrepare" , Request.Query["isProjectInPrepare"]},
};
}

@section BeforeMain
{
<partial name="_BackLink" model="@(new BackLink(Links.NewProject.SchoolApply.Page, routeParams))" />
<partial name="_ErrorSummary" />
}



<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds">
<form method="post">

<input hidden="" type="text" name="returnToSummary" value="no">
<input type="hidden" asp-for="Urn" />
<input type="hidden" asp-for="HasSchoolApplied" />
<h1 class="govuk-heading-l" data-cy="select-heading">Is the form a MAT/SAT project already in Prepare?</h1>

<div class="govuk-form-group" @ModelState.GetErrorStyleClass()>
<div class="govuk-radios">
<div class="govuk-radios__item">
<input asp-for="IsProjectInPrepare" class="govuk-radios__input" type="radio" value="Yes" id="DoneYes" data-cy="select-legal-input-yes">
<label class="govuk-label govuk-radios__label" for="DoneYes">
Yes
</label>
</div>

<div class="govuk-radios__item">
<input asp-for="IsProjectInPrepare" class="govuk-radios__input" type="radio" value="No" id="DoneNo" data-cy="select-legal-input-no">
<label class="govuk-label govuk-radios__label" for="DoneNo">
No
</label>
</div>
</div>
</div>

<button class="govuk-button pt-3" data-module="govuk-button" data-cy="select-common-submitbutton">
Continue
</button>
</form>

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Dfe.PrepareConversions.Data.Services;
using Dfe.PrepareConversions.Models;
using Dfe.PrepareConversions.Models.ProjectList;
using Dfe.PrepareConversions.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.IdentityModel.Tokens;
using System.Threading.Tasks;
using EstablishmentDto = Dfe.Academies.Contracts.V4.Establishments.EstablishmentDto;

namespace Dfe.PrepareConversions.Pages.SponsoredProject;

public class IsProjectAlreadyInPreprareModel : PageModel
{
private readonly ErrorService _errorService;
private readonly IGetEstablishment _getEstablishment;

public IsProjectAlreadyInPreprareModel(IGetEstablishment getEstablishment, ErrorService errorService)
{
_getEstablishment = getEstablishment;
_errorService = errorService;
}
[BindProperty]
public string IsFormAMat { get; set; }
[BindProperty]
public string HasSchoolApplied { get; set; }

[BindProperty]
public string IsProjectInPrepare { get; set; }

public string Urn { get; set; }

public async Task<IActionResult> OnGet(string urn, string isFormAMat, string hasSchoolApplied, string isProjectInPrepare)
{
ProjectListFilters.ClearFiltersFrom(TempData);
HasSchoolApplied = hasSchoolApplied;
IsFormAMat = isFormAMat;
IsProjectInPrepare = isProjectInPrepare ?? "yes"; // Default to Yes if not used backlink to access

EstablishmentDto establishment = await _getEstablishment.GetEstablishmentByUrn(urn);
Urn = establishment.Urn;

return Page();
}

public async Task<IActionResult> OnPost(string ukprn, string urn, string redirect)
{

if (IsProjectInPrepare.IsNullOrEmpty())
{
_errorService.AddError("Does project exists", "Select yes if the project already exists in Prepare");
return Page();
}
string nextPage = null;
if (IsProjectInPrepare.ToLower() == "yes")
{
nextPage = Links.NewProject.LinkFormAMatProject.Page;
}
else
{
nextPage = Links.NewProject.CreateNewFormAMat.Page;
}


redirect = string.IsNullOrEmpty(redirect) ? nextPage : redirect;

return RedirectToPage(redirect, new { ukprn, urn, HasSchoolApplied, IsFormAMat, IsProjectInPrepare });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public async Task<IActionResult> OnPost(string ukprn, string urn, string redirec
string nextPage = null;
if (IsFormAMat.ToLower() == "yes")
{
nextPage = Links.NewProject.CreateNewFormAMat.Page;
nextPage = Links.NewProject.IsProjectAlreadyInPrepare.Page;
}
else
{
Expand Down
Loading

0 comments on commit 56ceddf

Please sign in to comment.