Skip to content

Commit

Permalink
Add warning to Edit User page for users missing CRM account (#771)
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad authored Oct 23, 2023
1 parent ab35c7a commit 11b8663
Show file tree
Hide file tree
Showing 17 changed files with 95 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16220,6 +16220,7 @@ public static class Fields
{
public const string AzureActiveDirectoryObjectId = "azureactivedirectoryobjectid";
public const string FirstName = "firstname";
public const string IsDisabled = "isdisabled";
public const string LastName = "lastname";
public const string annotation_owning_user = "annotation_owning_user";
public const string contact_owning_user = "contact_owning_user";
Expand Down Expand Up @@ -16456,6 +16457,26 @@ public string FirstName
}
}

/// <summary>
/// Information about whether the user is enabled.
/// </summary>
[Microsoft.Xrm.Sdk.AttributeLogicalNameAttribute("isdisabled")]
public System.Nullable<bool> IsDisabled
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<bool>>("isdisabled");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("IsDisabled");
this.SetAttributeValue("isdisabled", value);
this.OnPropertyChanged("IsDisabled");
}
}

/// <summary>
/// Last name of the user.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Microsoft.Xrm.Sdk.Query;

namespace TeachingRecordSystem.Core.Dqt.Queries;

public record GetSystemUserByAzureActiveDirectoryObjectIdQuery(string AzureActiveDirectoryObjectId, ColumnSet ColumnSet) : ICrmQuery<SystemUser?>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.PowerPlatform.Dataverse.Client;
using Microsoft.Xrm.Sdk.Query;
using TeachingRecordSystem.Core.Dqt.Queries;

namespace TeachingRecordSystem.Core.Dqt.QueryHandlers;

public class GetSystemUserByAzureActiveDirectoryObjectIdHandler : ICrmQueryHandler<GetSystemUserByAzureActiveDirectoryObjectIdQuery, SystemUser?>
{
public async Task<SystemUser?> Execute(GetSystemUserByAzureActiveDirectoryObjectIdQuery query, IOrganizationServiceAsync organizationService)
{
var queryByAttribute = new QueryByAttribute()
{
EntityName = SystemUser.EntityLogicalName,
ColumnSet = query.ColumnSet
};
queryByAttribute.AddAttributeValue(SystemUser.Fields.AzureActiveDirectoryObjectId, query.AzureActiveDirectoryObjectId);

var response = await organizationService.RetrieveMultipleAsync(queryByAttribute);

return response.Entities.SingleOrDefault()?.ToEntity<SystemUser>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public void Configure(string? name, OpenIdConnectOptions options)

var request = new QueryByAttribute(SystemUser.EntityLogicalName);
request.AddAttributeValue(SystemUser.Fields.AzureActiveDirectoryObjectId, new Guid(aadUserId));
request.AddAttributeValue(SystemUser.Fields.IsDisabled, false);

var response = await serviceClient.RetrieveMultipleAsync(request);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ namespace TeachingRecordSystem.SupportUi.Pages.Users.AddUser;
public class ConfirmModel : PageModel
{
private readonly TrsDbContext _dbContext;
private readonly IUserService _userService;
private readonly IAadUserService _userService;
private readonly IClock _clock;
private readonly TrsLinkGenerator _linkGenerator;
private Services.AzureActiveDirectory.User? _user;

public ConfirmModel(
TrsDbContext dbContext,
IUserService userService,
IAadUserService userService,
IClock clock,
TrsLinkGenerator linkGenerator)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ namespace TeachingRecordSystem.SupportUi.Pages.Users.AddUser;
[Authorize(Roles = UserRoles.Administrator)]
public class IndexModel : PageModel
{
private readonly IUserService _userService;
private readonly IAadUserService _userService;
private readonly TrsLinkGenerator _trsLinkGenerator;

public IndexModel(IUserService userService, TrsLinkGenerator trsLinkGenerator)
public IndexModel(IAadUserService userService, TrsLinkGenerator trsLinkGenerator)
{
_userService = userService;
_trsLinkGenerator = trsLinkGenerator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
<form action="@LinkGenerator.EditUser(Model.UserId!)" method="post">
<h1 class="govuk-heading-l">@ViewBag.Title</h1>

@if (!Model.HasCrmAccount)
{
<govuk-warning-text icon-fallback-text="Warning" data-testid="NoCrmAccountWarning">User does not have an account in CRM.</govuk-warning-text>
}
else if (Model.CrmAccountIsDisabled)
{
<govuk-warning-text icon-fallback-text="Warning" data-testid="CrmAccountDisabledWarning">User's CRM account is disabled.</govuk-warning-text>
}

<govuk-input asp-for="Email" type="email" disabled />

<govuk-input asp-for="Name" disabled="@(!Model.IsActiveUser)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using TeachingRecordSystem.Core.DataStore.Postgres;
using TeachingRecordSystem.Core.Dqt.Models;
using TeachingRecordSystem.Core.Dqt.Queries;
using TeachingRecordSystem.Core.Events;

namespace TeachingRecordSystem.SupportUi.Pages.Users;
Expand All @@ -13,16 +15,19 @@ namespace TeachingRecordSystem.SupportUi.Pages.Users;
public class EditUser : PageModel
{
private readonly TrsDbContext _dbContext;
private readonly ICrmQueryDispatcher _crmQueryDispatcher;
private readonly IClock _clock;
private readonly TrsLinkGenerator _linkGenerator;
private Core.DataStore.Postgres.Models.User? _user;

public EditUser(
TrsDbContext dbContext,
ICrmQueryDispatcher crmQueryDispatcher,
IClock clock,
TrsLinkGenerator linkGenerator)
{
_dbContext = dbContext;
_crmQueryDispatcher = crmQueryDispatcher;
_clock = clock;
_linkGenerator = linkGenerator;
}
Expand All @@ -44,13 +49,29 @@ public EditUser(

public bool IsActiveUser { get; set; }

public IActionResult OnGet()
public bool HasCrmAccount { get; set; }

public bool CrmAccountIsDisabled { get; set; }

public async Task OnGet()
{
Name = _user!.Name;
IsActiveUser = _user.Active;
Roles = _user.Roles;

return Page();
if (_user.AzureAdUserId is not null)
{
var crmUser = await _crmQueryDispatcher.ExecuteQuery(
new GetSystemUserByAzureActiveDirectoryObjectIdQuery(
_user.AzureAdUserId, new ColumnSet(SystemUser.Fields.IsDisabled)));

HasCrmAccount = crmUser is not null;
CrmAccountIsDisabled = crmUser?.IsDisabled == true;
}
else
{
HasCrmAccount = false;
}
}

public async Task<IActionResult> OnPost()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

namespace TeachingRecordSystem.SupportUi.Services.AzureActiveDirectory;

public class UserService : IUserService
public class AadUserService : IAadUserService
{
private readonly GraphServiceClient _graphServiceClient;

public UserService(GraphServiceClient graphServiceClient)
public AadUserService(GraphServiceClient graphServiceClient)
{
_graphServiceClient = graphServiceClient;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace TeachingRecordSystem.SupportUi.Services.AzureActiveDirectory;

public interface IUserService
public interface IAadUserService
{
Task<User?> GetUserByEmail(string email);
Task<User?> GetUserById(string userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public static IServiceCollection AddAzureActiveDirectory(
{
if (!environment.IsUnitTests())
{
services.AddTransient<IUserService, UserService>();
services.AddTransient<IAadUserService, AadUserService>();
}

return services;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
global using FormFlow;
global using TeachingRecordSystem.Core;
global using TeachingRecordSystem.Core.Dqt;
global using ColumnSet = Microsoft.Xrm.Sdk.Query.ColumnSet;
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder)
services.AddSingleton<IEventObserver>(EventObserver);
services.AddTestScoped<IClock>(tss => tss.Clock);
services.AddTestScoped<IDataverseAdapter>(tss => tss.DataverseAdapterMock.Object);
services.AddTestScoped<IUserService>(tss => tss.AzureActiveDirectoryUserServiceMock.Object);
services.AddTestScoped<IAadUserService>(tss => tss.AzureActiveDirectoryUserServiceMock.Object);
services.AddSingleton<TestData>();
services.AddFakeXrm();
services.AddTransient<ICurrentUserIdProvider, TestUserCurrentUserIdProvider>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected TestBase(HostFixture hostFixture)

public TestableClock Clock => _testServices.Clock;

public Mock<Services.AzureActiveDirectory.IUserService> AzureActiveDirectoryUserServiceMock => _testServices.AzureActiveDirectoryUserServiceMock;
public Mock<Services.AzureActiveDirectory.IAadUserService> AzureActiveDirectoryUserServiceMock => _testServices.AzureActiveDirectoryUserServiceMock;

public HttpClient HttpClient { get; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ public static TestScopedServices Reset()

public Mock<IDataverseAdapter> DataverseAdapterMock { get; }

public Mock<IUserService> AzureActiveDirectoryUserServiceMock { get; }
public Mock<IAadUserService> AzureActiveDirectoryUserServiceMock { get; }
}
1 change: 1 addition & 0 deletions crm_attributes.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@
],
"systemuser": [
"azureactivedirectoryobjectid",
"isdisabled",
"firstname",
"lastname"
],
Expand Down
2 changes: 1 addition & 1 deletion tools/coretools/CrmSvcUtil.exe.config
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<add key="EntityCommandLineText" />
<add key="EntitiesToSkip" />
<add key="EntitiesWhitelist" value="account|annotation|contact|dfeta_businesseventaudit|dfeta_country|dfeta_document|dfeta_earlyyearsstatus|dfeta_hequalification|dfeta_hesubject|dfeta_induction|dfeta_inductionperiod|dfeta_initialteachertraining|dfeta_ittqualification|dfeta_ittsubject|dfeta_previousname|dfeta_qtsregistration|dfeta_qualification|dfeta_sanction|dfeta_sanctioncode|dfeta_specialism|dfeta_teacherstatus|incident|incidentresolution|plugintype|sdkmessage|sdkmessagefilter|sdkmessageprocessingstep|sdkmessageprocessingstepimage|subject|systemuser|task" />
<add key="AttributesWhitelist" value="account:dfeta_trainingprovider,dfeta_ukprn,name,statecode|annotation:documentbody,filename,mimetype,notetext,objectid,objecttypecode,statecode,subject|contact:address1_city,address1_country,address1_line1,address1_line2,address1_line3,address1_postalcode,birthdate,contactid,createdon,dfeta_activesanctions,dfeta_allowpiiupdatesfromregister,dfeta_eytsdate,dfeta_husid,dfeta_inductionStatus,dfeta_lastidentityupdate,dfeta_loginfailedcounter,dfeta_ninumber,dfeta_previouslastname,dfeta_qtsdate,dfeta_slugid,dfeta_statedfirstname,dfeta_statedlastname,dfeta_statedmiddlename,dfeta_trn,dfeta_trnallocaterequest,dfeta_trnrequired,dfeta_tspersonid,emailaddress1,emailaddress2,firstname,fullname,gendercode,lastname,masterid,merged,middlename,mobilephone,statecode,telephone1|dfeta_businesseventaudit:createdon,dfeta_changedfield,dfeta_newvalue,dfeta_oldvalue,dfeta_person,statecode|dfeta_country:dfeta_name,dfeta_value,statecode|dfeta_document:dfeta_caseid,dfeta_documentid,dfeta_name,dfeta_personid,dfeta_type,statecode,statuscode|dfeta_earlyyearsstatus:dfeta_name,dfeta_value,statecode|dfeta_hequalification:dfeta_hequalificationid,dfeta_name,dfeta_value,statecode|dfeta_hesubject:dfeta_name,dfeta_value,statecode|dfeta_induction:CreatedOn,dfeta_completiondate,dfeta_inductionexemptionreason,dfeta_inductionstatus,dfeta_personid,dfeta_startdate,statecode|dfeta_inductionperiod:dfeta_appropriatebodyid,dfeta_enddate,dfeta_inductionid,dfeta_numberofterms,dfeta_startdate,statecode|dfeta_initialteachertraining:dfeta_agerangefrom,dfeta_agerangeto,dfeta_cohortyear,dfeta_countryid,dfeta_establishmentid,dfeta_ittqualificationaim,dfeta_ittqualificationid,dfeta_personid,dfeta_programmeenddate,dfeta_programmestartdate,dfeta_programmetype,dfeta_result,dfeta_slugid,dfeta_subject1id,dfeta_subject2id,dfeta_subject3id,dfeta_traineeid,statecode|dfeta_ittqualification:dfeta_name,dfeta_value,statecode|dfeta_ittsubject:dfeta_name,dfeta_value,statecode|dfeta_previousname:createdon,dfeta_changedon,dfeta_name,dfeta_personid,dfeta_previousnameid,dfeta_type,statecode|dfeta_qtsregistration:dfeta_earlyyearsstatusid,dfeta_eytsdate,dfeta_inductionid,dfeta_name,dfeta_personid,dfeta_qtsdate,dfeta_teacherstatusid,statecode|dfeta_qualification:CreatedOn,dfeta_completionorawarddate,dfeta_createdbyapi,dfeta_he_classdivision,dfeta_he_completiondate,dfeta_he_countryid,dfeta_he_establishmentid,dfeta_he_hequalificationid,dfeta_he_hesubject1id,dfeta_he_hesubject2id,dfeta_he_hesubject3id,dfeta_mq_date,dfeta_mq_specialismid,dfeta_npqel_awarded,dfeta_npqel_date,dfeta_npqeyl_awarded,dfeta_npqeyl_date,dfeta_NPQH_Awarded,dfeta_NPQH_Date,dfeta_npqlbc_awarded,dfeta_npqlbc_date,dfeta_npqll_awarded,dfeta_npqll_date,dfeta_npqlt_awarded,dfeta_npqlt_date,dfeta_npqltd_awarded,dfeta_npqltd_date,dfeta_npqml_awarded,dfeta_npqml_date,dfeta_npqsl_awarded,dfeta_npqsl_date,dfeta_personid,dfeta_type,statecode|dfeta_sanction:dfeta_detailslink,dfeta_enddate,dfeta_noreappuntildate,dfeta_personid,dfeta_sanctioncodeid,dfeta_sanctiondetails,dfeta_sanctionid,dfeta_spent,dfeta_startdate,statecode|dfeta_sanctioncode:dfeta_name,dfeta_sanctioncodeid,dfeta_value,statecode|dfeta_specialism:dfeta_name,dfeta_value,statecode|dfeta_teacherstatus:dfeta_name,dfeta_qtsdaterequired,dfeta_value,statecode|incident:createdon,customerid,description,dfeta_fromidentity,dfeta_newdateofbirth,dfeta_newfirstname,dfeta_newlastname,dfeta_newmiddlename,dfeta_statedfirstname,dfeta_statedlastname,dfeta_statedmiddlename,statecode,statuscode,subjectid,ticketnumber,title|incidentresolution:activityid,incidentid,statecode,subject|plugintype:|sdkmessage:|sdkmessagefilter:|sdkmessageprocessingstep:|sdkmessageprocessingstepimage:|subject:description,statecode,subjectid,title|systemuser:azureactivedirectoryobjectid,firstname,lastname|task:category,description,dfeta_potentialduplicateid,regardingobjectid,scheduledend,statecode,subject" />
<add key="AttributesWhitelist" value="account:dfeta_trainingprovider,dfeta_ukprn,name,statecode|annotation:documentbody,filename,mimetype,notetext,objectid,objecttypecode,statecode,subject|contact:address1_city,address1_country,address1_line1,address1_line2,address1_line3,address1_postalcode,birthdate,contactid,createdon,dfeta_activesanctions,dfeta_allowpiiupdatesfromregister,dfeta_eytsdate,dfeta_husid,dfeta_inductionStatus,dfeta_lastidentityupdate,dfeta_loginfailedcounter,dfeta_ninumber,dfeta_previouslastname,dfeta_qtsdate,dfeta_slugid,dfeta_statedfirstname,dfeta_statedlastname,dfeta_statedmiddlename,dfeta_trn,dfeta_trnallocaterequest,dfeta_trnrequired,dfeta_tspersonid,emailaddress1,emailaddress2,firstname,fullname,gendercode,lastname,masterid,merged,middlename,mobilephone,statecode,telephone1|dfeta_businesseventaudit:createdon,dfeta_changedfield,dfeta_newvalue,dfeta_oldvalue,dfeta_person,statecode|dfeta_country:dfeta_name,dfeta_value,statecode|dfeta_document:dfeta_caseid,dfeta_documentid,dfeta_name,dfeta_personid,dfeta_type,statecode,statuscode|dfeta_earlyyearsstatus:dfeta_name,dfeta_value,statecode|dfeta_hequalification:dfeta_hequalificationid,dfeta_name,dfeta_value,statecode|dfeta_hesubject:dfeta_name,dfeta_value,statecode|dfeta_induction:CreatedOn,dfeta_completiondate,dfeta_inductionexemptionreason,dfeta_inductionstatus,dfeta_personid,dfeta_startdate,statecode|dfeta_inductionperiod:dfeta_appropriatebodyid,dfeta_enddate,dfeta_inductionid,dfeta_numberofterms,dfeta_startdate,statecode|dfeta_initialteachertraining:dfeta_agerangefrom,dfeta_agerangeto,dfeta_cohortyear,dfeta_countryid,dfeta_establishmentid,dfeta_ittqualificationaim,dfeta_ittqualificationid,dfeta_personid,dfeta_programmeenddate,dfeta_programmestartdate,dfeta_programmetype,dfeta_result,dfeta_slugid,dfeta_subject1id,dfeta_subject2id,dfeta_subject3id,dfeta_traineeid,statecode|dfeta_ittqualification:dfeta_name,dfeta_value,statecode|dfeta_ittsubject:dfeta_name,dfeta_value,statecode|dfeta_previousname:createdon,dfeta_changedon,dfeta_name,dfeta_personid,dfeta_previousnameid,dfeta_type,statecode|dfeta_qtsregistration:dfeta_earlyyearsstatusid,dfeta_eytsdate,dfeta_inductionid,dfeta_name,dfeta_personid,dfeta_qtsdate,dfeta_teacherstatusid,statecode|dfeta_qualification:CreatedOn,dfeta_completionorawarddate,dfeta_createdbyapi,dfeta_he_classdivision,dfeta_he_completiondate,dfeta_he_countryid,dfeta_he_establishmentid,dfeta_he_hequalificationid,dfeta_he_hesubject1id,dfeta_he_hesubject2id,dfeta_he_hesubject3id,dfeta_mq_date,dfeta_mq_specialismid,dfeta_npqel_awarded,dfeta_npqel_date,dfeta_npqeyl_awarded,dfeta_npqeyl_date,dfeta_NPQH_Awarded,dfeta_NPQH_Date,dfeta_npqlbc_awarded,dfeta_npqlbc_date,dfeta_npqll_awarded,dfeta_npqll_date,dfeta_npqlt_awarded,dfeta_npqlt_date,dfeta_npqltd_awarded,dfeta_npqltd_date,dfeta_npqml_awarded,dfeta_npqml_date,dfeta_npqsl_awarded,dfeta_npqsl_date,dfeta_personid,dfeta_type,statecode|dfeta_sanction:dfeta_detailslink,dfeta_enddate,dfeta_noreappuntildate,dfeta_personid,dfeta_sanctioncodeid,dfeta_sanctiondetails,dfeta_sanctionid,dfeta_spent,dfeta_startdate,statecode|dfeta_sanctioncode:dfeta_name,dfeta_sanctioncodeid,dfeta_value,statecode|dfeta_specialism:dfeta_name,dfeta_value,statecode|dfeta_teacherstatus:dfeta_name,dfeta_qtsdaterequired,dfeta_value,statecode|incident:createdon,customerid,description,dfeta_fromidentity,dfeta_newdateofbirth,dfeta_newfirstname,dfeta_newlastname,dfeta_newmiddlename,dfeta_statedfirstname,dfeta_statedlastname,dfeta_statedmiddlename,statecode,statuscode,subjectid,ticketnumber,title|incidentresolution:activityid,incidentid,statecode,subject|plugintype:|sdkmessage:|sdkmessagefilter:|sdkmessageprocessingstep:|sdkmessageprocessingstepimage:|subject:description,statecode,subjectid,title|systemuser:azureactivedirectoryobjectid,firstname,isdisabled,lastname|task:category,description,dfeta_potentialduplicateid,regardingobjectid,scheduledend,statecode,subject" />
<add key="EntityPrefixesToSkip" />
<add key="EntityPrefixesWhitelist" />
<add key="FilePrefixText" />
Expand Down

0 comments on commit 11b8663

Please sign in to comment.