Skip to content

Commit

Permalink
Add AllowIdSignInWithProhibitions member to v3 teacher response (#913)
Browse files Browse the repository at this point in the history
This is a short term solution so that ID can prevent sign in (or
registration) of prohibited teachers *unless* a flag has been set on
the matched DQT record.

As it's for our use only and short term, I've hidden it from the Swagger
doc and prefixed the include entry with an '_'.
  • Loading branch information
gunndabad authored Nov 16, 2023
1 parent 7cb4951 commit 8d0b59a
Show file tree
Hide file tree
Showing 13 changed files with 93 additions and 63 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace TeachingRecordSystem.Api.Infrastructure.OpenApi;

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public sealed class ExcludeFromSchemaAttribute : Attribute
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Reflection;
using NJsonSchema.Generation;

namespace TeachingRecordSystem.Api.Infrastructure.OpenApi;

public class RemoveExcludedEnumOptionsSchemaProcessor : ISchemaProcessor
{
public void Process(SchemaProcessorContext context)
{
var type = context.ContextualType.Type;

if (!type.IsEnum)
{
return;
}

foreach (var memberName in Enum.GetNames(type))
{
var member = type.GetField(memberName)!;
if (member.GetCustomAttribute<ExcludeFromSchemaAttribute>() is not null)
{
context.Schema.Enumeration.Remove(memberName);
context.Schema.EnumerationNames.Remove(memberName);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static IServiceCollection AddOpenApi(this IServiceCollection services, IC
settings.DocumentProcessors.Add(new PopulateResponseDescriptionOperationProcessor());

settings.SchemaProcessors.Add(new RemoveCompositeValuesFromFlagsEnumSchemaProcessor());
settings.SchemaProcessors.Add(new RemoveExcludedEnumOptionsSchemaProcessor());

settings.OperationProcessors.Add(new ResponseContentTypeOperationProcessor());
settings.OperationProcessors.Add(new PopulateResponseDescriptionOperationProcessor());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ public record AlertInfo
{
public required AlertType AlertType { get; init; }
public required string DqtSanctionCode { get; init; }
public required DateOnly? StartDate { get; init; }
public required DateOnly? EndDate { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ public GetTeacherHandler(
Contact.Fields.dfeta_NINumber,
Contact.Fields.dfeta_QTSDate,
Contact.Fields.dfeta_EYTSDate,
Contact.Fields.EMailAddress1)));
Contact.Fields.EMailAddress1,
Contact.Fields.dfeta_AllowIDSignInWithProhibitions)));

if (contactDetail is null)
{
Expand Down Expand Up @@ -201,7 +202,10 @@ public GetTeacherHandler(
var getSanctionsQuery = new GetSanctionsByContactIdsQuery(
new[] { teacher.Id },
ActiveOnly: true,
ColumnSet: new(dfeta_sanction.Fields.dfeta_StartDate));
ColumnSet: new(
dfeta_sanction.Fields.dfeta_StartDate,
dfeta_sanction.Fields.dfeta_EndDate,
dfeta_sanction.Fields.dfeta_Spent));

sanctions = (await _crmQueryDispatcher.ExecuteQuery(getSanctionsQuery))[teacher.Id];
}
Expand Down Expand Up @@ -275,6 +279,10 @@ public GetTeacherHandler(

var qtsAwardedInWales = qtsRegistrations.Any(qts => qts.dfeta_QTSDate is not null && qts.dfeta_TeacherStatusId.Id == qtsAwardedInWalesStatus.Id);

var allowIdSignInWithProhibitions = request.Include.HasFlag(GetTeacherRequestIncludes._AllowIdSignInWithProhibitions) ?
Option.Some(teacher.dfeta_AllowIDSignInWithProhibitions == true) :
default;

return new GetTeacherResponse()
{
Trn = request.Trn,
Expand Down Expand Up @@ -317,6 +325,7 @@ public GetTeacherHandler(
Sanctions = request.Include.HasFlag(GetTeacherRequestIncludes.Sanctions) ?
Option.Some(sanctions!
.Where(s => Constants.ExposableSanctionCodes.Contains(s.SanctionCode))
.Where(s => s.Sanction.dfeta_EndDate is null && s.Sanction.dfeta_Spent != true)
.Select(s => new SanctionInfo()
{
Code = s.SanctionCode,
Expand All @@ -329,12 +338,15 @@ public GetTeacherHandler(
.Select(s => new AlertInfo()
{
AlertType = AlertType.Prohibition,
DqtSanctionCode = s.SanctionCode
DqtSanctionCode = s.SanctionCode,
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true),
EndDate = s.Sanction.dfeta_EndDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
})) :
default,
PreviousNames = request.Include.HasFlag(GetTeacherRequestIncludes.PreviousNames) ?
Option.Some(previousNames!.Select(n => n)) :
default
default,
AllowIdSignInWithProhibitions = allowIdSignInWithProhibitions
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.ComponentModel;
using MediatR;
using TeachingRecordSystem.Api.Infrastructure.OpenApi;
using TeachingRecordSystem.Api.V3.Responses;

namespace TeachingRecordSystem.Api.V3.Requests;
Expand Down Expand Up @@ -27,5 +28,8 @@ public enum GetTeacherRequestIncludes
Alerts = 1 << 7,
PreviousNames = 1 << 8,

[ExcludeFromSchema]
_AllowIdSignInWithProhibitions = 1 << 9,

All = Induction | InitialTeacherTraining | NpqQualifications | MandatoryQualifications | PendingDetailChanges | HigherEducationQualifications | Sanctions | Alerts | PreviousNames
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public record GetTeacherResponse
public required Option<IEnumerable<SanctionInfo>> Sanctions { get; init; }
public required Option<IEnumerable<AlertInfo>> Alerts { get; init; }
public required Option<IEnumerable<NameInfo>> PreviousNames { get; init; }
public required Option<bool> AllowIdSignInWithProhibitions { get; init; }
}

public record GetTeacherResponseQts
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,7 @@ public static class Fields
public const string Id = "contactid";
public const string CreatedOn = "createdon";
public const string dfeta_ActiveSanctions = "dfeta_activesanctions";
public const string dfeta_AllowIDSignInWithProhibitions = "dfeta_allowidsigninwithprohibitions";
public const string dfeta_AllowPiiUpdatesFromRegister = "dfeta_allowpiiupdatesfromregister";
public const string dfeta_EYTSDate = "dfeta_eytsdate";
public const string dfeta_HUSID = "dfeta_husid";
Expand Down Expand Up @@ -1626,6 +1627,26 @@ public System.Nullable<bool> dfeta_ActiveSanctions
}
}

/// <summary>
///
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("dfeta_allowidsigninwithprohibitions")]
public System.Nullable<bool> dfeta_AllowIDSignInWithProhibitions
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<bool>>("dfeta_allowidsigninwithprohibitions");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("dfeta_AllowIDSignInWithProhibitions");
this.SetAttributeValue("dfeta_allowidsigninwithprohibitions", value);
this.OnPropertyChanged("dfeta_AllowIDSignInWithProhibitions");
}
}

/// <summary>
///
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ public async Task<IDictionary<Guid, SanctionResult[]>> Execute(

if (query.ActiveOnly)
{
queryExpression.Criteria.AddCondition(dfeta_sanction.Fields.dfeta_Spent, ConditionOperator.Equal, false);
queryExpression.Criteria.AddCondition(dfeta_sanction.Fields.dfeta_EndDate, ConditionOperator.Null);
queryExpression.Criteria.AddCondition(dfeta_sanction.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_sanctionState.Active);
}

queryExpression.Criteria.AddCondition(dfeta_sanction.Fields.StateCode, ConditionOperator.Equal, (int)dfeta_sanctionState.Active);
queryExpression.Criteria.AddCondition(dfeta_sanction.Fields.dfeta_PersonId, ConditionOperator.In, contactIdsArray.Cast<object>().ToArray()); // https://community.dynamics.com/crm/b/crmbusiness/posts/crm-2011-odd-error-with-query-expression-and-conditionoperator-in

var sanctionCodeLink = queryExpression.AddLink(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,12 +568,16 @@ protected async Task ValidRequestWithAlerts_ReturnsExpectedSanctionsContent(
new
{
alertType = "Prohibition",
dqtSanctionCode = sanctions[0].SanctionCode
dqtSanctionCode = sanctions[0].SanctionCode,
startDate = sanctions[0].StartDate,
endDate = (DateOnly?)null
},
new
{
alertType = "Prohibition",
dqtSanctionCode = sanctions[1].SanctionCode
dqtSanctionCode = sanctions[1].SanctionCode,
startDate = sanctions[1].StartDate,
endDate = (DateOnly?)null
}
},
responseAlerts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,57 +39,4 @@ public async Task ReturnsSanctionsForEachContactIdSpecified()
Assert.Collection(sanctionCodesByContactId[person2.ContactId], c => Assert.Equal(person2Sanction2Code, c.SanctionCode), c => Assert.Equal(person2Sanction1Code, c.SanctionCode));
Assert.Empty(sanctionCodesByContactId[person3.ContactId]);
}

[Theory]
[InlineData(true, true, false)]
[InlineData(false, true, true)]
[InlineData(true, false, true)]
[InlineData(false, false, true)]
public async Task SpentSanctionIsReturnedAsExpected(bool spent, bool activeOnly, bool expectSanctionReturned)
{
// Arrange
var sanctionCode = "G1";
var person = await _dataScope.TestData.CreatePerson(x => x.WithSanction(sanctionCode, spent: spent));

// Act
var sanctionCodesByContactId = await _crmQueryDispatcher.ExecuteQuery(
new GetSanctionsByContactIdsQuery(new[] { person.ContactId }, ActiveOnly: activeOnly, new ColumnSet()));

// Assert
if (expectSanctionReturned)
{
Assert.Collection(sanctionCodesByContactId[person.ContactId], c => Assert.Equal("G1", sanctionCode));
}
else
{
Assert.Empty(sanctionCodesByContactId[person.ContactId]);
}
}

[Theory]
[InlineData(true, true, false)]
[InlineData(false, true, true)]
[InlineData(true, false, true)]
[InlineData(false, false, true)]
public async Task EndedSanctionIsReturnedAsExpected(bool ended, bool activeOnly, bool expectSanctionReturned)
{
// Arrange
var sanctionCode = "G1";
var person = await _dataScope.TestData.CreatePerson(
x => x.WithSanction(sanctionCode, spent: false, endDate: ended ? DateOnly.FromDateTime(DateTime.Today.AddDays(-1)) : null));

// Act
var sanctionCodesByContactId = await _crmQueryDispatcher.ExecuteQuery(
new GetSanctionsByContactIdsQuery(new[] { person.ContactId }, ActiveOnly: activeOnly, new ColumnSet()));

// Assert
if (expectSanctionReturned)
{
Assert.Collection(sanctionCodesByContactId[person.ContactId], c => Assert.Equal(sanctionCode, c.SanctionCode));
}
else
{
Assert.Empty(sanctionCodesByContactId[person.ContactId]);
}
}
}
3 changes: 2 additions & 1 deletion crm_attributes.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@
"telephone1",
"dfeta_slugid",
"dfeta_allowpiiupdatesfromregister",
"dfeta_previouslastname"
"dfeta_previouslastname",
"dfeta_AllowIDSignInWithProhibitions"
],
"dfeta_businesseventaudit":[
"createdon",
Expand Down
Loading

0 comments on commit 8d0b59a

Please sign in to comment.