Skip to content

Commit

Permalink
Expose ChannelId for MailingListAddMember request
Browse files Browse the repository at this point in the history
We want to be able to specify the channel from the front-end for on-campus
events (via a QR code and unique URL containing the channel id). This updates
the `MailingListAddMember` model to allow the `ChannelId` to be specified and
uses it for the candidate/mailing list/event subscription channels.

Add validation to the `Candidate` model to ensure the channel ids are valid
according to the CRM.
  • Loading branch information
ethax-ross committed Sep 11, 2020
1 parent 624566e commit e82269a
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 3 deletions.
26 changes: 26 additions & 0 deletions GetIntoTeachingApi/Controllers/TypesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,32 @@ public async Task<IActionResult> GetCandidateChannels()
return Ok(await _store.GetPickListItems("contact", "dfe_channelcreation").ToListAsync());
}

[HttpGet]
[CrmETag]
[Route("candidate/mailing_list_subscription_channels")]
[SwaggerOperation(
Summary = "Retrieves the list of candidate mailing list subscription channels.",
OperationId = "GetCandidateMailingListSubscriptionChannels",
Tags = new[] { "Types" })]
[ProducesResponseType(typeof(IEnumerable<TypeEntity>), 200)]
public async Task<IActionResult> GetCandidateMailingListSubscriptionChannels()
{
return Ok(await _store.GetPickListItems("contact", "dfe_gitismlservicesubscriptionchannel").ToListAsync());
}

[HttpGet]
[CrmETag]
[Route("candidate/event_subscription_channels")]
[SwaggerOperation(
Summary = "Retrieves the list of candidate event subscription channels.",
OperationId = "GetCandidateEventSubscriptionChannels",
Tags = new[] { "Types" })]
[ProducesResponseType(typeof(IEnumerable<TypeEntity>), 200)]
public async Task<IActionResult> GetCandidateEventSubscriptionChannels()
{
return Ok(await _store.GetPickListItems("contact", "dfe_gitiseventsservicesubscriptionchannel").ToListAsync());
}

[HttpGet]
[CrmETag]
[Route("candidate/gcse_status")]
Expand Down
8 changes: 5 additions & 3 deletions GetIntoTeachingApi/Models/MailingListAddMember.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class MailingListAddMember

public int? ConsiderationJourneyStageId { get; set; }
public int? DegreeStatusId { get; set; }
[SwaggerSchema(WriteOnly = true)]
public int? ChannelId { get; set; }

public string Email { get; set; }
public string FirstName { get; set; }
Expand Down Expand Up @@ -78,7 +80,7 @@ private Candidate CreateCandidate()
LastName = LastName,
AddressPostcode = AddressPostcode,
Telephone = Telephone,
ChannelId = CandidateId == null ? (int?)Candidate.Channel.MailingList : null,
ChannelId = CandidateId == null ? ChannelId ?? (int?)Candidate.Channel.MailingList : null,
OptOutOfSms = false,
DoNotBulkEmail = false,
DoNotEmail = false,
Expand Down Expand Up @@ -108,7 +110,7 @@ private void AddQualification(Candidate candidate)
private void ConfigureSubscriptions(Candidate candidate)
{
candidate.HasMailingListSubscription = true;
candidate.MailingListSubscriptionChannelId = (int)Candidate.SubscriptionChannel.MailingList;
candidate.MailingListSubscriptionChannelId = ChannelId ?? (int)Candidate.SubscriptionChannel.MailingList;
candidate.MailingListSubscriptionStartAt = DateTime.UtcNow;
candidate.MailingListSubscriptionDoNotEmail = false;
candidate.MailingListSubscriptionDoNotBulkEmail = false;
Expand All @@ -117,7 +119,7 @@ private void ConfigureSubscriptions(Candidate candidate)
candidate.MailingListSubscriptionDoNotSendMm = false;

candidate.HasEventsSubscription = true;
candidate.EventsSubscriptionChannelId = (int)Candidate.SubscriptionChannel.Events;
candidate.EventsSubscriptionChannelId = ChannelId ?? (int)Candidate.SubscriptionChannel.Events;
candidate.EventsSubscriptionStartAt = DateTime.UtcNow;
candidate.EventsSubscriptionDoNotEmail = false;
candidate.EventsSubscriptionDoNotBulkEmail = false;
Expand Down
18 changes: 18 additions & 0 deletions GetIntoTeachingApi/Models/Validators/CandidateValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ public CandidateValidator(IStore store)
.Must(id => AdviserRequirementIds().Contains(id.ToString()))
.Unless(candidate => candidate.AdviserRequirementId == null)
.WithMessage("Must be a valid candidate adviser requirement.");
RuleFor(candidate => candidate.EventsSubscriptionChannelId)
.Must(id => EventSubscriptionChannelIds().Contains(id.ToString()))
.Unless(candidate => candidate.EventsSubscriptionChannelId == null)
.WithMessage("Must be a valid event subscription channel.");
RuleFor(candidate => candidate.MailingListSubscriptionChannelId)
.Must(id => MailingListSubscriptionChannelIds().Contains(id.ToString()))
.Unless(candidate => candidate.MailingListSubscriptionChannelId == null)
.WithMessage("Must be a valid mailing list subscription channel.");
}

private IEnumerable<string> PreferredTeachingSubjectIds()
Expand Down Expand Up @@ -134,6 +142,16 @@ private IEnumerable<string> ChannelIds()
return _store.GetPickListItems("contact", "dfe_channelcreation").Select(channel => channel.Id);
}

private IEnumerable<string> MailingListSubscriptionChannelIds()
{
return _store.GetPickListItems("contact", "dfe_gitismlservicesubscriptionchannel").Select(channel => channel.Id);
}

private IEnumerable<string> EventSubscriptionChannelIds()
{
return _store.GetPickListItems("contact", "dfe_gitiseventsservicesubscriptionchannel").Select(channel => channel.Id);
}

private IEnumerable<string> GcseStatusIds()
{
return _store.GetPickListItems("contact", "dfe_websitehasgcseenglish").Select(status => status.Id);
Expand Down
2 changes: 2 additions & 0 deletions GetIntoTeachingApi/Services/Store.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ private async Task SyncTypeEntities(ICrmService crm)
await SyncTypes(crm.GetPickListItems("contact", "dfe_candidatestatus"));
await SyncTypes(crm.GetPickListItems("contact", "dfe_iscandidateeligibleforadviser"));
await SyncTypes(crm.GetPickListItems("contact", "dfe_isadvisorrequiredos"));
await SyncTypes(crm.GetPickListItems("contact", "dfe_gitismlservicesubscriptionchannel"));
await SyncTypes(crm.GetPickListItems("contact", "dfe_gitiseventsservicesubscriptionchannel"));
await SyncTypes(crm.GetPickListItems("dfe_candidatequalification", "dfe_degreestatus"));
await SyncTypes(crm.GetPickListItems("dfe_candidatequalification", "dfe_ukdegreegrade"));
await SyncTypes(crm.GetPickListItems("dfe_candidatequalification", "dfe_type"));
Expand Down
24 changes: 24 additions & 0 deletions GetIntoTeachingApiTests/Controllers/TypesControllerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,30 @@ public async void GetCandidateChannels_ReturnsAllChannels()
ok.Value.Should().BeEquivalentTo(mockEntities);
}

[Fact]
public async void GetCandidateMailingListSubscriptionChannels_ReturnsAllChannels()
{
var mockEntities = MockTypeEntities();
_mockStore.Setup(mock => mock.GetPickListItems("contact", "dfe_gitismlservicesubscriptionchannel")).Returns(mockEntities.AsAsyncQueryable());

var response = await _controller.GetCandidateMailingListSubscriptionChannels();

var ok = response.Should().BeOfType<OkObjectResult>().Subject;
ok.Value.Should().BeEquivalentTo(mockEntities);
}

[Fact]
public async void GetCandidateEventSubscriptionChannels_ReturnsAllChannels()
{
var mockEntities = MockTypeEntities();
_mockStore.Setup(mock => mock.GetPickListItems("contact", "dfe_gitiseventsservicesubscriptionchannel")).Returns(mockEntities.AsAsyncQueryable());

var response = await _controller.GetCandidateEventSubscriptionChannels();

var ok = response.Should().BeOfType<OkObjectResult>().Subject;
ok.Value.Should().BeEquivalentTo(mockEntities);
}

[Fact]
public async void GetCandidateGcseStatus_ReturnsAllStatus()
{
Expand Down
10 changes: 10 additions & 0 deletions GetIntoTeachingApiTests/Models/MailingListAddMemberTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,15 @@ public void Candidate_ChannelIdWhenCandidateIdIsNotNull_IsNull()

request.Candidate.ChannelId.Should().BeNull();
}

[Fact]
public void Candidate_WhenChannelIsProvided_SetsOnAllModels()
{
var request = new MailingListAddMember() { ChannelId = 123 };

request.Candidate.ChannelId.Should().Be(123);
request.Candidate.MailingListSubscriptionChannelId.Should().Be(123);
request.Candidate.EventsSubscriptionChannelId.Should().Be(123);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public void Validate_WhenValid_HasNoErrors()
_mockStore
.Setup(mock => mock.GetPickListItems("contact", "dfe_channelcreation"))
.Returns(new[] { mockPickListItem }.AsQueryable());
_mockStore
.Setup(mock => mock.GetPickListItems("contact", "dfe_gitismlservicesubscriptionchannel"))
.Returns(new[] { mockPickListItem }.AsQueryable());
_mockStore
.Setup(mock => mock.GetPickListItems("contact", "dfe_gitiseventsservicesubscriptionchannel"))
.Returns(new[] { mockPickListItem }.AsQueryable());
_mockStore
.Setup(mock => mock.GetPickListItems("contact", "dfe_websitehasgcseenglish"))
.Returns(new[] { mockPickListItem }.AsQueryable());
Expand Down Expand Up @@ -95,6 +101,8 @@ public void Validate_WhenValid_HasNoErrors()
PreferredEducationPhaseId = int.Parse(mockPickListItem.Id),
InitialTeacherTrainingYearId = int.Parse(mockPickListItem.Id),
ChannelId = int.Parse(mockPickListItem.Id),
MailingListSubscriptionChannelId = int.Parse(mockPickListItem.Id),
EventsSubscriptionChannelId = int.Parse(mockPickListItem.Id),
PrivacyPolicy = new CandidatePrivacyPolicy() { AcceptedPolicyId = (Guid)mockPrivacyPolicy.Id }
};

Expand Down Expand Up @@ -444,6 +452,18 @@ public void Validate_AssignmentStatusIdIsNull_HasNoError()
_validator.ShouldNotHaveValidationErrorFor(candidate => candidate.AssignmentStatusId, null as int?);
}

[Fact]
public void Validate_MailingListSubscriptionChannelIdIsInvalid_HasError()
{
_validator.ShouldHaveValidationErrorFor(candidate => candidate.MailingListSubscriptionChannelId, 123);
}

[Fact]
public void Validate_EventSubscriptionChannelIdIsInvalid_HasError()
{
_validator.ShouldHaveValidationErrorFor(candidate => candidate.EventsSubscriptionChannelId, 123);
}

[Fact]
public void Validate_ChannelIdIsInvalid_HasError()
{
Expand Down
2 changes: 2 additions & 0 deletions GetIntoTeachingApiTests/Services/StoreTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ public async void SyncAsync_SyncsAllTypeEntities()
mockCrm.Verify(m => m.GetPickListItems("contact", "dfe_candidatestatus"));
mockCrm.Verify(m => m.GetPickListItems("contact", "dfe_iscandidateeligibleforadviser"));
mockCrm.Verify(m => m.GetPickListItems("contact", "dfe_isadvisorrequiredos"));
mockCrm.Verify(m => m.GetPickListItems("contact", "dfe_gitismlservicesubscriptionchannel"));
mockCrm.Verify(m => m.GetPickListItems("contact", "dfe_gitiseventsservicesubscriptionchannel"));
mockCrm.Verify(m => m.GetPickListItems("dfe_candidatequalification", "dfe_degreestatus"));
mockCrm.Verify(m => m.GetPickListItems("dfe_candidatequalification", "dfe_ukdegreegrade"));
mockCrm.Verify(m => m.GetPickListItems("dfe_candidatequalification", "dfe_type"));
Expand Down

0 comments on commit e82269a

Please sign in to comment.