Skip to content

Commit

Permalink
Made changes to force code reuse and keep SonarQube happy
Browse files Browse the repository at this point in the history
  • Loading branch information
spencerohegartyDfE committed Jan 20, 2025
1 parent 8ab448e commit 2702912
Show file tree
Hide file tree
Showing 17 changed files with 239 additions and 260 deletions.
71 changes: 61 additions & 10 deletions GetIntoTeachingApi/Models/Crm/Candidate.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GetIntoTeachingApi.Attributes;
using GetIntoTeachingApi.Attributes;
using GetIntoTeachingApi.Services;
using GetIntoTeachingApi.Utils;
using Microsoft.Xrm.Sdk;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Collections.Generic;
using System.Linq;

namespace GetIntoTeachingApi.Models.Crm
{
Expand Down Expand Up @@ -298,16 +298,13 @@ public enum RegistrationStatus
[EntityRelationship("dfe_contact_dfe_candidateschoolexperience_ContactId", typeof(CandidateSchoolExperience))]
public List<CandidateSchoolExperience> SchoolExperiences { get; set; } = new List<CandidateSchoolExperience>();
[EntityRelationship("dfe_contact_dfe_contactchannelcreation_ContactId", typeof(ContactChannelCreation))]
public List<ContactChannelCreation> ContactChannelCreations { get; set; } = new List<ContactChannelCreation>();
public ContactChannelCreations ContactChannelCreations { get; set; } = new ContactChannelCreations();

public Candidate()
: base()
{
public Candidate() : base(){
}

public Candidate(Entity entity, ICrmService crm, IServiceProvider serviceProvider)
: base(entity, crm, serviceProvider)
{
: base(entity, crm, serviceProvider){
}

public bool HasTeacherTrainingAdviser()
Expand Down Expand Up @@ -335,6 +332,60 @@ public bool IsPlanningToRetakeGcseMathsAndEnglish()
return new[] { PlanningToRetakeGcseMathsId, PlanningToRetakeGcseEnglishId }.All(g => g == (int)GcseStatus.HasOrIsPlanningOnRetaking);
}

/// <summary>
/// Allows the configuration of a contact channel for a
/// candidate based on the provided contactChannelCreator.
/// </summary>
public void ConfigureChannel(ICreateContactChannel contactChannelCreator, Guid? candidateId)
{
if (candidateId == null)
{
if (contactChannelCreator.CreationChannelSourceId.HasValue)
{
ChannelId = null;
AddContactChannelCreation(
channelCreation: !ContactChannelCreations.HasExistingContactChannelCreations,
contactChannelCreator: contactChannelCreator);
}
else
{
ChannelId = contactChannelCreator.DefaultContactCreationChannel;
}
}
else // Candidate record already exists
{
// NB: we do not update a candidate's ChannelId for an existing record
// NB: CreationChannel should always be false for existing candidates
if (contactChannelCreator.CreationChannelSourceId.HasValue)
{
AddContactChannelCreation(
channelCreation: false,
contactChannelCreator: contactChannelCreator);
}
}
}

/// <summary>
/// Allows automatic creation of an <see cref="ContactChannelCreation"/>
/// and assigns to the underlying collection of contact channel creations.
/// </summary>
/// <param name="channelCreation">
/// Predicates the context of the contact channel creation based on the candidate status.
/// </param>
/// <param name="contactChannelCreator">
/// The source of the contact channel creation request, a type
/// which implements the <see cref="ICreateContactChannel"/> interface.
/// </param>
private void AddContactChannelCreation(bool channelCreation, ICreateContactChannel contactChannelCreator)
{
ContactChannelCreations.AddContactChannelCreation(
ContactChannelCreation.Create(
creationChannel: channelCreation,
sourceId: contactChannelCreator.CreationChannelSourceId,
serviceId: contactChannelCreator.CreationChannelServiceId,
activityId: contactChannelCreator.CreationChannelActivityId));
}

public bool MagicLinkTokenExpired() => MagicLinkTokenExpiresAt == null || MagicLinkTokenExpiresAt < DateTime.UtcNow;
public bool MagicLinkTokenAlreadyExchanged() => MagicLinkTokenStatusId == (int)MagicLinkTokenStatus.Exchanged;
}
Expand Down
29 changes: 22 additions & 7 deletions GetIntoTeachingApi/Models/Crm/ContactChannelCreation.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.Text.Json.Serialization;
using FluentValidation;
using GetIntoTeachingApi.Attributes;
using GetIntoTeachingApi.Services;
using Microsoft.Xrm.Sdk;
using System;
using System.Text.Json.Serialization;

namespace GetIntoTeachingApi.Models.Crm
{
Expand Down Expand Up @@ -94,13 +93,29 @@ public enum CreationChannelActivity
[EntityField("dfe_creationchannelactivities", typeof(OptionSetValue))]
public int? CreationChannelActivityId { get; set; }

public ContactChannelCreation() : base()
{
public ContactChannelCreation() : base(){
}

public ContactChannelCreation(Entity entity, ICrmService crm, IServiceProvider serviceProvider)
: base(entity, crm, serviceProvider)
{
: base(entity, crm, serviceProvider){
}

/// <summary>
/// Factory method for creating a ContactChannelCreation instance.
/// </summary>
/// <returns>
/// A configured <see cref="ContactChannelCreation"/> instance.
/// </returns>
public static ContactChannelCreation Create(
bool creationChannel,
int? sourceId,
int? serviceId,
int? activityId) => new()
{
CreationChannel = creationChannel,
CreationChannelSourceId = sourceId,
CreationChannelServiceId = serviceId,
CreationChannelActivityId = activityId,
};
}
}
65 changes: 65 additions & 0 deletions GetIntoTeachingApi/Models/Crm/ContactChannelCreations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System;

namespace GetIntoTeachingApi.Models.Crm
{
/// <summary>
/// Provides the blueprint for an object which encapsulates a collection of
/// <see cref="ContactChannelCreation"/> types defined by the
/// parent <see cref="Candidate"/> instance.
/// </summary>
public sealed class ContactChannelCreations
{
private readonly IList<ContactChannelCreation> _contactChannelCreations;

/// <summary>
/// Initialises a new collection of <see cref="ContactChannelCreation"/> on instantiation.
/// </summary>
public ContactChannelCreations()
{
_contactChannelCreations = new List<ContactChannelCreation>();
}

/// <summary>
/// Offers read-only access to the underlying
/// <see cref="ContactChannelCreation"/> collection.
/// </summary>
/// <returns>
/// The read-only collection of <see cref="ContactChannelCreation"/> configured types.
/// </returns>
public IReadOnlyCollection<ContactChannelCreation> GetContactChannelCreations() =>
new ReadOnlyCollection<ContactChannelCreation>(_contactChannelCreations);

/// <summary>
/// Allows a safe mechanism to add (mutate) the underlying
/// collection of <see cref="ContactChannelCreation"/> types.
/// </summary>
/// <param name="contactChannelCreation"
/// The <see cref="ContactChannelCreation"/> type to add to the underlying collection.
/// ></param>
/// <exception cref="ArgumentNullException">
/// Exception type thrown if the <see cref="ContactChannelCreation"/> is null.
/// </exception>
public void AddContactChannelCreation(ContactChannelCreation contactChannelCreation)
{
if (contactChannelCreation == null!)
{
throw new ArgumentNullException(
nameof(contactChannelCreation),
"The 'ContactChannelCreation' cannot be null.");
}
_contactChannelCreations.Add(contactChannelCreation);
}

/// <summary>
/// Allows the current list of <see cref="ContactChannelCreation"/> types to be reset.
/// </summary>
public void Reset() => _contactChannelCreations.Clear();

/// <summary>
/// Determines whether we have any existing ContactChannelCreations.
/// </summary>
public bool HasExistingContactChannelCreations => _contactChannelCreations.Count > 0;
}
}
29 changes: 29 additions & 0 deletions GetIntoTeachingApi/Models/Crm/ICreateContactChannel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
namespace GetIntoTeachingApi.Models.Crm
{
/// <summary>
/// Interface that defines the contract on which objects
/// that wish to invoke contact channel creation behaviour must adhere.
/// </summary>
public interface ICreateContactChannel
{
/// <summary>
/// Provides the default read-only contact creation channel integer value.
/// </summary>
int? DefaultContactCreationChannel { get; }

/// <summary>
/// Provides the ability to assign and retrieve the channel source creation identifier.
/// </summary>
int? CreationChannelSourceId { get; set; }

/// <summary>
/// Provides the ability to assign and retrieve the channel service creation identifier.
/// </summary>
int? CreationChannelServiceId { get; set; }

/// <summary>
/// Provides the ability to assign and retrieve the channel activity creation identifier.
/// </summary>
int? CreationChannelActivityId { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public CandidateValidator(IStore store, IDateTimeProvider dateTime)
RuleFor(candidate => candidate.ChannelId)
.NotNull()
.When(candidate => candidate.Id == null)
.When(candidate => !candidate.ContactChannelCreations.Any())
.When(candidate => !candidate.ContactChannelCreations.HasExistingContactChannelCreations)
.SetValidator(new PickListItemIdValidator<Candidate>("contact", "dfe_channelcreation", store));
RuleFor(candidate => candidate.HasGcseEnglishId)
.SetValidator(new PickListItemIdValidator<Candidate>("contact", "dfe_websitehasgcseenglish", store))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using System;
using System.Linq;
using System.Text.Json.Serialization;
using GetIntoTeachingApi.Models.Crm;
using GetIntoTeachingApi.Models.Crm;
using GetIntoTeachingApi.Services;
using GetIntoTeachingApi.Utils;
using Swashbuckle.AspNetCore.Annotations;
using System;
using System.Text.Json.Serialization;

namespace GetIntoTeachingApi.Models.GetIntoTeaching
{
public class GetIntoTeachingCallback
public class GetIntoTeachingCallback : ICreateContactChannel
{
public Guid? CandidateId { get; set; }
[SwaggerSchema(WriteOnly = true)]
Expand All @@ -34,8 +33,9 @@ public class GetIntoTeachingCallback
[JsonIgnore]
public IDateTimeProvider DateTimeProvider { get; set; } = new DateTimeProvider();

public GetIntoTeachingCallback()
{
public int? DefaultContactCreationChannel => (int?)Candidate.Channel.GetIntoTeachingCallback;

public GetIntoTeachingCallback(){
}

public GetIntoTeachingCallback(Candidate candidate)
Expand Down Expand Up @@ -63,8 +63,7 @@ private Candidate CreateCandidate()
LastName = LastName,
AddressTelephone = AddressTelephone,
};

ConfigureChannel(candidate);
candidate.ConfigureChannel(contactChannelCreator: this, candidateId: CandidateId);
SchedulePhoneCall(candidate);
AcceptPrivacyPolicy(candidate);

Expand All @@ -87,43 +86,6 @@ private void SchedulePhoneCall(Candidate candidate)
}
}

private void ConfigureChannel(Candidate candidate)
{
if (CandidateId == null)
{
if (CreationChannelSourceId.HasValue)
{
candidate.ChannelId = null;
// NB: CreationChannel should be true only if it is the first ContactChannelCreation record
AddCandidateCreationChannel(candidate, !candidate.ContactChannelCreations.Any());
}
else
{
candidate.ChannelId = (int?)Candidate.Channel.GetIntoTeachingCallback;
}
}
else // Candidate record already exists
{
// NB: we do not update a candidate's ChannelId for an existing record
// NB: CreationChannel should always be false for existing candidates
if (CreationChannelSourceId.HasValue)
{
AddCandidateCreationChannel(candidate, false);
}
}
}

private void AddCandidateCreationChannel(Candidate candidate, bool creationChannel)
{
candidate.ContactChannelCreations.Add(new ContactChannelCreation()
{
CreationChannel = creationChannel,
CreationChannelSourceId = CreationChannelSourceId,
CreationChannelServiceId = CreationChannelServiceId,
CreationChannelActivityId = CreationChannelActivityId,
});
}

private void AcceptPrivacyPolicy(Candidate candidate)
{
if (AcceptedPolicyId != null)
Expand Down
Loading

0 comments on commit 2702912

Please sign in to comment.