diff --git a/TeachingRecordSystem/TeachingRecordSystem.sln b/TeachingRecordSystem/TeachingRecordSystem.sln index 2e2b580648..a1bbce22bc 100644 --- a/TeachingRecordSystem/TeachingRecordSystem.sln +++ b/TeachingRecordSystem/TeachingRecordSystem.sln @@ -53,7 +53,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeachingRecordSystem.Author EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gen", "gen", "{5E273A79-2EA3-46CD-9049-769F880868FE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TeachingRecordSystem.Api.Generator", "gen\TeachingRecordSystem.Api.Generator\TeachingRecordSystem.Api.Generator.csproj", "{7EA8C0A7-C149-4928-8E37-55D44976D765}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TeachingRecordSystem.Api.Generator", "gen\TeachingRecordSystem.Api.Generator\TeachingRecordSystem.Api.Generator.csproj", "{7EA8C0A7-C149-4928-8E37-55D44976D765}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/Pages/RequestTrn/PreviousName.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/Pages/RequestTrn/PreviousName.cshtml.cs index 890ebd9178..55d8839397 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/Pages/RequestTrn/PreviousName.cshtml.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/Pages/RequestTrn/PreviousName.cshtml.cs @@ -2,7 +2,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc.RazorPages; -using TeachingRecordSystem.AuthorizeAccess.DataAnnotations; +using TeachingRecordSystem.UiCommon.DataAnnotations; using TeachingRecordSystem.UiCommon.FormFlow; namespace TeachingRecordSystem.AuthorizeAccess.Pages.RequestTrn; diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertCategoryMapping.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertCategoryMapping.cs index 8ec2b682d1..4e4cc5faa8 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertCategoryMapping.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertCategoryMapping.cs @@ -13,15 +13,15 @@ public void Configure(EntityTypeBuilder builder) builder.HasData( new AlertCategory { AlertCategoryId = Guid.Parse("ee78d44d-abf8-44a9-b22b-87a821f8d3c9"), Name = "EEA Decision" }, new AlertCategory { AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Failed induction" }, - new AlertCategory { AlertCategoryId = Guid.Parse("768c9eb4-355b-4491-bb20-67eb59a97579"), Name = "Flags" }, + new AlertCategory { AlertCategoryId = Guid.Parse("768c9eb4-355b-4491-bb20-67eb59a97579"), Name = "Flag" }, new AlertCategory { AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "GTC Decision" }, new AlertCategory { AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "GTC Prohibition from teaching" }, new AlertCategory { AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "GTC Restriction" }, new AlertCategory { AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition from teaching" }, - new AlertCategory { AlertCategoryId = Guid.Parse("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), Name = "DBS" }, + new AlertCategory { AlertCategoryId = Guid.Parse("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), Name = "Restricted/DBS" }, new AlertCategory { AlertCategoryId = Guid.Parse("cbf7633f-3904-407d-8371-42a473fa641f"), Name = "Restriction" }, new AlertCategory { AlertCategoryId = Guid.Parse("38df5a00-94ab-486f-8905-d5b2eac04000"), Name = "Section 128 (SoS)" }, new AlertCategory { AlertCategoryId = Guid.Parse("227b75e5-bb98-496c-8860-1baea37aa5c6"), Name = "TRA Decision (SoS)" }, - new AlertCategory { AlertCategoryId = Guid.Parse("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a"), Name = "Not true alert" }); + new AlertCategory { AlertCategoryId = Guid.Parse("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), Name = "SoS Restriction" }); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertTypeMapping.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertTypeMapping.cs index a6481ccf34..bb7f196804 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertTypeMapping.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Mappings/AlertTypeMapping.cs @@ -11,53 +11,54 @@ public void Configure(EntityTypeBuilder builder) builder.HasKey(x => x.AlertTypeId); builder.Property(x => x.Name).IsRequired().HasMaxLength(AlertType.NameMaxLength).UseCollation("case_insensitive"); builder.Property(x => x.DqtSanctionCode).HasMaxLength(AlertType.DqtSanctionCodeMaxLength).UseCollation("case_insensitive"); + builder.Property(x => x.ProhibitionLevel).IsRequired(); + builder.Property(x => x.IsActive).IsRequired(); builder.HasIndex(x => x.AlertCategoryId).HasDatabaseName(AlertType.AlertCategoryIdIndexName); - builder.HasOne().WithMany().HasForeignKey(x => x.AlertCategoryId).HasConstraintName(AlertType.AlertCategoryForeignKeyName); + builder.HasOne().WithMany(c => c.AlertTypes).HasForeignKey(x => x.AlertCategoryId).HasConstraintName(AlertType.AlertCategoryForeignKeyName); builder.HasData( - new AlertType { AlertTypeId = Guid.Parse("2ca98658-1d5b-49d5-b05f-cc08c8b8502c"), AlertCategoryId = Guid.Parse("ee78d44d-abf8-44a9-b22b-87a821f8d3c9"), Name = "Teacher sanctioned in other EEA member state", DqtSanctionCode = "T8", ProhibitionLevel = ProhibitionLevel.Notify }, - new AlertType { AlertTypeId = Guid.Parse("9fafaa80-f9f8-44a0-b7b3-cffedcbe0298"), AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Failed induction", DqtSanctionCode = "C2", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("651e1f56-3135-4961-bd7e-3f7b2c75cb04"), AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Prohibited by the Secretary of State - failed probation", DqtSanctionCode = "C1", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("5ea8bb68-4774-4ad8-b635-213a0cdda4c3"), AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Restricted by the Secretary of State - failed probation - permitted to carry out specified work for a period equal in length to a statutory induction period only", DqtSanctionCode = "C3", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("ae3e385d-03f8-4f12-9ce2-006afe827d23"), AlertCategoryId = Guid.Parse("768c9eb4-355b-4491-bb20-67eb59a97579"), Name = "FOR INTERNAL INFORMATION ONLY - see alert details", DqtSanctionCode = "T9", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("a6fc9f2e-8923-4163-978e-93bd901d146f"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Conditional Registration Order - conviction of a relevant offence", DqtSanctionCode = "A18", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("1ebd1620-293d-4169-ba78-0b41a6413ad9"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Conditional Registration Order - serious professional incompetence", DqtSanctionCode = "A7", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("3499860a-a0fb-43e3-878e-c226d14150b0"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Conditional Registration Order - unacceptable professional conduct", DqtSanctionCode = "A3", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("552ee226-a3a9-4dc3-8d04-0b7e4f641b51"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "For internal information only - historic GTC finding of unsuitable for registration", DqtSanctionCode = "A15", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("33e00e46-6513-4136-adfd-1352cf34d8ec"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - breach of condition(s)", DqtSanctionCode = "A22", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("0740f9eb-ece3-4394-a230-453da224d337"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - conviction for a relevant offence", DqtSanctionCode = "A16", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("b6c8d8f1-723e-49a5-9551-25805e3e29b9"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - serious professional incompetence", DqtSanctionCode = "A12", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("78f88de2-9ec1-41b8-948a-33bdff223206"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - unacceptable professional conduct", DqtSanctionCode = "A11", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("fcff87d6-88f5-4fc5-ac81-5350b4fdd9e1"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Reprimand - conviction of a relevant offence", DqtSanctionCode = "A17", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("3f7de5fd-05a8-404f-a97c-428f54e81322"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Reprimand - serious professional incompetence", DqtSanctionCode = "A8", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("0ae8d4b6-ec9b-47ca-9338-6dae9192afe5"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Reprimand - unacceptable professional conduct", DqtSanctionCode = "A4", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("72e48b6a-e781-4bf3-910b-91f2d28f2eaa"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - conviction of a relevant offence - eligible to reapply after specified time", DqtSanctionCode = "A21B", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("950d3eed-bef5-448a-b0f0-bf9c54f2103b"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - conviction of a relevant offence - ineligible to reapply", DqtSanctionCode = "A21A", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("cac68337-3f95-4475-97cf-1381e6b74700"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - serious professional incompetence - Eligible to reapply after specified time", DqtSanctionCode = "A5B", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("c02bdc3a-7a19-4034-aa23-3a23c54e1d34"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - serious professional incompetence - Ineligible to reapply", DqtSanctionCode = "A5A", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("e3658a61-bee2-4df1-9a26-e010681ee310"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - unacceptable professional conduct - Eligible to reapply after specified time", DqtSanctionCode = "A1B", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("fa6bd220-61b0-41fc-9066-421b3b9d7885"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - unacceptable professional conduct - Ineligible to reapply", DqtSanctionCode = "A1A", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("d372fcfa-1c4a-4fed-84c8-4c7885575681"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - conviction of a relevant offence - with conditions", DqtSanctionCode = "A20", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("af65c236-47a6-427b-8e4b-930de6d256f0"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - conviction of a relevant offence - without conditions", DqtSanctionCode = "A19", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("50508749-7a6b-4175-8538-9a1e55692efd"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - serious professional incompetence - with conditions", DqtSanctionCode = "A14", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("a6f51ccc-a19c-4dc2-ba80-ffb7a95ff2ee"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - serious professional incompetence - without conditions", DqtSanctionCode = "A6", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("1a2b06ae-7e9f-4761-b95d-397ca5da4b13"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - unacceptable professional conduct - with conditions", DqtSanctionCode = "A13", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("872d7700-aa6f-435e-b5f9-821fb087962a"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - unacceptable professional conduct - without conditions", DqtSanctionCode = "A2", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("17b4fe26-7468-4702-92e5-785b861cf0fa"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - with conditions - (arising from breach of previous condition(s))", DqtSanctionCode = "A24", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("3c5fc83b-10e1-4a15-83e6-794fce3e0b45"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - without conditions - (arising from breach of previous condition(s))", DqtSanctionCode = "A23", ProhibitionLevel = ProhibitionLevel.Restrict }, - new AlertType { AlertTypeId = Guid.Parse("62715a16-69f8-44f7-90f4-df83cd0c9f16"), AlertCategoryId = Guid.Parse("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a"), Name = "Employers to contact the Secretary of State", DqtSanctionCode = "B4", ProhibitionLevel = ProhibitionLevel.None }, - new AlertType { AlertTypeId = Guid.Parse("eab8b66d-68d0-4cb9-8e4d-bbd245648fb6"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Barring by the Secretary of State", DqtSanctionCode = "B1", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("2c496e3f-00d3-4f0d-81f3-21458fe707b3"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Formerly barred by the Independent Safeguarding Authority", DqtSanctionCode = "G2", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("993daa42-96cb-4621-bd9e-d4b195076bbe"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Formerly on List 99", DqtSanctionCode = "B6", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("a414283f-7d5b-4587-83bf-f6da8c05b8d5"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Interim prohibition by the Secretary of State", DqtSanctionCode = "T2", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("8ef92c14-4b1f-4530-9189-779ad9f3cefd"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibited by an Independent Schools Tribunal or Secretary of State", DqtSanctionCode = "B3", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("50feafbc-5124-4189-b06c-6463c7ebb8a8"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - deregistered by GTC Scotland", DqtSanctionCode = "T3", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("5aa21b8f-2069-43c9-8afd-05b34b02505f"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - refer to GTC Northern Ireland", DqtSanctionCode = "T5", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("a5bd4352-2cec-4417-87a1-4b6b79d033c2"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - refer to the Education Workforce Council, Wales", DqtSanctionCode = "T4", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("ed0cd700-3fb2-4db0-9403-ba57126090ed"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - misconduct", DqtSanctionCode = "T1", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("40794ea8-eda2-40a8-a26a-5f447aae6c99"), AlertCategoryId = Guid.Parse("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), Name = "A possible matching record was found. Please contact the DBS before employing this person", DqtSanctionCode = "G1", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("38db7946-2dbf-408e-bc48-1625829e7dfe"), AlertCategoryId = Guid.Parse("cbf7633f-3904-407d-8371-42a473fa641f"), Name = "Restricted by the Secretary of State - Not Permitted to work as teacher", DqtSanctionCode = "B2B", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("18e04dcb-fb86-4b05-8d5d-ff9c5da738dd"), AlertCategoryId = Guid.Parse("cbf7633f-3904-407d-8371-42a473fa641f"), Name = "Restricted by the Secretary of State - Permitted to work as teacher", DqtSanctionCode = "B2A", ProhibitionLevel = ProhibitionLevel.Teaching }, - new AlertType { AlertTypeId = Guid.Parse("241eeb78-fac7-4c77-8059-c12e93dc2fae"), AlertCategoryId = Guid.Parse("38df5a00-94ab-486f-8905-d5b2eac04000"), Name = "Section 128 barring direction", DqtSanctionCode = "T7", ProhibitionLevel = ProhibitionLevel.LeadershipPositions }, - new AlertType { AlertTypeId = Guid.Parse("7924fe90-483c-49f8-84fc-674feddba848"), AlertCategoryId = Guid.Parse("227b75e5-bb98-496c-8860-1baea37aa5c6"), Name = "Secretary of State decision- no prohibition", DqtSanctionCode = "T6", ProhibitionLevel = ProhibitionLevel.None }); + new AlertType { AlertTypeId = Guid.Parse("2ca98658-1d5b-49d5-b05f-cc08c8b8502c"), AlertCategoryId = Guid.Parse("ee78d44d-abf8-44a9-b22b-87a821f8d3c9"), Name = "Teacher sanctioned in other EEA member state", DqtSanctionCode = "T8", ProhibitionLevel = ProhibitionLevel.Notify, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("9fafaa80-f9f8-44a0-b7b3-cffedcbe0298"), AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Failed induction", DqtSanctionCode = "C2", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("651e1f56-3135-4961-bd7e-3f7b2c75cb04"), AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Prohibited by the Secretary of State - failed probation", DqtSanctionCode = "C1", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("5ea8bb68-4774-4ad8-b635-213a0cdda4c3"), AlertCategoryId = Guid.Parse("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), Name = "Restricted by the Secretary of State - failed probation - permitted to carry out specified work for a period equal in length to a statutory induction period only", DqtSanctionCode = "C3", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("ae3e385d-03f8-4f12-9ce2-006afe827d23"), AlertCategoryId = Guid.Parse("768c9eb4-355b-4491-bb20-67eb59a97579"), Name = "FOR INTERNAL INFORMATION ONLY - see alert details", DqtSanctionCode = "T9", ProhibitionLevel = ProhibitionLevel.None, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("a6fc9f2e-8923-4163-978e-93bd901d146f"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Conditional Registration Order - conviction of a relevant offence", DqtSanctionCode = "A18", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("1ebd1620-293d-4169-ba78-0b41a6413ad9"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Conditional Registration Order - serious professional incompetence", DqtSanctionCode = "A7", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("3499860a-a0fb-43e3-878e-c226d14150b0"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Conditional Registration Order - unacceptable professional conduct", DqtSanctionCode = "A3", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("552ee226-a3a9-4dc3-8d04-0b7e4f641b51"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "For internal information only - historic GTC finding of unsuitable for registration", DqtSanctionCode = "A15", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("33e00e46-6513-4136-adfd-1352cf34d8ec"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - breach of condition(s)", DqtSanctionCode = "A22", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("0740f9eb-ece3-4394-a230-453da224d337"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - conviction for a relevant offence", DqtSanctionCode = "A16", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("b6c8d8f1-723e-49a5-9551-25805e3e29b9"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - serious professional incompetence", DqtSanctionCode = "A12", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("78f88de2-9ec1-41b8-948a-33bdff223206"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "No Sanction - unacceptable professional conduct", DqtSanctionCode = "A11", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("fcff87d6-88f5-4fc5-ac81-5350b4fdd9e1"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Reprimand - conviction of a relevant offence", DqtSanctionCode = "A17", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("3f7de5fd-05a8-404f-a97c-428f54e81322"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Reprimand - serious professional incompetence", DqtSanctionCode = "A8", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("0ae8d4b6-ec9b-47ca-9338-6dae9192afe5"), AlertCategoryId = Guid.Parse("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), Name = "Reprimand - unacceptable professional conduct", DqtSanctionCode = "A4", ProhibitionLevel = ProhibitionLevel.None, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("72e48b6a-e781-4bf3-910b-91f2d28f2eaa"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - conviction of a relevant offence - eligible to reapply after specified time", DqtSanctionCode = "A21B", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("950d3eed-bef5-448a-b0f0-bf9c54f2103b"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - conviction of a relevant offence - ineligible to reapply", DqtSanctionCode = "A21A", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("cac68337-3f95-4475-97cf-1381e6b74700"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - serious professional incompetence - Eligible to reapply after specified time", DqtSanctionCode = "A5B", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("c02bdc3a-7a19-4034-aa23-3a23c54e1d34"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - serious professional incompetence - Ineligible to reapply", DqtSanctionCode = "A5A", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("e3658a61-bee2-4df1-9a26-e010681ee310"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - unacceptable professional conduct - Eligible to reapply after specified time", DqtSanctionCode = "A1B", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("fa6bd220-61b0-41fc-9066-421b3b9d7885"), AlertCategoryId = Guid.Parse("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), Name = "Prohibition Order - unacceptable professional conduct - Ineligible to reapply", DqtSanctionCode = "A1A", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("d372fcfa-1c4a-4fed-84c8-4c7885575681"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - conviction of a relevant offence - with conditions", DqtSanctionCode = "A20", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("af65c236-47a6-427b-8e4b-930de6d256f0"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - conviction of a relevant offence - without conditions", DqtSanctionCode = "A19", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("50508749-7a6b-4175-8538-9a1e55692efd"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - serious professional incompetence - with conditions", DqtSanctionCode = "A14", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("a6f51ccc-a19c-4dc2-ba80-ffb7a95ff2ee"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - serious professional incompetence - without conditions", DqtSanctionCode = "A6", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("1a2b06ae-7e9f-4761-b95d-397ca5da4b13"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - unacceptable professional conduct - with conditions", DqtSanctionCode = "A13", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("872d7700-aa6f-435e-b5f9-821fb087962a"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - unacceptable professional conduct - without conditions", DqtSanctionCode = "A2", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("17b4fe26-7468-4702-92e5-785b861cf0fa"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - with conditions - (arising from breach of previous condition(s))", DqtSanctionCode = "A24", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("3c5fc83b-10e1-4a15-83e6-794fce3e0b45"), AlertCategoryId = Guid.Parse("790410c1-b884-4cdd-8db9-64a042ab54ae"), Name = "Suspension order - without conditions - (arising from breach of previous condition(s))", DqtSanctionCode = "A23", ProhibitionLevel = ProhibitionLevel.Restrict, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("eab8b66d-68d0-4cb9-8e4d-bbd245648fb6"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Barring by the Secretary of State", DqtSanctionCode = "B1", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("2c496e3f-00d3-4f0d-81f3-21458fe707b3"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Formerly barred by the Independent Safeguarding Authority", DqtSanctionCode = "G2", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("993daa42-96cb-4621-bd9e-d4b195076bbe"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Formerly on List 99", DqtSanctionCode = "B6", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("a414283f-7d5b-4587-83bf-f6da8c05b8d5"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Interim prohibition by the Secretary of State", DqtSanctionCode = "T2", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("8ef92c14-4b1f-4530-9189-779ad9f3cefd"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibited by an Independent Schools Tribunal or Secretary of State", DqtSanctionCode = "B3", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("50feafbc-5124-4189-b06c-6463c7ebb8a8"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - deregistered by GTC Scotland", DqtSanctionCode = "T3", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("5aa21b8f-2069-43c9-8afd-05b34b02505f"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - refer to GTC Northern Ireland", DqtSanctionCode = "T5", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("a5bd4352-2cec-4417-87a1-4b6b79d033c2"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - refer to the Education Workforce Council, Wales", DqtSanctionCode = "T4", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("ed0cd700-3fb2-4db0-9403-ba57126090ed"), AlertCategoryId = Guid.Parse("b2b19019-b165-47a3-8745-3297ff152581"), Name = "Prohibition by the Secretary of State - misconduct", DqtSanctionCode = "T1", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("40794ea8-eda2-40a8-a26a-5f447aae6c99"), AlertCategoryId = Guid.Parse("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), Name = "A possible matching record was found. Please contact the DBS before employing this person", DqtSanctionCode = "G1", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("38db7946-2dbf-408e-bc48-1625829e7dfe"), AlertCategoryId = Guid.Parse("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), Name = "Restricted by the Secretary of State - Not Permitted to work as teacher", DqtSanctionCode = "B2B", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("18e04dcb-fb86-4b05-8d5d-ff9c5da738dd"), AlertCategoryId = Guid.Parse("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), Name = "Restricted by the Secretary of State - Permitted to work as teacher", DqtSanctionCode = "B2A", ProhibitionLevel = ProhibitionLevel.Teaching, IsActive = false }, + new AlertType { AlertTypeId = Guid.Parse("241eeb78-fac7-4c77-8059-c12e93dc2fae"), AlertCategoryId = Guid.Parse("38df5a00-94ab-486f-8905-d5b2eac04000"), Name = "Section 128 barring direction", DqtSanctionCode = "T7", ProhibitionLevel = ProhibitionLevel.LeadershipPositions, IsActive = true }, + new AlertType { AlertTypeId = Guid.Parse("7924fe90-483c-49f8-84fc-674feddba848"), AlertCategoryId = Guid.Parse("227b75e5-bb98-496c-8860-1baea37aa5c6"), Name = "Secretary of State decision- no prohibition", DqtSanctionCode = "T6", ProhibitionLevel = ProhibitionLevel.None, IsActive = true }); } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/20240912133630_AlertTypeIsActive.Designer.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/20240912133630_AlertTypeIsActive.Designer.cs new file mode 100644 index 0000000000..7a7c0b3744 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/20240912133630_AlertTypeIsActive.Designer.cs @@ -0,0 +1,2860 @@ +// +using System; +using System.Collections.Generic; +using System.Text.Json; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using TeachingRecordSystem.Core.DataStore.Postgres; + +#nullable disable + +namespace TeachingRecordSystem.Core.DataStore.Postgres.Migrations +{ + [DbContext(typeof(TrsDbContext))] + [Migration("20240912133630_AlertTypeIsActive")] + partial class AlertTypeIsActive + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ApplicationType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("application_type"); + + b.Property("ClientId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasColumnType("text") + .HasColumnName("client_secret"); + + b.Property("ClientType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("client_type"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("ConsentType") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("consent_type"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("DisplayNames") + .HasColumnType("text") + .HasColumnName("display_names"); + + b.Property("JsonWebKeySet") + .HasColumnType("text") + .HasColumnName("json_web_key_set"); + + b.Property("Permissions") + .HasColumnType("text") + .HasColumnName("permissions"); + + b.Property("PostLogoutRedirectUris") + .HasColumnType("text") + .HasColumnName("post_logout_redirect_uris"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("RedirectUris") + .HasColumnType("text") + .HasColumnName("redirect_uris"); + + b.Property("Requirements") + .HasColumnType("text") + .HasColumnName("requirements"); + + b.Property("Settings") + .HasColumnType("text") + .HasColumnName("settings"); + + b.HasKey("Id") + .HasName("pk_oidc_applications"); + + b.HasIndex("ClientId") + .IsUnique() + .HasDatabaseName("ix_oidc_applications_client_id"); + + b.ToTable("oidc_applications", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ApplicationId") + .HasColumnType("uuid") + .HasColumnName("application_id"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_date"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("Scopes") + .HasColumnType("text") + .HasColumnName("scopes"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("status"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)") + .HasColumnName("subject"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_oidc_authorizations"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type") + .HasDatabaseName("ix_oidc_authorizations_application_id_status_subject_type"); + + b.ToTable("oidc_authorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreScope", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Descriptions") + .HasColumnType("text") + .HasColumnName("descriptions"); + + b.Property("DisplayName") + .HasColumnType("text") + .HasColumnName("display_name"); + + b.Property("DisplayNames") + .HasColumnType("text") + .HasColumnName("display_names"); + + b.Property("Name") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("Resources") + .HasColumnType("text") + .HasColumnName("resources"); + + b.HasKey("Id") + .HasName("pk_oidc_scopes"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_oidc_scopes_name"); + + b.ToTable("oidc_scopes", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("id"); + + b.Property("ApplicationId") + .HasColumnType("uuid") + .HasColumnName("application_id"); + + b.Property("AuthorizationId") + .HasColumnType("uuid") + .HasColumnName("authorization_id"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("concurrency_token"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_date"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiration_date"); + + b.Property("Payload") + .HasColumnType("text") + .HasColumnName("payload"); + + b.Property("Properties") + .HasColumnType("text") + .HasColumnName("properties"); + + b.Property("RedemptionDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("redemption_date"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("reference_id"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("status"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)") + .HasColumnName("subject"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_oidc_tokens"); + + b.HasIndex("ReferenceId") + .IsUnique() + .HasDatabaseName("ix_oidc_tokens_reference_id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type") + .HasDatabaseName("ix_oidc_tokens_application_id_status_subject_type"); + + b.ToTable("oidc_tokens", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Alert", b => + { + b.Property("AlertId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("alert_id"); + + b.Property("AlertTypeId") + .HasColumnType("uuid") + .HasColumnName("alert_type_id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_on"); + + b.Property("Details") + .HasColumnType("text") + .HasColumnName("details"); + + b.Property("EndDate") + .HasColumnType("date") + .HasColumnName("end_date"); + + b.Property("ExternalLink") + .HasColumnType("text") + .HasColumnName("external_link"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("StartDate") + .HasColumnType("date") + .HasColumnName("start_date"); + + b.Property("UpdatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on"); + + b.HasKey("AlertId") + .HasName("pk_alerts"); + + b.HasIndex("AlertTypeId") + .HasDatabaseName("ix_alerts_alert_type_id"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_alerts_person_id"); + + b.ToTable("alerts", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertCategory", b => + { + b.Property("AlertCategoryId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("alert_category_id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name") + .UseCollation("case_insensitive"); + + b.HasKey("AlertCategoryId") + .HasName("pk_alert_categories"); + + b.ToTable("alert_categories", (string)null); + + b.HasData( + new + { + AlertCategoryId = new Guid("ee78d44d-abf8-44a9-b22b-87a821f8d3c9"), + Name = "EEA Decision" + }, + new + { + AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), + Name = "Failed induction" + }, + new + { + AlertCategoryId = new Guid("768c9eb4-355b-4491-bb20-67eb59a97579"), + Name = "Flag" + }, + new + { + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + Name = "GTC Decision" + }, + new + { + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + Name = "GTC Prohibition from teaching" + }, + new + { + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + Name = "GTC Restriction" + }, + new + { + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + Name = "Prohibition from teaching" + }, + new + { + AlertCategoryId = new Guid("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), + Name = "Restricted/DBS" + }, + new + { + AlertCategoryId = new Guid("cbf7633f-3904-407d-8371-42a473fa641f"), + Name = "Restriction" + }, + new + { + AlertCategoryId = new Guid("38df5a00-94ab-486f-8905-d5b2eac04000"), + Name = "Section 128 (SoS)" + }, + new + { + AlertCategoryId = new Guid("227b75e5-bb98-496c-8860-1baea37aa5c6"), + Name = "TRA Decision (SoS)" + }, + new + { + AlertCategoryId = new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), + Name = "SoS Restriction" + }); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertType", b => + { + b.Property("AlertTypeId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("alert_type_id"); + + b.Property("AlertCategoryId") + .HasColumnType("uuid") + .HasColumnName("alert_category_id"); + + b.Property("DqtSanctionCode") + .HasMaxLength(5) + .HasColumnType("character varying(5)") + .HasColumnName("dqt_sanction_code") + .UseCollation("case_insensitive"); + + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("is_active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name") + .UseCollation("case_insensitive"); + + b.Property("ProhibitionLevel") + .HasColumnType("integer") + .HasColumnName("prohibition_level"); + + b.HasKey("AlertTypeId") + .HasName("pk_alert_types"); + + b.HasIndex("AlertCategoryId") + .HasDatabaseName("ix_alert_types_alert_category_id"); + + b.ToTable("alert_types", (string)null); + + b.HasData( + new + { + AlertTypeId = new Guid("2ca98658-1d5b-49d5-b05f-cc08c8b8502c"), + AlertCategoryId = new Guid("ee78d44d-abf8-44a9-b22b-87a821f8d3c9"), + DqtSanctionCode = "T8", + IsActive = true, + Name = "Teacher sanctioned in other EEA member state", + ProhibitionLevel = 3 + }, + new + { + AlertTypeId = new Guid("9fafaa80-f9f8-44a0-b7b3-cffedcbe0298"), + AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), + DqtSanctionCode = "C2", + IsActive = true, + Name = "Failed induction", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("651e1f56-3135-4961-bd7e-3f7b2c75cb04"), + AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), + DqtSanctionCode = "C1", + IsActive = false, + Name = "Prohibited by the Secretary of State - failed probation", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("5ea8bb68-4774-4ad8-b635-213a0cdda4c3"), + AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), + DqtSanctionCode = "C3", + IsActive = false, + Name = "Restricted by the Secretary of State - failed probation - permitted to carry out specified work for a period equal in length to a statutory induction period only", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("ae3e385d-03f8-4f12-9ce2-006afe827d23"), + AlertCategoryId = new Guid("768c9eb4-355b-4491-bb20-67eb59a97579"), + DqtSanctionCode = "T9", + IsActive = true, + Name = "FOR INTERNAL INFORMATION ONLY - see alert details", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("a6fc9f2e-8923-4163-978e-93bd901d146f"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A18", + IsActive = false, + Name = "Conditional Registration Order - conviction of a relevant offence", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("1ebd1620-293d-4169-ba78-0b41a6413ad9"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A7", + IsActive = false, + Name = "Conditional Registration Order - serious professional incompetence", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("3499860a-a0fb-43e3-878e-c226d14150b0"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A3", + IsActive = false, + Name = "Conditional Registration Order - unacceptable professional conduct", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("552ee226-a3a9-4dc3-8d04-0b7e4f641b51"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A15", + IsActive = false, + Name = "For internal information only - historic GTC finding of unsuitable for registration", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("33e00e46-6513-4136-adfd-1352cf34d8ec"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A22", + IsActive = false, + Name = "No Sanction - breach of condition(s)", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("0740f9eb-ece3-4394-a230-453da224d337"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A16", + IsActive = false, + Name = "No Sanction - conviction for a relevant offence", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("b6c8d8f1-723e-49a5-9551-25805e3e29b9"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A12", + IsActive = false, + Name = "No Sanction - serious professional incompetence", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("78f88de2-9ec1-41b8-948a-33bdff223206"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A11", + IsActive = false, + Name = "No Sanction - unacceptable professional conduct", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("fcff87d6-88f5-4fc5-ac81-5350b4fdd9e1"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A17", + IsActive = false, + Name = "Reprimand - conviction of a relevant offence", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("3f7de5fd-05a8-404f-a97c-428f54e81322"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A8", + IsActive = false, + Name = "Reprimand - serious professional incompetence", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("0ae8d4b6-ec9b-47ca-9338-6dae9192afe5"), + AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), + DqtSanctionCode = "A4", + IsActive = false, + Name = "Reprimand - unacceptable professional conduct", + ProhibitionLevel = 0 + }, + new + { + AlertTypeId = new Guid("72e48b6a-e781-4bf3-910b-91f2d28f2eaa"), + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + DqtSanctionCode = "A21B", + IsActive = false, + Name = "Prohibition Order - conviction of a relevant offence - eligible to reapply after specified time", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("950d3eed-bef5-448a-b0f0-bf9c54f2103b"), + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + DqtSanctionCode = "A21A", + IsActive = false, + Name = "Prohibition Order - conviction of a relevant offence - ineligible to reapply", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("cac68337-3f95-4475-97cf-1381e6b74700"), + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + DqtSanctionCode = "A5B", + IsActive = false, + Name = "Prohibition Order - serious professional incompetence - Eligible to reapply after specified time", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("c02bdc3a-7a19-4034-aa23-3a23c54e1d34"), + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + DqtSanctionCode = "A5A", + IsActive = false, + Name = "Prohibition Order - serious professional incompetence - Ineligible to reapply", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("e3658a61-bee2-4df1-9a26-e010681ee310"), + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + DqtSanctionCode = "A1B", + IsActive = false, + Name = "Prohibition Order - unacceptable professional conduct - Eligible to reapply after specified time", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("fa6bd220-61b0-41fc-9066-421b3b9d7885"), + AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), + DqtSanctionCode = "A1A", + IsActive = false, + Name = "Prohibition Order - unacceptable professional conduct - Ineligible to reapply", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("d372fcfa-1c4a-4fed-84c8-4c7885575681"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A20", + IsActive = false, + Name = "Suspension order - conviction of a relevant offence - with conditions", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("af65c236-47a6-427b-8e4b-930de6d256f0"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A19", + IsActive = false, + Name = "Suspension order - conviction of a relevant offence - without conditions", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("50508749-7a6b-4175-8538-9a1e55692efd"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A14", + IsActive = false, + Name = "Suspension order - serious professional incompetence - with conditions", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("a6f51ccc-a19c-4dc2-ba80-ffb7a95ff2ee"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A6", + IsActive = false, + Name = "Suspension order - serious professional incompetence - without conditions", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("1a2b06ae-7e9f-4761-b95d-397ca5da4b13"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A13", + IsActive = false, + Name = "Suspension order - unacceptable professional conduct - with conditions", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("872d7700-aa6f-435e-b5f9-821fb087962a"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A2", + IsActive = false, + Name = "Suspension order - unacceptable professional conduct - without conditions", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("17b4fe26-7468-4702-92e5-785b861cf0fa"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A24", + IsActive = false, + Name = "Suspension order - with conditions - (arising from breach of previous condition(s))", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("3c5fc83b-10e1-4a15-83e6-794fce3e0b45"), + AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), + DqtSanctionCode = "A23", + IsActive = false, + Name = "Suspension order - without conditions - (arising from breach of previous condition(s))", + ProhibitionLevel = 2 + }, + new + { + AlertTypeId = new Guid("eab8b66d-68d0-4cb9-8e4d-bbd245648fb6"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "B1", + IsActive = false, + Name = "Barring by the Secretary of State", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("2c496e3f-00d3-4f0d-81f3-21458fe707b3"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "G2", + IsActive = false, + Name = "Formerly barred by the Independent Safeguarding Authority", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("993daa42-96cb-4621-bd9e-d4b195076bbe"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "B6", + IsActive = false, + Name = "Formerly on List 99", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("a414283f-7d5b-4587-83bf-f6da8c05b8d5"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "T2", + IsActive = true, + Name = "Interim prohibition by the Secretary of State", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("8ef92c14-4b1f-4530-9189-779ad9f3cefd"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "B3", + IsActive = false, + Name = "Prohibited by an Independent Schools Tribunal or Secretary of State", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("50feafbc-5124-4189-b06c-6463c7ebb8a8"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "T3", + IsActive = true, + Name = "Prohibition by the Secretary of State - deregistered by GTC Scotland", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("5aa21b8f-2069-43c9-8afd-05b34b02505f"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "T5", + IsActive = true, + Name = "Prohibition by the Secretary of State - refer to GTC Northern Ireland", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("a5bd4352-2cec-4417-87a1-4b6b79d033c2"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "T4", + IsActive = true, + Name = "Prohibition by the Secretary of State - refer to the Education Workforce Council, Wales", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("ed0cd700-3fb2-4db0-9403-ba57126090ed"), + AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), + DqtSanctionCode = "T1", + IsActive = true, + Name = "Prohibition by the Secretary of State - misconduct", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("40794ea8-eda2-40a8-a26a-5f447aae6c99"), + AlertCategoryId = new Guid("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), + DqtSanctionCode = "G1", + IsActive = true, + Name = "A possible matching record was found. Please contact the DBS before employing this person", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("38db7946-2dbf-408e-bc48-1625829e7dfe"), + AlertCategoryId = new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), + DqtSanctionCode = "B2B", + IsActive = false, + Name = "Restricted by the Secretary of State - Not Permitted to work as teacher", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("18e04dcb-fb86-4b05-8d5d-ff9c5da738dd"), + AlertCategoryId = new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), + DqtSanctionCode = "B2A", + IsActive = false, + Name = "Restricted by the Secretary of State - Permitted to work as teacher", + ProhibitionLevel = 1 + }, + new + { + AlertTypeId = new Guid("241eeb78-fac7-4c77-8059-c12e93dc2fae"), + AlertCategoryId = new Guid("38df5a00-94ab-486f-8905-d5b2eac04000"), + DqtSanctionCode = "T7", + IsActive = true, + Name = "Section 128 barring direction", + ProhibitionLevel = 4 + }, + new + { + AlertTypeId = new Guid("7924fe90-483c-49f8-84fc-674feddba848"), + AlertCategoryId = new Guid("227b75e5-bb98-496c-8860-1baea37aa5c6"), + DqtSanctionCode = "T6", + IsActive = true, + Name = "Secretary of State decision- no prohibition", + ProhibitionLevel = 0 + }); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.ApiKey", b => + { + b.Property("ApiKeyId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("api_key_id"); + + b.Property("ApplicationUserId") + .HasColumnType("uuid") + .HasColumnName("application_user_id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("Expires") + .HasColumnType("timestamp with time zone") + .HasColumnName("expires"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("key"); + + b.Property("UpdatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on"); + + b.HasKey("ApiKeyId") + .HasName("pk_api_keys"); + + b.HasIndex("ApplicationUserId") + .HasDatabaseName("ix_api_keys_application_user_id"); + + b.HasIndex("Key") + .IsUnique() + .HasDatabaseName("ix_api_keys_key"); + + b.ToTable("api_keys", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EntityChangesJournal", b => + { + b.Property("Key") + .HasColumnType("text") + .HasColumnName("key"); + + b.Property("EntityLogicalName") + .HasColumnType("text") + .HasColumnName("entity_logical_name"); + + b.Property("DataToken") + .HasColumnType("text") + .HasColumnName("data_token"); + + b.Property("LastUpdated") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_updated"); + + b.Property("LastUpdatedBy") + .HasColumnType("text") + .HasColumnName("last_updated_by"); + + b.Property("NextQueryPageNumber") + .HasColumnType("integer") + .HasColumnName("next_query_page_number"); + + b.Property("NextQueryPageSize") + .HasColumnType("integer") + .HasColumnName("next_query_page_size"); + + b.Property("NextQueryPagingCookie") + .HasColumnType("text") + .HasColumnName("next_query_paging_cookie"); + + b.HasKey("Key", "EntityLogicalName") + .HasName("pk_entity_changes_journals"); + + b.ToTable("entity_changes_journals", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Establishment", b => + { + b.Property("EstablishmentId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("establishment_id"); + + b.Property("Address3") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("address3") + .UseCollation("case_insensitive"); + + b.Property("County") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("county") + .UseCollation("case_insensitive"); + + b.Property("EstablishmentName") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)") + .HasColumnName("establishment_name") + .UseCollation("case_insensitive"); + + b.Property("EstablishmentNumber") + .HasMaxLength(4) + .HasColumnType("character(4)") + .HasColumnName("establishment_number") + .IsFixedLength(); + + b.Property("EstablishmentSourceId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(1) + .HasColumnName("establishment_source_id"); + + b.Property("EstablishmentStatusCode") + .HasColumnType("integer") + .HasColumnName("establishment_status_code"); + + b.Property("EstablishmentStatusName") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("establishment_status_name"); + + b.Property("EstablishmentTypeCode") + .HasMaxLength(3) + .HasColumnType("character varying(3)") + .HasColumnName("establishment_type_code"); + + b.Property("EstablishmentTypeGroupCode") + .HasColumnType("integer") + .HasColumnName("establishment_type_group_code"); + + b.Property("EstablishmentTypeGroupName") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("establishment_type_group_name"); + + b.Property("EstablishmentTypeName") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("establishment_type_name") + .UseCollation("case_insensitive"); + + b.Property("LaCode") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character(3)") + .HasColumnName("la_code") + .IsFixedLength(); + + b.Property("LaName") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("la_name") + .UseCollation("case_insensitive"); + + b.Property("Locality") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("locality") + .UseCollation("case_insensitive"); + + b.Property("Postcode") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("postcode") + .UseCollation("case_insensitive"); + + b.Property("Street") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("street") + .UseCollation("case_insensitive"); + + b.Property("Town") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("town") + .UseCollation("case_insensitive"); + + b.Property("Urn") + .HasMaxLength(6) + .HasColumnType("integer") + .HasColumnName("urn") + .IsFixedLength(); + + b.HasKey("EstablishmentId") + .HasName("pk_establishments"); + + b.HasIndex("EstablishmentSourceId") + .HasDatabaseName("ix_establishment_establishment_source_id"); + + b.HasIndex("Urn") + .HasDatabaseName("ix_establishment_urn"); + + b.HasIndex("LaCode", "EstablishmentNumber") + .HasDatabaseName("ix_establishment_la_code_establishment_number"); + + b.ToTable("establishments", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EstablishmentSource", b => + { + b.Property("EstablishmentSourceId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("establishment_source_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("EstablishmentSourceId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("name") + .UseCollation("case_insensitive"); + + b.HasKey("EstablishmentSourceId") + .HasName("pk_establishment_sources"); + + b.ToTable("establishment_sources", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Event", b => + { + b.Property("EventId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("event_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("EventName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("event_name"); + + b.Property("Inserted") + .HasColumnType("timestamp with time zone") + .HasColumnName("inserted"); + + b.Property("Key") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("key"); + + b.Property("Payload") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("payload"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("Published") + .HasColumnType("boolean") + .HasColumnName("published"); + + b.HasKey("EventId") + .HasName("pk_events"); + + b.HasIndex("Key") + .IsUnique() + .HasDatabaseName("ix_events_key") + .HasFilter("key is not null"); + + b.HasIndex("Payload") + .HasDatabaseName("ix_events_payload"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Payload"), "gin"); + + b.HasIndex("PersonId", "EventName") + .HasDatabaseName("ix_events_person_id_event_name") + .HasFilter("person_id is not null"); + + NpgsqlIndexBuilderExtensions.IncludeProperties(b.HasIndex("PersonId", "EventName"), new[] { "Payload" }); + + b.ToTable("events", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EytsAwardedEmailsJob", b => + { + b.Property("EytsAwardedEmailsJobId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("eyts_awarded_emails_job_id"); + + b.Property("AwardedToUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("awarded_to_utc"); + + b.Property("ExecutedUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("executed_utc"); + + b.HasKey("EytsAwardedEmailsJobId") + .HasName("pk_eyts_awarded_emails_jobs"); + + b.HasIndex("ExecutedUtc") + .HasDatabaseName("ix_eyts_awarded_emails_jobs_executed_utc"); + + b.ToTable("eyts_awarded_emails_jobs", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EytsAwardedEmailsJobItem", b => + { + b.Property("EytsAwardedEmailsJobId") + .HasColumnType("uuid") + .HasColumnName("eyts_awarded_emails_job_id"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("EmailAddress") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("email_address"); + + b.Property("EmailSent") + .HasColumnType("boolean") + .HasColumnName("email_sent"); + + b.Property("Personalization") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("personalization"); + + b.Property("Trn") + .IsRequired() + .HasMaxLength(7) + .HasColumnType("character(7)") + .HasColumnName("trn") + .IsFixedLength(); + + b.HasKey("EytsAwardedEmailsJobId", "PersonId") + .HasName("pk_eyts_awarded_emails_job_items"); + + b.HasIndex("Personalization") + .HasDatabaseName("ix_eyts_awarded_emails_job_items_personalization"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Personalization"), "gin"); + + b.ToTable("eyts_awarded_emails_job_items", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InductionCompletedEmailsJob", b => + { + b.Property("InductionCompletedEmailsJobId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("induction_completed_emails_job_id"); + + b.Property("AwardedToUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("awarded_to_utc"); + + b.Property("ExecutedUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("executed_utc"); + + b.HasKey("InductionCompletedEmailsJobId") + .HasName("pk_induction_completed_emails_jobs"); + + b.HasIndex("ExecutedUtc") + .HasDatabaseName("ix_induction_completed_emails_jobs_executed_utc"); + + b.ToTable("induction_completed_emails_jobs", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InductionCompletedEmailsJobItem", b => + { + b.Property("InductionCompletedEmailsJobId") + .HasColumnType("uuid") + .HasColumnName("induction_completed_emails_job_id"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("EmailAddress") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("email_address"); + + b.Property("EmailSent") + .HasColumnType("boolean") + .HasColumnName("email_sent"); + + b.Property("Personalization") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("personalization"); + + b.Property("Trn") + .IsRequired() + .HasMaxLength(7) + .HasColumnType("character(7)") + .HasColumnName("trn") + .IsFixedLength(); + + b.HasKey("InductionCompletedEmailsJobId", "PersonId") + .HasName("pk_induction_completed_emails_job_items"); + + b.HasIndex("Personalization") + .HasDatabaseName("ix_induction_completed_emails_job_items_personalization"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Personalization"), "gin"); + + b.ToTable("induction_completed_emails_job_items", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InternationalQtsAwardedEmailsJob", b => + { + b.Property("InternationalQtsAwardedEmailsJobId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("international_qts_awarded_emails_job_id"); + + b.Property("AwardedToUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("awarded_to_utc"); + + b.Property("ExecutedUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("executed_utc"); + + b.HasKey("InternationalQtsAwardedEmailsJobId") + .HasName("pk_international_qts_awarded_emails_jobs"); + + b.HasIndex("ExecutedUtc") + .HasDatabaseName("ix_international_qts_awarded_emails_jobs_executed_utc"); + + b.ToTable("international_qts_awarded_emails_jobs", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InternationalQtsAwardedEmailsJobItem", b => + { + b.Property("InternationalQtsAwardedEmailsJobId") + .HasColumnType("uuid") + .HasColumnName("international_qts_awarded_emails_job_id"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("EmailAddress") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("email_address"); + + b.Property("EmailSent") + .HasColumnType("boolean") + .HasColumnName("email_sent"); + + b.Property("Personalization") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("personalization"); + + b.Property("Trn") + .IsRequired() + .HasMaxLength(7) + .HasColumnType("character(7)") + .HasColumnName("trn") + .IsFixedLength(); + + b.HasKey("InternationalQtsAwardedEmailsJobId", "PersonId") + .HasName("pk_international_qts_awarded_emails_job_items"); + + b.HasIndex("Personalization") + .HasDatabaseName("ix_international_qts_awarded_emails_job_items_personalization"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Personalization"), "gin"); + + b.ToTable("international_qts_awarded_emails_job_items", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.JourneyState", b => + { + b.Property("InstanceId") + .HasMaxLength(300) + .HasColumnType("character varying(300)") + .HasColumnName("instance_id"); + + b.Property("Completed") + .HasColumnType("timestamp with time zone") + .HasColumnName("completed"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("State") + .IsRequired() + .HasColumnType("text") + .HasColumnName("state"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated"); + + b.Property("UserId") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("user_id"); + + b.HasKey("InstanceId") + .HasName("pk_journey_states"); + + b.ToTable("journey_states", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.MandatoryQualificationProvider", b => + { + b.Property("MandatoryQualificationProviderId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("mandatory_qualification_provider_id"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name"); + + b.HasKey("MandatoryQualificationProviderId") + .HasName("pk_mandatory_qualification_providers"); + + b.ToTable("mandatory_qualification_providers", (string)null); + + b.HasData( + new + { + MandatoryQualificationProviderId = new Guid("e28ea41d-408d-4c89-90cc-8b9b04ac68f5"), + Name = "University of Birmingham" + }, + new + { + MandatoryQualificationProviderId = new Guid("89f9a1aa-3d68-4985-a4ce-403b6044c18c"), + Name = "University of Leeds" + }, + new + { + MandatoryQualificationProviderId = new Guid("aa5c300e-3b7c-456c-8183-3520b3d55dca"), + Name = "University of Manchester" + }, + new + { + MandatoryQualificationProviderId = new Guid("f417e73e-e2ad-40eb-85e3-55865be7f6be"), + Name = "Mary Hare School / University of Hertfordshire" + }, + new + { + MandatoryQualificationProviderId = new Guid("fbf22e04-b274-4c80-aba8-79fb6a7a32ce"), + Name = "University of Edinburgh" + }, + new + { + MandatoryQualificationProviderId = new Guid("26204149-349c-4ad6-9466-bb9b83723eae"), + Name = "Liverpool John Moores University" + }, + new + { + MandatoryQualificationProviderId = new Guid("0c30f666-647c-4ea8-8883-0fc6010b56be"), + Name = "University of Oxford/Oxford Polytechnic" + }, + new + { + MandatoryQualificationProviderId = new Guid("d0e6d54c-5e90-438a-945d-f97388c2b352"), + Name = "University of Cambridge" + }, + new + { + MandatoryQualificationProviderId = new Guid("aec32252-ef25-452e-a358-34a04e03369c"), + Name = "University of Newcastle-upon-Tyne" + }, + new + { + MandatoryQualificationProviderId = new Guid("d9ee7054-7fde-4cfd-9a5e-4b99511d1b3d"), + Name = "University of Plymouth" + }, + new + { + MandatoryQualificationProviderId = new Guid("707d58ca-1953-413b-9a46-41e9b0be885e"), + Name = "University of Hertfordshire" + }, + new + { + MandatoryQualificationProviderId = new Guid("3fc648a7-18e4-49e7-8a4b-1612616b72d5"), + Name = "University of London" + }, + new + { + MandatoryQualificationProviderId = new Guid("374dceb8-8224-45b8-b7dc-a6b0282b1065"), + Name = "Bristol Polytechnic" + }, + new + { + MandatoryQualificationProviderId = new Guid("d4fc958b-21de-47ec-9f03-36ae237a1b11"), + Name = "University College, Swansea" + }); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.NameSynonyms", b => + { + b.Property("NameSynonymsId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("name_synonyms_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("NameSynonymsId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("name") + .UseCollation("case_insensitive"); + + b.Property("Synonyms") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("synonyms") + .UseCollation("case_insensitive"); + + b.HasKey("NameSynonymsId") + .HasName("pk_name_synonyms"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_name_synonyms_name"); + + b.ToTable("name_synonyms", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.OneLoginUser", b => + { + b.Property("Subject") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("subject"); + + b.Property("Email") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("email"); + + b.Property("FirstOneLoginSignIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("first_one_login_sign_in"); + + b.Property("FirstSignIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("first_sign_in"); + + b.Property("LastCoreIdentityVc") + .HasColumnType("jsonb") + .HasColumnName("last_core_identity_vc"); + + b.Property("LastOneLoginSignIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_one_login_sign_in"); + + b.Property("LastSignIn") + .HasColumnType("timestamp with time zone") + .HasColumnName("last_sign_in"); + + b.Property("MatchRoute") + .HasColumnType("integer") + .HasColumnName("match_route"); + + b.Property("MatchedAttributes") + .HasColumnType("jsonb") + .HasColumnName("matched_attributes"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("VerificationRoute") + .HasColumnType("integer") + .HasColumnName("verification_route"); + + b.Property("VerifiedDatesOfBirth") + .HasColumnType("jsonb") + .HasColumnName("verified_dates_of_birth"); + + b.Property("VerifiedNames") + .HasColumnType("jsonb") + .HasColumnName("verified_names"); + + b.Property("VerifiedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("verified_on"); + + b.HasKey("Subject") + .HasName("pk_one_login_users"); + + b.ToTable("one_login_users", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Person", b => + { + b.Property("PersonId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("DateOfBirth") + .HasColumnType("date") + .HasColumnName("date_of_birth"); + + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_on"); + + b.Property("DqtContactId") + .HasColumnType("uuid") + .HasColumnName("dqt_contact_id"); + + b.Property("DqtCreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_created_on"); + + b.Property("DqtFirstName") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("dqt_first_name") + .UseCollation("case_insensitive"); + + b.Property("DqtFirstSync") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_first_sync"); + + b.Property("DqtLastName") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("dqt_last_name") + .UseCollation("case_insensitive"); + + b.Property("DqtLastSync") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_last_sync"); + + b.Property("DqtMiddleName") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("dqt_middle_name") + .UseCollation("case_insensitive"); + + b.Property("DqtModifiedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_modified_on"); + + b.Property("DqtState") + .HasColumnType("integer") + .HasColumnName("dqt_state"); + + b.Property("EmailAddress") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("email_address") + .UseCollation("case_insensitive"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("first_name") + .UseCollation("case_insensitive"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("last_name") + .UseCollation("case_insensitive"); + + b.Property("MiddleName") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("middle_name") + .UseCollation("case_insensitive"); + + b.Property("NationalInsuranceNumber") + .HasMaxLength(9) + .HasColumnType("character(9)") + .HasColumnName("national_insurance_number") + .IsFixedLength(); + + b.Property("Trn") + .HasMaxLength(7) + .HasColumnType("character(7)") + .HasColumnName("trn") + .IsFixedLength(); + + b.Property("UpdatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on"); + + b.HasKey("PersonId") + .HasName("pk_persons"); + + b.HasIndex("DqtContactId") + .IsUnique() + .HasDatabaseName("ix_persons_dqt_contact_id") + .HasFilter("dqt_contact_id is not null"); + + b.HasIndex("Trn") + .IsUnique() + .HasDatabaseName("ix_persons_trn") + .HasFilter("trn is not null"); + + b.ToTable("persons", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.PersonSearchAttribute", b => + { + b.Property("PersonSearchAttributeId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("person_search_attribute_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("PersonSearchAttributeId")); + + b.Property("AttributeKey") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("attribute_key") + .UseCollation("case_insensitive"); + + b.Property("AttributeType") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("attribute_type") + .UseCollation("case_insensitive"); + + b.Property("AttributeValue") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)") + .HasColumnName("attribute_value") + .UseCollation("case_insensitive"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("Tags") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("tags"); + + b.HasKey("PersonSearchAttributeId") + .HasName("pk_person_search_attributes"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_person_search_attributes_person_id"); + + b.HasIndex("AttributeType", "AttributeValue") + .HasDatabaseName("ix_person_search_attributes_attribute_type_and_value"); + + b.ToTable("person_search_attributes", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.QtsAwardedEmailsJob", b => + { + b.Property("QtsAwardedEmailsJobId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("qts_awarded_emails_job_id"); + + b.Property("AwardedToUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("awarded_to_utc"); + + b.Property("ExecutedUtc") + .HasColumnType("timestamp with time zone") + .HasColumnName("executed_utc"); + + b.HasKey("QtsAwardedEmailsJobId") + .HasName("pk_qts_awarded_emails_jobs"); + + b.HasIndex("ExecutedUtc") + .HasDatabaseName("ix_qts_awarded_emails_jobs_executed_utc"); + + b.ToTable("qts_awarded_emails_jobs", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.QtsAwardedEmailsJobItem", b => + { + b.Property("QtsAwardedEmailsJobId") + .HasColumnType("uuid") + .HasColumnName("qts_awarded_emails_job_id"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("EmailAddress") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("email_address"); + + b.Property("EmailSent") + .HasColumnType("boolean") + .HasColumnName("email_sent"); + + b.Property("Personalization") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("personalization"); + + b.Property("Trn") + .IsRequired() + .HasMaxLength(7) + .HasColumnType("character(7)") + .HasColumnName("trn") + .IsFixedLength(); + + b.HasKey("QtsAwardedEmailsJobId", "PersonId") + .HasName("pk_qts_awarded_emails_job_items"); + + b.HasIndex("Personalization") + .HasDatabaseName("ix_qts_awarded_emails_job_items_personalization"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("Personalization"), "gin"); + + b.ToTable("qts_awarded_emails_job_items", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Qualification", b => + { + b.Property("QualificationId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("qualification_id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("DeletedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("deleted_on"); + + b.Property("DqtCreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_created_on"); + + b.Property("DqtFirstSync") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_first_sync"); + + b.Property("DqtLastSync") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_last_sync"); + + b.Property("DqtModifiedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("dqt_modified_on"); + + b.Property("DqtQualificationId") + .HasColumnType("uuid") + .HasColumnName("dqt_qualification_id"); + + b.Property("DqtState") + .HasColumnType("integer") + .HasColumnName("dqt_state"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("QualificationType") + .HasColumnType("integer") + .HasColumnName("qualification_type"); + + b.Property("UpdatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on"); + + b.HasKey("QualificationId") + .HasName("pk_qualifications"); + + b.HasIndex("DqtQualificationId") + .IsUnique() + .HasDatabaseName("ix_qualifications_dqt_qualification_id") + .HasFilter("dqt_qualification_id is not null"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_qualifications_person_id"); + + b.ToTable("qualifications", (string)null); + + b.HasDiscriminator("QualificationType"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.SupportTask", b => + { + b.Property("SupportTaskReference") + .HasMaxLength(16) + .HasColumnType("character varying(16)") + .HasColumnName("support_task_reference"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("OneLoginUserSubject") + .HasColumnType("character varying(255)") + .HasColumnName("one_login_user_subject"); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("status"); + + b.Property("SupportTaskType") + .HasColumnType("integer") + .HasColumnName("support_task_type"); + + b.Property("UpdatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on"); + + b.Property("_data") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("data"); + + b.HasKey("SupportTaskReference") + .HasName("pk_support_tasks"); + + b.HasIndex("OneLoginUserSubject") + .HasDatabaseName("ix_support_tasks_one_login_user_subject"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_support_tasks_person_id"); + + b.ToTable("support_tasks", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtract", b => + { + b.Property("TpsCsvExtractId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("tps_csv_extract_id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("Filename") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("filename"); + + b.HasKey("TpsCsvExtractId") + .HasName("pk_tps_csv_extracts"); + + b.ToTable("tps_csv_extracts", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtractItem", b => + { + b.Property("TpsCsvExtractItemId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("tps_csv_extract_item_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("DateOfBirth") + .HasColumnType("date") + .HasColumnName("date_of_birth"); + + b.Property("DateOfDeath") + .HasColumnType("date") + .HasColumnName("date_of_death"); + + b.Property("EmploymentEndDate") + .HasColumnType("date") + .HasColumnName("employment_end_date"); + + b.Property("EmploymentStartDate") + .HasColumnType("date") + .HasColumnName("employment_start_date"); + + b.Property("EmploymentType") + .HasColumnType("integer") + .HasColumnName("employment_type"); + + b.Property("EstablishmentEmailAddress") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("establishment_email_address"); + + b.Property("EstablishmentNumber") + .HasMaxLength(4) + .HasColumnType("character(4)") + .HasColumnName("establishment_number") + .IsFixedLength(); + + b.Property("EstablishmentPostcode") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("establishment_postcode"); + + b.Property("ExtractDate") + .HasColumnType("date") + .HasColumnName("extract_date"); + + b.Property("Gender") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("gender"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("key"); + + b.Property("LocalAuthorityCode") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character(3)") + .HasColumnName("local_authority_code") + .IsFixedLength(); + + b.Property("MemberEmailAddress") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("member_email_address"); + + b.Property("MemberId") + .HasColumnType("integer") + .HasColumnName("member_id"); + + b.Property("MemberPostcode") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("member_postcode"); + + b.Property("NationalInsuranceNumber") + .IsRequired() + .HasMaxLength(9) + .HasColumnType("character(9)") + .HasColumnName("national_insurance_number") + .IsFixedLength(); + + b.Property("Result") + .HasColumnType("integer") + .HasColumnName("result"); + + b.Property("TpsCsvExtractId") + .HasColumnType("uuid") + .HasColumnName("tps_csv_extract_id"); + + b.Property("TpsCsvExtractLoadItemId") + .HasColumnType("uuid") + .HasColumnName("tps_csv_extract_load_item_id"); + + b.Property("Trn") + .IsRequired() + .HasMaxLength(7) + .HasColumnType("character(7)") + .HasColumnName("trn") + .IsFixedLength(); + + b.Property("WithdrawalIndicator") + .HasMaxLength(1) + .HasColumnType("character(1)") + .HasColumnName("withdrawal_indicator") + .IsFixedLength(); + + b.HasKey("TpsCsvExtractItemId") + .HasName("pk_tps_csv_extract_items"); + + b.HasIndex("Key") + .HasDatabaseName("ix_tps_csv_extract_items_key"); + + b.HasIndex("TpsCsvExtractId") + .HasDatabaseName("ix_tps_csv_extract_items_tps_csv_extract_id"); + + b.HasIndex("TpsCsvExtractLoadItemId") + .HasDatabaseName("ix_tps_csv_extract_items_tps_csv_extract_load_item_id"); + + b.HasIndex("Trn") + .HasDatabaseName("ix_tps_csv_extract_items_trn"); + + b.HasIndex("LocalAuthorityCode", "EstablishmentNumber") + .HasDatabaseName("ix_tps_csv_extract_items_la_code_establishment_number"); + + b.ToTable("tps_csv_extract_items", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtractLoadItem", b => + { + b.Property("TpsCsvExtractLoadItemId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("tps_csv_extract_load_item_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("DateOfBirth") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("date_of_birth"); + + b.Property("DateOfDeath") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("date_of_death"); + + b.Property("EmploymentEndDate") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("employment_end_date"); + + b.Property("EmploymentStartDate") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("employment_start_date"); + + b.Property("Errors") + .HasColumnType("integer") + .HasColumnName("errors"); + + b.Property("EstablishmentEmailAddress") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("establishment_email_address"); + + b.Property("EstablishmentNumber") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("establishment_number"); + + b.Property("EstablishmentPostcode") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("establishment_postcode"); + + b.Property("ExtractDate") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("extract_date"); + + b.Property("FullOrPartTimeIndicator") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("full_or_part_time_indicator"); + + b.Property("Gender") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("gender"); + + b.Property("LocalAuthorityCode") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("local_authority_code"); + + b.Property("MemberEmailAddress") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("member_email_address"); + + b.Property("MemberId") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("member_id"); + + b.Property("MemberPostcode") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("member_postcode"); + + b.Property("NationalInsuranceNumber") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("national_insurance_number"); + + b.Property("TpsCsvExtractId") + .HasColumnType("uuid") + .HasColumnName("tps_csv_extract_id"); + + b.Property("Trn") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("trn"); + + b.Property("WithdrawalIndicator") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("withdrawal_indicator"); + + b.HasKey("TpsCsvExtractLoadItemId") + .HasName("pk_tps_csv_extract_load_items"); + + b.ToTable("tps_csv_extract_load_items", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsEmployment", b => + { + b.Property("TpsEmploymentId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("tps_employment_id"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on"); + + b.Property("EmploymentType") + .HasColumnType("integer") + .HasColumnName("employment_type"); + + b.Property("EndDate") + .HasColumnType("date") + .HasColumnName("end_date"); + + b.Property("EstablishmentId") + .HasColumnType("uuid") + .HasColumnName("establishment_id"); + + b.Property("Key") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("key"); + + b.Property("LastExtractDate") + .HasColumnType("date") + .HasColumnName("last_extract_date"); + + b.Property("LastKnownTpsEmployedDate") + .HasColumnType("date") + .HasColumnName("last_known_tps_employed_date"); + + b.Property("NationalInsuranceNumber") + .HasMaxLength(9) + .HasColumnType("character(9)") + .HasColumnName("national_insurance_number") + .IsFixedLength(); + + b.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b.Property("PersonPostcode") + .HasMaxLength(10) + .HasColumnType("character varying(10)") + .HasColumnName("person_postcode"); + + b.Property("StartDate") + .HasColumnType("date") + .HasColumnName("start_date"); + + b.Property("UpdatedOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on"); + + b.Property("WithdrawalConfirmed") + .HasColumnType("boolean") + .HasColumnName("withdrawal_confirmed"); + + b.HasKey("TpsEmploymentId") + .HasName("pk_tps_employments"); + + b.HasIndex("EstablishmentId") + .HasDatabaseName("ix_tps_employments_establishment_id"); + + b.HasIndex("Key") + .HasDatabaseName("ix_tps_employments_key"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_tps_employments_person_id"); + + b.ToTable("tps_employments", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsEstablishment", b => + { + b.Property("TpsEstablishmentId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("tps_establishment_id"); + + b.Property("EmployersName") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("employers_name"); + + b.Property("EstablishmentCode") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character(4)") + .HasColumnName("establishment_code") + .IsFixedLength(); + + b.Property("LaCode") + .IsRequired() + .HasMaxLength(3) + .HasColumnType("character(3)") + .HasColumnName("la_code") + .IsFixedLength(); + + b.Property("SchoolClosedDate") + .HasColumnType("date") + .HasColumnName("school_closed_date"); + + b.Property("SchoolGiasName") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("school_gias_name"); + + b.HasKey("TpsEstablishmentId") + .HasName("pk_tps_establishments"); + + b.HasIndex("LaCode", "EstablishmentCode") + .HasDatabaseName("ix_tps_establishments_la_code_establishment_number"); + + b.ToTable("tps_establishments", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsEstablishmentType", b => + { + b.Property("TpsEstablishmentTypeId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("tps_establishment_type_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("TpsEstablishmentTypeId")); + + b.Property("Description") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("character varying(300)") + .HasColumnName("description"); + + b.Property("EstablishmentRangeFrom") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character(4)") + .HasColumnName("establishment_range_from") + .IsFixedLength(); + + b.Property("EstablishmentRangeTo") + .IsRequired() + .HasMaxLength(4) + .HasColumnType("character(4)") + .HasColumnName("establishment_range_to") + .IsFixedLength(); + + b.Property("ShortDescription") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("character varying(120)") + .HasColumnName("short_description"); + + b.HasKey("TpsEstablishmentTypeId") + .HasName("pk_tps_establishment_types"); + + b.ToTable("tps_establishment_types", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TrnRequest", b => + { + b.Property("TrnRequestId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("trn_request_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("TrnRequestId")); + + b.Property("ClientId") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("client_id"); + + b.Property("IdentityUserId") + .HasColumnType("uuid") + .HasColumnName("identity_user_id"); + + b.Property("LinkedToIdentity") + .HasColumnType("boolean") + .HasColumnName("linked_to_identity"); + + b.Property("RequestId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("request_id"); + + b.Property("TeacherId") + .HasColumnType("uuid") + .HasColumnName("teacher_id"); + + b.Property("TrnToken") + .HasMaxLength(128) + .HasColumnType("character varying(128)") + .HasColumnName("trn_token"); + + b.HasKey("TrnRequestId") + .HasName("pk_trn_requests"); + + b.HasIndex("ClientId", "RequestId") + .IsUnique() + .HasDatabaseName("ix_trn_requests_client_id_request_id"); + + b.ToTable("trn_requests", (string)null); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.UserBase", b => + { + b.Property("UserId") + .ValueGeneratedOnAdd() + .HasColumnType("uuid") + .HasColumnName("user_id"); + + b.Property("Active") + .HasColumnType("boolean") + .HasColumnName("active"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("name"); + + b.Property("UserType") + .HasColumnType("integer") + .HasColumnName("user_type"); + + b.HasKey("UserId") + .HasName("pk_users"); + + b.ToTable("users", (string)null); + + b.HasDiscriminator("UserType"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.MandatoryQualification", b => + { + b.HasBaseType("TeachingRecordSystem.Core.DataStore.Postgres.Models.Qualification"); + + b.Property("DqtMqEstablishmentId") + .HasColumnType("uuid") + .HasColumnName("dqt_mq_establishment_id"); + + b.Property("DqtSpecialismId") + .HasColumnType("uuid") + .HasColumnName("dqt_specialism_id"); + + b.Property("EndDate") + .HasColumnType("date") + .HasColumnName("end_date"); + + b.Property("ProviderId") + .HasColumnType("uuid") + .HasColumnName("mq_provider_id"); + + b.Property("Specialism") + .HasColumnType("integer") + .HasColumnName("mq_specialism"); + + b.Property("StartDate") + .HasColumnType("date") + .HasColumnName("start_date"); + + b.Property("Status") + .HasColumnType("integer") + .HasColumnName("mq_status"); + + b.HasDiscriminator().HasValue(0); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.ApplicationUser", b => + { + b.HasBaseType("TeachingRecordSystem.Core.DataStore.Postgres.Models.UserBase"); + + b.Property("ApiRoles") + .HasColumnType("varchar[]") + .HasColumnName("api_roles"); + + b.Property("ClientId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("client_id"); + + b.Property("ClientSecret") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("client_secret"); + + b.Property("IsOidcClient") + .HasColumnType("boolean") + .HasColumnName("is_oidc_client"); + + b.Property("OneLoginAuthenticationSchemeName") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("one_login_authentication_scheme_name"); + + b.Property("OneLoginClientId") + .HasMaxLength(50) + .HasColumnType("character varying(50)") + .HasColumnName("one_login_client_id"); + + b.Property("OneLoginPostLogoutRedirectUriPath") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("one_login_post_logout_redirect_uri_path"); + + b.Property("OneLoginPrivateKeyPem") + .HasMaxLength(2000) + .HasColumnType("character varying(2000)") + .HasColumnName("one_login_private_key_pem"); + + b.Property("OneLoginRedirectUriPath") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("one_login_redirect_uri_path"); + + b.Property>("PostLogoutRedirectUris") + .HasColumnType("varchar[]") + .HasColumnName("post_logout_redirect_uris"); + + b.Property>("RedirectUris") + .HasColumnType("varchar[]") + .HasColumnName("redirect_uris"); + + b.HasIndex("ClientId") + .IsUnique() + .HasDatabaseName("ix_users_client_id") + .HasFilter("client_id is not null"); + + b.HasIndex("OneLoginAuthenticationSchemeName") + .IsUnique() + .HasDatabaseName("ix_users_one_login_authentication_scheme_name") + .HasFilter("one_login_authentication_scheme_name is not null"); + + b.HasDiscriminator().HasValue(2); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.SystemUser", b => + { + b.HasBaseType("TeachingRecordSystem.Core.DataStore.Postgres.Models.UserBase"); + + b.ToTable("users", (string)null); + + b.HasDiscriminator().HasValue(3); + + b.HasData( + new + { + UserId = new Guid("a81394d1-a498-46d8-af3e-e077596ab303"), + Active = true, + Name = "System", + UserType = 0 + }); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.User", b => + { + b.HasBaseType("TeachingRecordSystem.Core.DataStore.Postgres.Models.UserBase"); + + b.Property("AzureAdUserId") + .HasMaxLength(100) + .HasColumnType("character varying(100)") + .HasColumnName("azure_ad_user_id"); + + b.Property("DqtUserId") + .HasColumnType("uuid") + .HasColumnName("dqt_user_id"); + + b.Property("Email") + .HasMaxLength(200) + .HasColumnType("character varying(200)") + .HasColumnName("email") + .UseCollation("case_insensitive"); + + b.Property("Roles") + .IsRequired() + .HasColumnType("varchar[]") + .HasColumnName("roles"); + + b.HasIndex("AzureAdUserId") + .IsUnique() + .HasDatabaseName("ix_users_azure_ad_user_id"); + + b.HasDiscriminator().HasValue(1); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Authorizations") + .HasForeignKey("ApplicationId") + .HasConstraintName("fk_oidc_authorizations_oidc_applications_application_id"); + + b.Navigation("Application"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", "Application") + .WithMany("Tokens") + .HasForeignKey("ApplicationId") + .HasConstraintName("fk_oidc_tokens_oidc_applications_application_id"); + + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId") + .HasConstraintName("fk_oidc_tokens_oidc_authorizations_authorization_id"); + + b.Navigation("Application"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Alert", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertType", null) + .WithMany() + .HasForeignKey("AlertTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_alerts_alert_type"); + + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.Person", null) + .WithMany() + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_alerts_person"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertType", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertCategory", null) + .WithMany("AlertTypes") + .HasForeignKey("AlertCategoryId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_alert_types_alert_category"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.ApiKey", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.ApplicationUser", "ApplicationUser") + .WithMany("ApiKeys") + .HasForeignKey("ApplicationUserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_api_key_application_user"); + + b.Navigation("ApplicationUser"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Establishment", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.EstablishmentSource", null) + .WithMany() + .HasForeignKey("EstablishmentSourceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_establishments_establishment_source_id"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EytsAwardedEmailsJobItem", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.EytsAwardedEmailsJob", "EytsAwardedEmailsJob") + .WithMany("JobItems") + .HasForeignKey("EytsAwardedEmailsJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_eyts_awarded_emails_job_items_eyts_awarded_emails_jobs_eyts"); + + b.Navigation("EytsAwardedEmailsJob"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InductionCompletedEmailsJobItem", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.InductionCompletedEmailsJob", "InductionCompletedEmailsJob") + .WithMany("JobItems") + .HasForeignKey("InductionCompletedEmailsJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_induction_completed_emails_job_items_induction_completed_em"); + + b.Navigation("InductionCompletedEmailsJob"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InternationalQtsAwardedEmailsJobItem", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.InternationalQtsAwardedEmailsJob", "InternationalQtsAwardedEmailsJob") + .WithMany("JobItems") + .HasForeignKey("InternationalQtsAwardedEmailsJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_international_qts_awarded_emails_job_items_international_qt"); + + b.Navigation("InternationalQtsAwardedEmailsJob"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.OneLoginUser", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.Person", "Person") + .WithOne() + .HasForeignKey("TeachingRecordSystem.Core.DataStore.Postgres.Models.OneLoginUser", "PersonId") + .HasConstraintName("fk_one_login_users_persons_person_id"); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.QtsAwardedEmailsJobItem", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.QtsAwardedEmailsJob", "QtsAwardedEmailsJob") + .WithMany("JobItems") + .HasForeignKey("QtsAwardedEmailsJobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_qts_awarded_emails_job_items_qts_awarded_emails_jobs_qts_aw"); + + b.Navigation("QtsAwardedEmailsJob"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.Qualification", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.Person", null) + .WithMany() + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_qualifications_person"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.SupportTask", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.OneLoginUser", null) + .WithMany() + .HasForeignKey("OneLoginUserSubject") + .HasConstraintName("fk_support_tasks_one_login_user"); + + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.Person", null) + .WithMany() + .HasForeignKey("PersonId") + .HasConstraintName("fk_support_tasks_person"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtractItem", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtract", null) + .WithMany() + .HasForeignKey("TpsCsvExtractId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tps_csv_extract_items_tps_csv_extract_id"); + + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtractLoadItem", null) + .WithMany() + .HasForeignKey("TpsCsvExtractLoadItemId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tps_csv_extract_items_tps_csv_extract_load_item_id"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtractLoadItem", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsCsvExtract", null) + .WithMany() + .HasForeignKey("TpsCsvExtractId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tps_csv_extract_load_items_tps_csv_extract_id"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.TpsEmployment", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.Establishment", null) + .WithMany() + .HasForeignKey("EstablishmentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tps_employments_establishment_id"); + + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.Person", null) + .WithMany() + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tps_employments_person_id"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.MandatoryQualification", b => + { + b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.MandatoryQualificationProvider", "Provider") + .WithMany() + .HasForeignKey("ProviderId") + .HasConstraintName("fk_qualifications_mandatory_qualification_provider"); + + b.Navigation("Provider"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreApplication", b => + { + b.Navigation("Authorizations"); + + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertCategory", b => + { + b.Navigation("AlertTypes"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EytsAwardedEmailsJob", b => + { + b.Navigation("JobItems"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InductionCompletedEmailsJob", b => + { + b.Navigation("JobItems"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.InternationalQtsAwardedEmailsJob", b => + { + b.Navigation("JobItems"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.QtsAwardedEmailsJob", b => + { + b.Navigation("JobItems"); + }); + + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.ApplicationUser", b => + { + b.Navigation("ApiKeys"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/20240912133630_AlertTypeIsActive.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/20240912133630_AlertTypeIsActive.cs new file mode 100644 index 0000000000..95b90eb546 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/20240912133630_AlertTypeIsActive.cs @@ -0,0 +1,410 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TeachingRecordSystem.Core.DataStore.Postgres.Migrations +{ + /// + public partial class AlertTypeIsActive : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("62715a16-69f8-44f7-90f4-df83cd0c9f16")); + + migrationBuilder.DeleteData( + table: "alert_categories", + keyColumn: "alert_category_id", + keyValue: new Guid("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a")); + + migrationBuilder.AddColumn( + name: "is_active", + table: "alert_types", + type: "boolean", + nullable: false, + defaultValue: false); + + migrationBuilder.UpdateData( + table: "alert_categories", + keyColumn: "alert_category_id", + keyValue: new Guid("768c9eb4-355b-4491-bb20-67eb59a97579"), + column: "name", + value: "Flag"); + + migrationBuilder.UpdateData( + table: "alert_categories", + keyColumn: "alert_category_id", + keyValue: new Guid("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), + column: "name", + value: "Restricted/DBS"); + + migrationBuilder.InsertData( + table: "alert_categories", + columns: new[] { "alert_category_id", "name" }, + values: new object[] { new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), "SoS Restriction" }); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("0740f9eb-ece3-4394-a230-453da224d337"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("0ae8d4b6-ec9b-47ca-9338-6dae9192afe5"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("17b4fe26-7468-4702-92e5-785b861cf0fa"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("18e04dcb-fb86-4b05-8d5d-ff9c5da738dd"), + columns: new[] { "alert_category_id", "is_active" }, + values: new object[] { new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), false }); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("1a2b06ae-7e9f-4761-b95d-397ca5da4b13"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("1ebd1620-293d-4169-ba78-0b41a6413ad9"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("241eeb78-fac7-4c77-8059-c12e93dc2fae"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("2c496e3f-00d3-4f0d-81f3-21458fe707b3"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("2ca98658-1d5b-49d5-b05f-cc08c8b8502c"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("33e00e46-6513-4136-adfd-1352cf34d8ec"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("3499860a-a0fb-43e3-878e-c226d14150b0"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("38db7946-2dbf-408e-bc48-1625829e7dfe"), + columns: new[] { "alert_category_id", "is_active" }, + values: new object[] { new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), false }); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("3c5fc83b-10e1-4a15-83e6-794fce3e0b45"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("3f7de5fd-05a8-404f-a97c-428f54e81322"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("40794ea8-eda2-40a8-a26a-5f447aae6c99"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("50508749-7a6b-4175-8538-9a1e55692efd"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("50feafbc-5124-4189-b06c-6463c7ebb8a8"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("552ee226-a3a9-4dc3-8d04-0b7e4f641b51"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("5aa21b8f-2069-43c9-8afd-05b34b02505f"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("5ea8bb68-4774-4ad8-b635-213a0cdda4c3"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("651e1f56-3135-4961-bd7e-3f7b2c75cb04"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("72e48b6a-e781-4bf3-910b-91f2d28f2eaa"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("78f88de2-9ec1-41b8-948a-33bdff223206"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("7924fe90-483c-49f8-84fc-674feddba848"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("872d7700-aa6f-435e-b5f9-821fb087962a"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("8ef92c14-4b1f-4530-9189-779ad9f3cefd"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("950d3eed-bef5-448a-b0f0-bf9c54f2103b"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("993daa42-96cb-4621-bd9e-d4b195076bbe"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("9fafaa80-f9f8-44a0-b7b3-cffedcbe0298"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("a414283f-7d5b-4587-83bf-f6da8c05b8d5"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("a5bd4352-2cec-4417-87a1-4b6b79d033c2"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("a6f51ccc-a19c-4dc2-ba80-ffb7a95ff2ee"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("a6fc9f2e-8923-4163-978e-93bd901d146f"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("ae3e385d-03f8-4f12-9ce2-006afe827d23"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("af65c236-47a6-427b-8e4b-930de6d256f0"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("b6c8d8f1-723e-49a5-9551-25805e3e29b9"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("c02bdc3a-7a19-4034-aa23-3a23c54e1d34"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("cac68337-3f95-4475-97cf-1381e6b74700"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("d372fcfa-1c4a-4fed-84c8-4c7885575681"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("e3658a61-bee2-4df1-9a26-e010681ee310"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("eab8b66d-68d0-4cb9-8e4d-bbd245648fb6"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("ed0cd700-3fb2-4db0-9403-ba57126090ed"), + column: "is_active", + value: true); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("fa6bd220-61b0-41fc-9066-421b3b9d7885"), + column: "is_active", + value: false); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("fcff87d6-88f5-4fc5-ac81-5350b4fdd9e1"), + column: "is_active", + value: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "alert_categories", + keyColumn: "alert_category_id", + keyValue: new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7")); + + migrationBuilder.DropColumn( + name: "is_active", + table: "alert_types"); + + migrationBuilder.UpdateData( + table: "alert_categories", + keyColumn: "alert_category_id", + keyValue: new Guid("768c9eb4-355b-4491-bb20-67eb59a97579"), + column: "name", + value: "Flags"); + + migrationBuilder.UpdateData( + table: "alert_categories", + keyColumn: "alert_category_id", + keyValue: new Guid("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), + column: "name", + value: "DBS"); + + migrationBuilder.InsertData( + table: "alert_categories", + columns: new[] { "alert_category_id", "name" }, + values: new object[] { new Guid("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a"), "Not true alert" }); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("18e04dcb-fb86-4b05-8d5d-ff9c5da738dd"), + column: "alert_category_id", + value: new Guid("cbf7633f-3904-407d-8371-42a473fa641f")); + + migrationBuilder.UpdateData( + table: "alert_types", + keyColumn: "alert_type_id", + keyValue: new Guid("38db7946-2dbf-408e-bc48-1625829e7dfe"), + column: "alert_category_id", + value: new Guid("cbf7633f-3904-407d-8371-42a473fa641f")); + + migrationBuilder.InsertData( + table: "alert_types", + columns: new[] { "alert_type_id", "alert_category_id", "dqt_sanction_code", "name", "prohibition_level" }, + values: new object[] { new Guid("62715a16-69f8-44f7-90f4-df83cd0c9f16"), new Guid("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a"), "B4", "Employers to contact the Secretary of State", 0 }); + } + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/TrsDbContextModelSnapshot.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/TrsDbContextModelSnapshot.cs index b391ea74cd..459d1a5404 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/TrsDbContextModelSnapshot.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Migrations/TrsDbContextModelSnapshot.cs @@ -374,7 +374,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { AlertCategoryId = new Guid("768c9eb4-355b-4491-bb20-67eb59a97579"), - Name = "Flags" + Name = "Flag" }, new { @@ -399,7 +399,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) new { AlertCategoryId = new Guid("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), - Name = "DBS" + Name = "Restricted/DBS" }, new { @@ -418,8 +418,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) }, new { - AlertCategoryId = new Guid("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a"), - Name = "Not true alert" + AlertCategoryId = new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), + Name = "SoS Restriction" }); }); @@ -440,6 +440,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnName("dqt_sanction_code") .UseCollation("case_insensitive"); + b.Property("IsActive") + .HasColumnType("boolean") + .HasColumnName("is_active"); + b.Property("Name") .IsRequired() .HasMaxLength(200) @@ -465,6 +469,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("2ca98658-1d5b-49d5-b05f-cc08c8b8502c"), AlertCategoryId = new Guid("ee78d44d-abf8-44a9-b22b-87a821f8d3c9"), DqtSanctionCode = "T8", + IsActive = true, Name = "Teacher sanctioned in other EEA member state", ProhibitionLevel = 3 }, @@ -473,6 +478,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("9fafaa80-f9f8-44a0-b7b3-cffedcbe0298"), AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), DqtSanctionCode = "C2", + IsActive = true, Name = "Failed induction", ProhibitionLevel = 1 }, @@ -481,6 +487,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("651e1f56-3135-4961-bd7e-3f7b2c75cb04"), AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), DqtSanctionCode = "C1", + IsActive = false, Name = "Prohibited by the Secretary of State - failed probation", ProhibitionLevel = 1 }, @@ -489,6 +496,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("5ea8bb68-4774-4ad8-b635-213a0cdda4c3"), AlertCategoryId = new Guid("0ae0707b-1503-477d-bc0f-1505ed95dbdf"), DqtSanctionCode = "C3", + IsActive = false, Name = "Restricted by the Secretary of State - failed probation - permitted to carry out specified work for a period equal in length to a statutory induction period only", ProhibitionLevel = 1 }, @@ -497,6 +505,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("ae3e385d-03f8-4f12-9ce2-006afe827d23"), AlertCategoryId = new Guid("768c9eb4-355b-4491-bb20-67eb59a97579"), DqtSanctionCode = "T9", + IsActive = true, Name = "FOR INTERNAL INFORMATION ONLY - see alert details", ProhibitionLevel = 0 }, @@ -505,6 +514,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("a6fc9f2e-8923-4163-978e-93bd901d146f"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A18", + IsActive = false, Name = "Conditional Registration Order - conviction of a relevant offence", ProhibitionLevel = 2 }, @@ -513,6 +523,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("1ebd1620-293d-4169-ba78-0b41a6413ad9"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A7", + IsActive = false, Name = "Conditional Registration Order - serious professional incompetence", ProhibitionLevel = 2 }, @@ -521,6 +532,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("3499860a-a0fb-43e3-878e-c226d14150b0"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A3", + IsActive = false, Name = "Conditional Registration Order - unacceptable professional conduct", ProhibitionLevel = 2 }, @@ -529,6 +541,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("552ee226-a3a9-4dc3-8d04-0b7e4f641b51"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A15", + IsActive = false, Name = "For internal information only - historic GTC finding of unsuitable for registration", ProhibitionLevel = 0 }, @@ -537,6 +550,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("33e00e46-6513-4136-adfd-1352cf34d8ec"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A22", + IsActive = false, Name = "No Sanction - breach of condition(s)", ProhibitionLevel = 0 }, @@ -545,6 +559,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("0740f9eb-ece3-4394-a230-453da224d337"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A16", + IsActive = false, Name = "No Sanction - conviction for a relevant offence", ProhibitionLevel = 0 }, @@ -553,6 +568,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("b6c8d8f1-723e-49a5-9551-25805e3e29b9"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A12", + IsActive = false, Name = "No Sanction - serious professional incompetence", ProhibitionLevel = 0 }, @@ -561,6 +577,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("78f88de2-9ec1-41b8-948a-33bdff223206"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A11", + IsActive = false, Name = "No Sanction - unacceptable professional conduct", ProhibitionLevel = 0 }, @@ -569,6 +586,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("fcff87d6-88f5-4fc5-ac81-5350b4fdd9e1"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A17", + IsActive = false, Name = "Reprimand - conviction of a relevant offence", ProhibitionLevel = 0 }, @@ -577,6 +595,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("3f7de5fd-05a8-404f-a97c-428f54e81322"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A8", + IsActive = false, Name = "Reprimand - serious professional incompetence", ProhibitionLevel = 0 }, @@ -585,6 +604,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("0ae8d4b6-ec9b-47ca-9338-6dae9192afe5"), AlertCategoryId = new Guid("06d98708-b52d-496a-aaa7-c1d7d2ca8b24"), DqtSanctionCode = "A4", + IsActive = false, Name = "Reprimand - unacceptable professional conduct", ProhibitionLevel = 0 }, @@ -593,6 +613,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("72e48b6a-e781-4bf3-910b-91f2d28f2eaa"), AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), DqtSanctionCode = "A21B", + IsActive = false, Name = "Prohibition Order - conviction of a relevant offence - eligible to reapply after specified time", ProhibitionLevel = 1 }, @@ -601,6 +622,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("950d3eed-bef5-448a-b0f0-bf9c54f2103b"), AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), DqtSanctionCode = "A21A", + IsActive = false, Name = "Prohibition Order - conviction of a relevant offence - ineligible to reapply", ProhibitionLevel = 1 }, @@ -609,6 +631,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("cac68337-3f95-4475-97cf-1381e6b74700"), AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), DqtSanctionCode = "A5B", + IsActive = false, Name = "Prohibition Order - serious professional incompetence - Eligible to reapply after specified time", ProhibitionLevel = 1 }, @@ -617,6 +640,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("c02bdc3a-7a19-4034-aa23-3a23c54e1d34"), AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), DqtSanctionCode = "A5A", + IsActive = false, Name = "Prohibition Order - serious professional incompetence - Ineligible to reapply", ProhibitionLevel = 1 }, @@ -625,6 +649,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("e3658a61-bee2-4df1-9a26-e010681ee310"), AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), DqtSanctionCode = "A1B", + IsActive = false, Name = "Prohibition Order - unacceptable professional conduct - Eligible to reapply after specified time", ProhibitionLevel = 1 }, @@ -633,6 +658,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("fa6bd220-61b0-41fc-9066-421b3b9d7885"), AlertCategoryId = new Guid("70b7d473-2ec8-4643-bfd4-d4ab9a9a0988"), DqtSanctionCode = "A1A", + IsActive = false, Name = "Prohibition Order - unacceptable professional conduct - Ineligible to reapply", ProhibitionLevel = 1 }, @@ -641,6 +667,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("d372fcfa-1c4a-4fed-84c8-4c7885575681"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A20", + IsActive = false, Name = "Suspension order - conviction of a relevant offence - with conditions", ProhibitionLevel = 2 }, @@ -649,6 +676,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("af65c236-47a6-427b-8e4b-930de6d256f0"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A19", + IsActive = false, Name = "Suspension order - conviction of a relevant offence - without conditions", ProhibitionLevel = 2 }, @@ -657,6 +685,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("50508749-7a6b-4175-8538-9a1e55692efd"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A14", + IsActive = false, Name = "Suspension order - serious professional incompetence - with conditions", ProhibitionLevel = 2 }, @@ -665,6 +694,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("a6f51ccc-a19c-4dc2-ba80-ffb7a95ff2ee"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A6", + IsActive = false, Name = "Suspension order - serious professional incompetence - without conditions", ProhibitionLevel = 2 }, @@ -673,6 +703,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("1a2b06ae-7e9f-4761-b95d-397ca5da4b13"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A13", + IsActive = false, Name = "Suspension order - unacceptable professional conduct - with conditions", ProhibitionLevel = 2 }, @@ -681,6 +712,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("872d7700-aa6f-435e-b5f9-821fb087962a"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A2", + IsActive = false, Name = "Suspension order - unacceptable professional conduct - without conditions", ProhibitionLevel = 2 }, @@ -689,6 +721,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("17b4fe26-7468-4702-92e5-785b861cf0fa"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A24", + IsActive = false, Name = "Suspension order - with conditions - (arising from breach of previous condition(s))", ProhibitionLevel = 2 }, @@ -697,22 +730,16 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("3c5fc83b-10e1-4a15-83e6-794fce3e0b45"), AlertCategoryId = new Guid("790410c1-b884-4cdd-8db9-64a042ab54ae"), DqtSanctionCode = "A23", + IsActive = false, Name = "Suspension order - without conditions - (arising from breach of previous condition(s))", ProhibitionLevel = 2 }, new - { - AlertTypeId = new Guid("62715a16-69f8-44f7-90f4-df83cd0c9f16"), - AlertCategoryId = new Guid("ff18c0a8-aaea-4c8b-93a2-2206beea1d7a"), - DqtSanctionCode = "B4", - Name = "Employers to contact the Secretary of State", - ProhibitionLevel = 0 - }, - new { AlertTypeId = new Guid("eab8b66d-68d0-4cb9-8e4d-bbd245648fb6"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "B1", + IsActive = false, Name = "Barring by the Secretary of State", ProhibitionLevel = 1 }, @@ -721,6 +748,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("2c496e3f-00d3-4f0d-81f3-21458fe707b3"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "G2", + IsActive = false, Name = "Formerly barred by the Independent Safeguarding Authority", ProhibitionLevel = 1 }, @@ -729,6 +757,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("993daa42-96cb-4621-bd9e-d4b195076bbe"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "B6", + IsActive = false, Name = "Formerly on List 99", ProhibitionLevel = 1 }, @@ -737,6 +766,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("a414283f-7d5b-4587-83bf-f6da8c05b8d5"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "T2", + IsActive = true, Name = "Interim prohibition by the Secretary of State", ProhibitionLevel = 1 }, @@ -745,6 +775,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("8ef92c14-4b1f-4530-9189-779ad9f3cefd"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "B3", + IsActive = false, Name = "Prohibited by an Independent Schools Tribunal or Secretary of State", ProhibitionLevel = 1 }, @@ -753,6 +784,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("50feafbc-5124-4189-b06c-6463c7ebb8a8"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "T3", + IsActive = true, Name = "Prohibition by the Secretary of State - deregistered by GTC Scotland", ProhibitionLevel = 1 }, @@ -761,6 +793,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("5aa21b8f-2069-43c9-8afd-05b34b02505f"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "T5", + IsActive = true, Name = "Prohibition by the Secretary of State - refer to GTC Northern Ireland", ProhibitionLevel = 1 }, @@ -769,6 +802,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("a5bd4352-2cec-4417-87a1-4b6b79d033c2"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "T4", + IsActive = true, Name = "Prohibition by the Secretary of State - refer to the Education Workforce Council, Wales", ProhibitionLevel = 1 }, @@ -777,6 +811,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("ed0cd700-3fb2-4db0-9403-ba57126090ed"), AlertCategoryId = new Guid("b2b19019-b165-47a3-8745-3297ff152581"), DqtSanctionCode = "T1", + IsActive = true, Name = "Prohibition by the Secretary of State - misconduct", ProhibitionLevel = 1 }, @@ -785,22 +820,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("40794ea8-eda2-40a8-a26a-5f447aae6c99"), AlertCategoryId = new Guid("e8a9ee91-bf7f-4f70-bc66-a644d522384e"), DqtSanctionCode = "G1", + IsActive = true, Name = "A possible matching record was found. Please contact the DBS before employing this person", ProhibitionLevel = 1 }, new { AlertTypeId = new Guid("38db7946-2dbf-408e-bc48-1625829e7dfe"), - AlertCategoryId = new Guid("cbf7633f-3904-407d-8371-42a473fa641f"), + AlertCategoryId = new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), DqtSanctionCode = "B2B", + IsActive = false, Name = "Restricted by the Secretary of State - Not Permitted to work as teacher", ProhibitionLevel = 1 }, new { AlertTypeId = new Guid("18e04dcb-fb86-4b05-8d5d-ff9c5da738dd"), - AlertCategoryId = new Guid("cbf7633f-3904-407d-8371-42a473fa641f"), + AlertCategoryId = new Guid("e4057fc2-a010-42a9-8cb2-7dcc5c9b5fa7"), DqtSanctionCode = "B2A", + IsActive = false, Name = "Restricted by the Secretary of State - Permitted to work as teacher", ProhibitionLevel = 1 }, @@ -809,6 +847,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("241eeb78-fac7-4c77-8059-c12e93dc2fae"), AlertCategoryId = new Guid("38df5a00-94ab-486f-8905-d5b2eac04000"), DqtSanctionCode = "T7", + IsActive = true, Name = "Section 128 barring direction", ProhibitionLevel = 4 }, @@ -817,6 +856,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) AlertTypeId = new Guid("7924fe90-483c-49f8-84fc-674feddba848"), AlertCategoryId = new Guid("227b75e5-bb98-496c-8860-1baea37aa5c6"), DqtSanctionCode = "T6", + IsActive = true, Name = "Secretary of State decision- no prohibition", ProhibitionLevel = 0 }); @@ -2606,7 +2646,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertType", b => { b.HasOne("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertCategory", null) - .WithMany() + .WithMany("AlertTypes") .HasForeignKey("AlertCategoryId") .OnDelete(DeleteBehavior.Cascade) .IsRequired() @@ -2782,6 +2822,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Tokens"); }); + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.AlertCategory", b => + { + b.Navigation("AlertTypes"); + }); + modelBuilder.Entity("TeachingRecordSystem.Core.DataStore.Postgres.Models.EytsAwardedEmailsJob", b => { b.Navigation("JobItems"); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertCategory.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertCategory.cs index 8d37f0aab6..bc83c150d6 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertCategory.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertCategory.cs @@ -6,4 +6,5 @@ public class AlertCategory public required Guid AlertCategoryId { get; init; } public required string Name { get; init; } + public List? AlertTypes { get; set; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertType.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertType.cs index d14da94aca..d3ce99a52b 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertType.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/DataStore/Postgres/Models/AlertType.cs @@ -12,4 +12,5 @@ public class AlertType public required string Name { get; init; } public required string? DqtSanctionCode { get; init; } public required ProhibitionLevel ProhibitionLevel { get; init; } + public required bool IsActive { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/AlertCreatedEvent.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/AlertCreatedEvent.cs index 344866a46f..e964f0cf26 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/AlertCreatedEvent.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/Events/AlertCreatedEvent.cs @@ -6,4 +6,6 @@ public record class AlertCreatedEvent : EventBase, IEventWithPersonId, IEventWit { public required Guid PersonId { get; init; } public required Alert Alert { get; init; } + public required string? Reason { get; init; } + public required Models.File? EvidenceFile { get; init; } } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.Core/ReferenceDataCache.cs b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ReferenceDataCache.cs index d4670c054e..d63d725d8e 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.Core/ReferenceDataCache.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.Core/ReferenceDataCache.cs @@ -160,16 +160,16 @@ public async Task GetAlertCategoryById(Guid alertCategoryId) return alertCategories.Single(ac => ac.AlertCategoryId == alertCategoryId, $"Could not find alert category with ID: '{alertCategoryId}'."); } - public async Task GetAlertTypeById(Guid alertTypeId) + public async Task GetAlertTypes(bool includeActiveOnly = false) { var alertTypes = await EnsureAlertTypes(); - return alertTypes.Single(at => at.AlertTypeId == alertTypeId, $"Could not find alert type with ID: '{alertTypeId}'."); + return alertTypes.Where(t => !includeActiveOnly || (includeActiveOnly && t.IsActive)).ToArray(); } - public async Task GetAlertTypes() + public async Task GetAlertTypeById(Guid alertTypeId) { var alertTypes = await EnsureAlertTypes(); - return alertTypes; + return alertTypes.Single(at => at.AlertTypeId == alertTypeId, $"Could not find alert type with ID: '{alertTypeId}'."); } public async Task GetAlertTypeByDqtSanctionCode(string dqtSanctionCode) @@ -230,7 +230,7 @@ private Task EnsureAlertCategories() => async () => { using var dbContext = dbContextFactory.CreateDbContext(); - return await dbContext.AlertCategories.ToArrayAsync(); + return await dbContext.AlertCategories.Include(c => c.AlertTypes).ToArrayAsync(); }); private Task EnsureAlertTypes() => diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/RequireFeatureEnabledFilter.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/RequireFeatureEnabledFilter.cs new file mode 100644 index 0000000000..da07f3d6a9 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Infrastructure/Filters/RequireFeatureEnabledFilter.cs @@ -0,0 +1,30 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace TeachingRecordSystem.SupportUi.Infrastructure.Filters; + +public class RequireFeatureEnabledFilter(IConfiguration configuration, string featureName) : IResourceFilter +{ + public void OnResourceExecuting(ResourceExecutingContext context) + { + var features = configuration.GetSection("EnabledFeatures").Get>(); + if (features is null || !features.Contains(featureName)) + { + context.Result = new NotFoundResult(); + } + } + + public void OnResourceExecuted(ResourceExecutedContext context) + { + } +} + +public class RequireFeatureEnabledFilterFactory(string featureName) : IFilterFactory, IOrderedFilter +{ + public bool IsReusable => false; + + public int Order => -300; + + public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) => + ActivatorUtilities.CreateInstance(serviceProvider, featureName); +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs index b8683a6045..1dfb4b5daf 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/JourneyNames.cs @@ -10,4 +10,5 @@ public static class JourneyNames public const string EditMqStartDate = nameof(EditMqStartDate); public const string EditMqStatus = nameof(EditMqStatus); public const string DeleteMq = nameof(DeleteMq); + public const string AddAlert = nameof(AddAlert); } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/AddAlertState.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/AddAlertState.cs new file mode 100644 index 0000000000..6f24388f9b --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/AddAlertState.cs @@ -0,0 +1,38 @@ +using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Serialization; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +public class AddAlertState +{ + public Guid? AlertTypeId { get; set; } + + public string? AlertTypeName { get; set; } + + public string? Details { get; set; } + + public string? Link { get; set; } + + public DateOnly? StartDate { get; set; } + + public DateOnly? EndDate { get; set; } + + public bool? HasEndDate { get; set; } + + public string? Reason { get; set; } + + public bool? UploadEvidence { get; set; } + + public Guid? EvidenceFileId { get; set; } + + public string? EvidenceFileName { get; set; } + + public string? EvidenceFileSizeDescription { get; set; } + + [JsonIgnore] + [MemberNotNullWhen(true, nameof(AlertTypeId), nameof(Details), nameof(StartDate))] + public bool IsComplete => + AlertTypeId.HasValue && + !string.IsNullOrWhiteSpace(Details) + && StartDate.HasValue; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/CheckAnswers.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/CheckAnswers.cshtml new file mode 100644 index 0000000000..7d8229a0c1 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/CheckAnswers.cshtml @@ -0,0 +1,93 @@ +@page "/alerts/add/check-answers/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.CheckAnswersModel +@{ + ViewBag.Title = "Check details and confirm alert"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName +

@ViewBag.Title

+ + + + Alert type + @Model.AlertTypeName + + Change + + + + Details + + + Change + + + + Link + + @if (Model.Link is not null) + { + @($"{Model.Link} (opens in new tab)") + } + else + { + + } + + + Change + + + + Start date + @Model.StartDate?.ToString("dd/MM/yyyy") + + Change + + + + End date + @Model.EndDate?.ToString("dd/MM/yyyy") + + Change + + + + Reason + + + Change + + + + Evidence + + @if (Model.UploadedEvidenceFileUrl is not null) + { + @($"{Model.EvidenceFileName} (opens in new tab)") + } + else + { + + } + + + Change + + + + +
+ Add alert + Cancel and return to record +
+
+
+
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/CheckAnswers.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/CheckAnswers.cshtml.cs new file mode 100644 index 0000000000..5ff1f6085c --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/CheckAnswers.cshtml.cs @@ -0,0 +1,124 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.DataStore.Postgres; +using TeachingRecordSystem.Core.DataStore.Postgres.Models; +using TeachingRecordSystem.Core.Services.Files; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class CheckAnswersModel( + TrsDbContext dbContext, + TrsLinkGenerator linkGenerator, + IFileService fileService, + IClock clock) : PageModel +{ + private static readonly TimeSpan _fileUrlExpiresAfter = TimeSpan.FromMinutes(15); + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + public Guid? AlertTypeId { get; set; } + + public string? AlertTypeName { get; set; } + + public string? Details { get; set; } + + public string? Link { get; set; } + + public DateOnly? StartDate { get; set; } + + public DateOnly? EndDate { get; set; } + + public string? Reason { get; set; } + + public string? EvidenceFileName { get; set; } + + public string? EvidenceFileSizeDescription { get; set; } + + public string? UploadedEvidenceFileUrl { get; set; } + + public async Task OnPost() + { + var now = clock.UtcNow; + + var alert = new Alert() + { + AlertId = Guid.NewGuid(), + CreatedOn = now, + UpdatedOn = now, + PersonId = PersonId, + AlertTypeId = AlertTypeId!.Value, + Details = Details, + ExternalLink = Link, + StartDate = StartDate, + EndDate = EndDate + }; + dbContext.Alerts.Add(alert); + + var createdEvent = new AlertCreatedEvent() + { + EventId = Guid.NewGuid(), + CreatedUtc = now, + RaisedBy = User.GetUserId(), + PersonId = PersonId, + Alert = EventModels.Alert.FromModel(alert), + Reason = Reason, + EvidenceFile = JourneyInstance!.State.EvidenceFileId is Guid fileId ? + new EventModels.File() + { + FileId = fileId, + Name = JourneyInstance.State.EvidenceFileName! + } : + null + }; + dbContext.AddEvent(createdEvent); + + await dbContext.SaveChangesAsync(); + + await JourneyInstance!.CompleteAsync(); + TempData.SetFlashSuccess("Alert added"); + + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + if (!JourneyInstance!.State.IsComplete) + { + context.Result = Redirect(linkGenerator.AlertAddType(PersonId, JourneyInstance.InstanceId)); + return; + } + + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + AlertTypeId = JourneyInstance!.State.AlertTypeId; + AlertTypeName = JourneyInstance!.State.AlertTypeName; + Details = JourneyInstance!.State.Details; + Link = JourneyInstance!.State.Link; + StartDate = JourneyInstance!.State.StartDate; + EndDate = JourneyInstance!.State.EndDate; + Reason = JourneyInstance!.State.Reason; + EvidenceFileName = JourneyInstance.State.EvidenceFileName; + UploadedEvidenceFileUrl = JourneyInstance!.State.EvidenceFileId is not null ? + await fileService.GetFileUrl(JourneyInstance!.State.EvidenceFileId!.Value, _fileUrlExpiresAfter) : + null; + + await next(); + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Details.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Details.cshtml new file mode 100644 index 0000000000..e643ebc0d5 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Details.cshtml @@ -0,0 +1,24 @@ +@page "/alerts/add/details/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.DetailsModel +@{ + ViewBag.Title = "Details"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName + + + +
+ Continue + Cancel and return to record +
+ +
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Details.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Details.cshtml.cs new file mode 100644 index 0000000000..81eae297dd --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Details.cshtml.cs @@ -0,0 +1,62 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class DetailsModel(TrsLinkGenerator linkGenerator) : PageModel +{ + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Required(ErrorMessage = "Enter details")] + [Display(Name = "Details")] + public string? Details { get; set; } + + public async Task OnPost() + { + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => + { + state.Details = Details; + }); + + return Redirect(FromCheckAnswers + ? linkGenerator.AlertAddCheckAnswers(PersonId, JourneyInstance.InstanceId) + : linkGenerator.AlertAddLink(PersonId, JourneyInstance.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) + { + if (JourneyInstance!.State.AlertTypeId is null) + { + context.Result = Redirect(linkGenerator.AlertAddType(PersonId, JourneyInstance.InstanceId)); + return; + } + + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + Details ??= JourneyInstance!.State.Details; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/EndDate.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/EndDate.cshtml new file mode 100644 index 0000000000..7b9f9a956c --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/EndDate.cshtml @@ -0,0 +1,35 @@ +@page "/alerts/add/end-date/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.EndDateModel +@{ + ViewBag.Title = "End date"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName +

@ViewBag.Title

+ + + + + Yes + + + + + No + + + +
+ Continue + Cancel and return to record +
+
+
+
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/EndDate.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/EndDate.cshtml.cs new file mode 100644 index 0000000000..e1afe976cd --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/EndDate.cshtml.cs @@ -0,0 +1,69 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.UiCommon.DataAnnotations; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class EndDateModel(TrsLinkGenerator linkGenerator) : PageModel +{ + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Display(Name = "Is there an end date for this alert?")] + [Required(ErrorMessage = "Select yes if there is an end date for this alert")] + public bool? HasEndDate { get; set; } + + [BindProperty] + [Display(Name = "End date")] + [RequiredIfOtherPropertyEquals(nameof(HasEndDate), ErrorMessage = "Enter an end date")] + public DateOnly? EndDate { get; set; } + + public async Task OnPost() + { + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => + { + state.HasEndDate = HasEndDate; + state.EndDate = HasEndDate!.Value ? EndDate : null; + }); + + return Redirect(FromCheckAnswers + ? linkGenerator.AlertAddCheckAnswers(PersonId, JourneyInstance.InstanceId) + : linkGenerator.AlertAddReason(PersonId, JourneyInstance.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) + { + if (JourneyInstance!.State.StartDate is null) + { + context.Result = Redirect(linkGenerator.AlertAddStartDate(PersonId, JourneyInstance.InstanceId)); + return; + } + + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + EndDate ??= JourneyInstance!.State.EndDate; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Index.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Index.cshtml new file mode 100644 index 0000000000..aa241ed833 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Index.cshtml @@ -0,0 +1,4 @@ +@page "/alerts/add" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.IndexModel +@{ +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Index.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Index.cshtml.cs new file mode 100644 index 0000000000..1ecaca44ad --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Index.cshtml.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), ActivatesJourney, RequireJourneyInstance] +public class IndexModel(TrsLinkGenerator linkGenerator) : PageModel +{ + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + public IActionResult OnGet() => Redirect(linkGenerator.AlertAddType(PersonId, JourneyInstance!.InstanceId)); +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Link.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Link.cshtml new file mode 100644 index 0000000000..13a3cac425 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Link.cshtml @@ -0,0 +1,26 @@ +@page "/alerts/add/link/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.LinkModel +@{ + ViewBag.Title = "Link"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName + + + Optional + + +
+ Continue + Cancel and return to record +
+
+
+
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Link.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Link.cshtml.cs new file mode 100644 index 0000000000..c1782043b2 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Link.cshtml.cs @@ -0,0 +1,68 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class LinkModel(TrsLinkGenerator linkGenerator) : PageModel +{ + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Display(Name = "Link")] + public string? Link { get; set; } + + public async Task OnPost() + { + if (!string.IsNullOrEmpty(Link) && + (!Uri.TryCreate(Link, UriKind.Absolute, out var uri) || + (uri.Scheme != "http" && uri.Scheme != "https"))) + { + ModelState.AddModelError(nameof(Link), "Enter a valid URL"); + } + + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => + { + state.Link = Link; + }); + + return Redirect(FromCheckAnswers + ? linkGenerator.AlertAddCheckAnswers(PersonId, JourneyInstance.InstanceId) + : linkGenerator.AlertAddStartDate(PersonId, JourneyInstance.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) + { + if (string.IsNullOrEmpty(JourneyInstance!.State.Details)) + { + context.Result = Redirect(linkGenerator.AlertAddDetails(PersonId, JourneyInstance.InstanceId)); + return; + } + + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + Link ??= JourneyInstance!.State.Link; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Reason.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Reason.cshtml new file mode 100644 index 0000000000..4809f5268b --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Reason.cshtml @@ -0,0 +1,50 @@ +@page "/alerts/add/reason/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.ReasonModel +@{ + ViewBag.Title = "Reason"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName + + + Optional + + + + + + + Yes + + @if (Model.EvidenceFileId is not null) + { + Currently uploaded file +

+ @($"{Model.EvidenceFileName} ({Model.EvidenceFileSizeDescription})") +

+ } + + Upload a file + +
+
+ + No + +
+
+ +
+ Continue + Cancel and return to record +
+
+
+
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Reason.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Reason.cshtml.cs new file mode 100644 index 0000000000..2706285575 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Reason.cshtml.cs @@ -0,0 +1,125 @@ +using System.ComponentModel.DataAnnotations; +using Humanizer; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; +using TeachingRecordSystem.Core.Services.Files; +using TeachingRecordSystem.SupportUi.Infrastructure.DataAnnotations; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class ReasonModel(TrsLinkGenerator linkGenerator, IFileService fileService) : PageModel +{ + public const int MaxFileSizeMb = 50; + + private static readonly TimeSpan _fileUrlExpiresAfter = TimeSpan.FromMinutes(15); + + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Display(Name = "Reason for adding")] + public string? Detail { get; set; } + + [BindProperty] + [Display(Name = "Upload evidence")] + [Required(ErrorMessage = "Select yes if you want to upload evidence")] + public bool? UploadEvidence { get; set; } + + [BindProperty] + [EvidenceFile] + [FileSize(MaxFileSizeMb * 1024 * 1024, ErrorMessage = "The selected file must be smaller than 50MB")] + public IFormFile? EvidenceFile { get; set; } + + public Guid? EvidenceFileId { get; set; } + + public string? EvidenceFileName { get; set; } + + public string? EvidenceFileSizeDescription { get; set; } + + public string? UploadedEvidenceFileUrl { get; set; } + + public async Task OnGet() + { + Detail ??= JourneyInstance!.State.Reason; + UploadedEvidenceFileUrl ??= JourneyInstance?.State.EvidenceFileId is not null ? + await fileService.GetFileUrl(JourneyInstance.State.EvidenceFileId.Value, _fileUrlExpiresAfter) : + null; + UploadEvidence ??= JourneyInstance?.State.UploadEvidence; + } + + public async Task OnPost() + { + if (UploadEvidence == true && EvidenceFileId is null && EvidenceFile is null) + { + ModelState.AddModelError(nameof(EvidenceFile), "Select a file"); + } + + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + if (UploadEvidence == true) + { + if (EvidenceFile is not null) + { + if (EvidenceFileId is not null) + { + await fileService.DeleteFile(EvidenceFileId.Value); + } + + using var stream = EvidenceFile.OpenReadStream(); + var evidenceFileId = await fileService.UploadFile(stream, EvidenceFile.ContentType); + await JourneyInstance!.UpdateStateAsync(state => + { + state.EvidenceFileId = evidenceFileId; + state.EvidenceFileName = EvidenceFile.FileName; + state.EvidenceFileSizeDescription = EvidenceFile.Length.Bytes().Humanize(); + }); + } + } + else if (EvidenceFileId is not null) + { + await fileService.DeleteFile(EvidenceFileId.Value); + await JourneyInstance!.UpdateStateAsync(state => + { + state.EvidenceFileId = null; + state.EvidenceFileName = null; + state.EvidenceFileSizeDescription = null; + }); + } + + await JourneyInstance!.UpdateStateAsync(state => + { + state.Reason = Detail; + state.UploadEvidence = UploadEvidence; + }); + + return Redirect(linkGenerator.AlertAddCheckAnswers(PersonId, JourneyInstance.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) + { + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + EvidenceFileId = JourneyInstance!.State.EvidenceFileId; + EvidenceFileName = JourneyInstance!.State.EvidenceFileName; + EvidenceFileSizeDescription = JourneyInstance!.State.EvidenceFileSizeDescription; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/StartDate.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/StartDate.cshtml new file mode 100644 index 0000000000..2661622e51 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/StartDate.cshtml @@ -0,0 +1,28 @@ +@page "/alerts/add/start-date/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.StartDateModel +@{ + ViewBag.Title = "Start date"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName + + + + + + + +
+ Continue + Cancel and return to record +
+
+
+
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/StartDate.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/StartDate.cshtml.cs new file mode 100644 index 0000000000..655395a4c9 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/StartDate.cshtml.cs @@ -0,0 +1,62 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class StartDateModel(TrsLinkGenerator linkGenerator) : PageModel +{ + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Required(ErrorMessage = "Enter a start date")] + [Display(Name = "Start date")] + public DateOnly? StartDate { get; set; } + + public async Task OnPost() + { + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + await JourneyInstance!.UpdateStateAsync(state => + { + state.StartDate = StartDate!.Value; + }); + + return Redirect(FromCheckAnswers + ? linkGenerator.AlertAddCheckAnswers(PersonId, JourneyInstance.InstanceId) + : linkGenerator.AlertAddEndDate(PersonId, JourneyInstance.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override void OnPageHandlerExecuting(PageHandlerExecutingContext context) + { + if (string.IsNullOrEmpty(JourneyInstance!.State.Details)) + { + context.Result = Redirect(linkGenerator.AlertAddDetails(PersonId, JourneyInstance.InstanceId)); + return; + } + + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + StartDate ??= JourneyInstance!.State.StartDate; + } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Type.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Type.cshtml new file mode 100644 index 0000000000..fa27a975fb --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Type.cshtml @@ -0,0 +1,40 @@ +@page "/alerts/add/type/{handler?}" +@model TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.TypeModel +@{ + ViewBag.Title = "Alert type"; +} + +@section BeforeContent { + Back +} + +
+
+
+ Add an alert - @Model.PersonName +

@ViewBag.Title

+ + + + Select one + + @foreach (var category in Model.Categories!) + { + @category.Name + @foreach (var type in category.AlertTypes) + { + + @type.Name + + } + } + + + +
+ Continue + Cancel and return to record +
+
+
+
diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Type.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Type.cshtml.cs new file mode 100644 index 0000000000..ced1a11d79 --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Alerts/AddAlert/Type.cshtml.cs @@ -0,0 +1,84 @@ +using System.ComponentModel.DataAnnotations; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +[Journey(JourneyNames.AddAlert), RequireJourneyInstance] +public class TypeModel( + TrsLinkGenerator linkGenerator, + ReferenceDataCache referenceDataCache) : PageModel +{ + public JourneyInstance? JourneyInstance { get; set; } + + [FromQuery] + public Guid PersonId { get; set; } + + [FromQuery] + public bool FromCheckAnswers { get; set; } + + public string? PersonName { get; set; } + + [BindProperty] + [Display(Name = "Alert Type")] + [Required(ErrorMessage = "Select an alert type")] + public Guid? AlertTypeId { get; set; } + + public AlertCategoryInfo[]? Categories { get; set; } + + public AlertTypeInfo[]? AlertTypes { get; set; } + + public async Task OnPost() + { + if (!ModelState.IsValid) + { + return this.PageWithErrors(); + } + + var selectedType = AlertTypes!.Single(t => t.AlertTypeId == AlertTypeId); + + await JourneyInstance!.UpdateStateAsync( + state => + { + state.AlertTypeId = AlertTypeId; + state.AlertTypeName = selectedType.Name; + }); + + return Redirect(FromCheckAnswers + ? linkGenerator.AlertAddCheckAnswers(PersonId, JourneyInstance.InstanceId) + : linkGenerator.AlertAddDetails(PersonId, JourneyInstance.InstanceId)); + } + + public async Task OnPostCancel() + { + await JourneyInstance!.DeleteAsync(); + return Redirect(linkGenerator.PersonAlerts(PersonId)); + } + + public override async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, PageHandlerExecutionDelegate next) + { + var personInfo = context.HttpContext.GetCurrentPersonFeature(); + + PersonName = personInfo.Name; + AlertTypeId ??= JourneyInstance!.State.AlertTypeId; + + var categories = await referenceDataCache.GetAlertCategories(); + Categories = categories.Select( + c => new AlertCategoryInfo( + c.Name, + c.AlertTypes!.Where(t => t.IsActive == true).Select(t => new AlertTypeInfo(t.AlertTypeId, t.Name)).OrderBy(t => t.Name).ToArray())) + .Where(c => c.AlertTypes.Length > 0) + .OrderBy(c => c.Name) + .ToArray(); + + var alertTypes = await referenceDataCache.GetAlertTypes(includeActiveOnly: true); + AlertTypes = alertTypes.Where(t => t.IsActive == true).Select(t => new AlertTypeInfo(t.AlertTypeId, t.Name)).ToArray(); + + await base.OnPageHandlerExecutionAsync(context, next); + } + + public record AlertTypeInfo(Guid AlertTypeId, string Name); + + public record AlertCategoryInfo(string Name, AlertTypeInfo[] AlertTypes); +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Alerts.cshtml b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Alerts.cshtml new file mode 100644 index 0000000000..fdb4e2908d --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Alerts.cshtml @@ -0,0 +1,4 @@ +@page "/persons/{personId}/alerts" +@model TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail.AlertsModel +@{ +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Alerts.cshtml.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Alerts.cshtml.cs new file mode 100644 index 0000000000..fa4c3b81ab --- /dev/null +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Pages/Persons/PersonDetail/Alerts.cshtml.cs @@ -0,0 +1,10 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.RazorPages; + +namespace TeachingRecordSystem.SupportUi.Pages.Persons.PersonDetail; + +public class AlertsModel : PageModel +{ + [FromRoute] + public Guid PersonId { get; set; } +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs index e43465c4c8..7e372f1f60 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/Program.cs @@ -98,6 +98,14 @@ model.Filters.Add(new CheckPersonExistsFilterFactory()); }); + options.Conventions.AddFolderApplicationModelConvention( + "/Alerts/AddAlert", + model => + { + model.Filters.Add(new RequireFeatureEnabledFilterFactory("Alerts")); + model.Filters.Add(new CheckPersonExistsFilterFactory()); + }); + options.Conventions.AddFolderApplicationModelConvention( "/Mqs/AddMq", model => @@ -211,6 +219,12 @@ requestDataKeys: ["personId"], appendUniqueKey: true)); + options.JourneyRegistry.RegisterJourney(new JourneyDescriptor( + JourneyNames.AddAlert, + typeof(TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert.AddAlertState), + requestDataKeys: ["personId"], + appendUniqueKey: true)); + options.JourneyRegistry.RegisterJourney(new JourneyDescriptor( JourneyNames.AddMq, typeof(TeachingRecordSystem.SupportUi.Pages.Mqs.AddMq.AddMqState), diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj index 9c5bca1b38..f1a6d54ca3 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TeachingRecordSystem.SupportUi.csproj @@ -23,5 +23,5 @@ - + diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs index 7c1c0e2449..496fa7f814 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/TrsLinkGenerator.cs @@ -19,8 +19,47 @@ public class TrsLinkGenerator(LinkGenerator linkGenerator) public string AlertAdd(Guid personId, JourneyInstanceId? journeyInstanceId) => GetRequiredPathByPage("/Alerts/AddAlert/Index", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); - public string AlertAddConfirm(Guid personId, JourneyInstanceId journeyInstanceId) => - GetRequiredPathByPage("/Alerts/AddAlert/Confirm", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + public string AlertAddType(Guid personId, JourneyInstanceId journeyInstanceId, bool? fromCheckAnswers = null) => + GetRequiredPathByPage("/Alerts/AddAlert/Type", routeValues: new { personId, fromCheckAnswers }, journeyInstanceId: journeyInstanceId); + + public string AlertAddTypeCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/Type", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddDetails(Guid personId, JourneyInstanceId journeyInstanceId, bool? fromCheckAnswers = null) => + GetRequiredPathByPage("/Alerts/AddAlert/Details", routeValues: new { personId, fromCheckAnswers }, journeyInstanceId: journeyInstanceId); + + public string AlertAddDetailsCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/Details", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddLink(Guid personId, JourneyInstanceId journeyInstanceId, bool? fromCheckAnswers = null) => + GetRequiredPathByPage("/Alerts/AddAlert/Link", routeValues: new { personId, fromCheckAnswers }, journeyInstanceId: journeyInstanceId); + + public string AlertAddLinkCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/Link", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddStartDate(Guid personId, JourneyInstanceId journeyInstanceId, bool? fromCheckAnswers = null) => + GetRequiredPathByPage("/Alerts/AddAlert/StartDate", routeValues: new { personId, fromCheckAnswers }, journeyInstanceId: journeyInstanceId); + + public string AlertAddStartDateCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/StartDate", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddEndDate(Guid personId, JourneyInstanceId journeyInstanceId, bool? fromCheckAnswers = null) => + GetRequiredPathByPage("/Alerts/AddAlert/EndDate", routeValues: new { personId, fromCheckAnswers }, journeyInstanceId: journeyInstanceId); + + public string AlertAddEndDateCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/EndDate", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddReason(Guid personId, JourneyInstanceId journeyInstanceId, bool? fromCheckAnswers = null) => + GetRequiredPathByPage("/Alerts/AddAlert/Reason", routeValues: new { personId, fromCheckAnswers }, journeyInstanceId: journeyInstanceId); + + public string AlertAddReasonCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/Reason", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddCheckAnswers(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/CheckAnswers", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); + + public string AlertAddConfirmCancel(Guid personId, JourneyInstanceId journeyInstanceId) => + GetRequiredPathByPage("/Alerts/AddAlert/CheckAnswers", "cancel", routeValues: new { personId }, journeyInstanceId: journeyInstanceId); public string AlertClose(Guid alertId, JourneyInstanceId? journeyInstanceId) => GetRequiredPathByPage("/Alerts/CloseAlert/Index", routeValues: new { alertId }, journeyInstanceId: journeyInstanceId); diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json index 3f5d6c4194..4c12b56820 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/appsettings.json @@ -13,5 +13,6 @@ "SignedOutCallbackPath": "/signout-oidc" }, "AllowedHosts": "*", - "ConcurrentNameChangeWindowSeconds": 5 + "ConcurrentNameChangeWindowSeconds": 5, + "EnabledFeatures": [ "Alerts" ] } diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/wwwroot/Styles/site.scss b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/wwwroot/Styles/site.scss index afeefc3dce..76420a8d67 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/wwwroot/Styles/site.scss +++ b/TeachingRecordSystem/src/TeachingRecordSystem.SupportUi/wwwroot/Styles/site.scss @@ -64,6 +64,17 @@ width: 200px; } +.trs-\!-width-300 { + width: 300px; +} + .trs-\!-max-width-none { max-width: none; } + +.trs-radios__divider--heading-s { + @include govuk-text-colour; + @include govuk-font($size: 19, $weight: bold); + width: 400px; + text-align: left; +} diff --git a/TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/DataAnnotations/RequiredIfOtherPropertyEqualsAttribute.cs b/TeachingRecordSystem/src/TeachingRecordSystem.UiCommon/DataAnnotations/RequiredIfOtherPropertyEqualsAttribute.cs similarity index 95% rename from TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/DataAnnotations/RequiredIfOtherPropertyEqualsAttribute.cs rename to TeachingRecordSystem/src/TeachingRecordSystem.UiCommon/DataAnnotations/RequiredIfOtherPropertyEqualsAttribute.cs index 89592e4124..064485b5d9 100644 --- a/TeachingRecordSystem/src/TeachingRecordSystem.AuthorizeAccess/DataAnnotations/RequiredIfOtherPropertyEqualsAttribute.cs +++ b/TeachingRecordSystem/src/TeachingRecordSystem.UiCommon/DataAnnotations/RequiredIfOtherPropertyEqualsAttribute.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace TeachingRecordSystem.AuthorizeAccess.DataAnnotations; +namespace TeachingRecordSystem.UiCommon.DataAnnotations; [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] public class RequiredIfOtherPropertyEqualsAttribute : RequiredAttribute diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/AlertTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/AlertTests.cs new file mode 100644 index 0000000000..ec39637ccc --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/AlertTests.cs @@ -0,0 +1,82 @@ +using Microsoft.Playwright; + +namespace TeachingRecordSystem.SupportUi.EndToEndTests; + +public class AlertTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task AddAlert() + { + var person = await TestData.CreatePerson(); + var alertType = await TestData.ReferenceDataCache.GetAlertTypeById(Guid.Parse("ed0cd700-3fb2-4db0-9403-ba57126090ed")); // Prohibition by the Secretary of State - misconduct + var details = TestData.GenerateLoremIpsum(); + var link = TestData.GenerateUrl(); + var startDate = new DateOnly(2021, 1, 1); + var endDate = new DateOnly(2023, 2, 10); + var reason = TestData.GenerateLoremIpsum(); + var evidenceFileName = "evidence.jpg"; + var evidenceFileMimeType = "image/jpeg"; + var personId = person.PersonId; + + await using var context = await HostFixture.CreateBrowserContext(); + var page = await context.NewPageAsync(); + + await page.GoToAddAlertPage(personId); + + await page.AssertOnAddAlertTypePage(); + + await page.CheckAsync($"text={alertType.Name}"); + + await page.ClickContinueButton(); + + await page.AssertOnAddAlertDetailsPage(); + + await page.FillAsync("label:text-is('Details')", details); + + await page.ClickContinueButton(); + + await page.AssertOnAddAlertLinkPage(); + + await page.FillAsync("label:text-is('Link')", link); + + await page.ClickContinueButton(); + + await page.AssertOnAddAlertStartDatePage(); + + await page.FillDateInput(startDate); + + await page.ClickContinueButton(); + + await page.AssertOnAddAlertEndDatePage(); + + await page.CheckAsync("text=Yes"); + await page.FillDateInput(endDate); + + await page.ClickContinueButton(); + + await page.AssertOnAddAlertReasonPage(); + + await page.FillAsync("label:text-is('Reason')", reason); + + await page.CheckAsync("text=Yes"); + await page + .GetByLabel("Upload file") + .SetInputFilesAsync( + new FilePayload() + { + Name = evidenceFileName, + MimeType = evidenceFileMimeType, + Buffer = TestData.JpegImage + }); + + await page.ClickContinueButton(); + + await page.AssertOnAddAlertCheckAnswersPage(); + + await page.ClickButton("Add alert"); + + await page.AssertOnPersonAlertsPage(personId); + + await page.AssertFlashMessage("Alert added"); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs index 9f2ea4e2f2..251e4ac01d 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.EndToEndTests/PageExtensions.cs @@ -31,6 +31,11 @@ public static async Task GoToPersonQualificationsPage(this IPage page, Guid pers await page.GotoAsync($"/persons/{personId}/qualifications"); } + public static async Task GoToAddAlertPage(this IPage page, Guid personId) + { + await page.GotoAsync($"/alerts/add?personId={personId}"); + } + public static async Task GoToAddMqPage(this IPage page, Guid personId) { await page.GotoAsync($"/mqs/add?personId={personId}"); @@ -112,9 +117,14 @@ public static async Task AssertOnPersonQualificationsPage(this IPage page, Guid await page.WaitForUrlPathAsync($"/persons/{personId}/qualifications"); } - public static async Task AssertOnAddAlertPage(this IPage page) + public static async Task AssertOnAddAlertTypePage(this IPage page) + { + await page.WaitForUrlPathAsync($"/alerts/add/type"); + } + + public static async Task AssertOnAddAlertDetailsPage(this IPage page) { - await page.WaitForUrlPathAsync($"/alerts/add"); + await page.WaitForUrlPathAsync($"/alerts/add/details"); } public static async Task AssertOnAddAlertConfirmPage(this IPage page) @@ -122,6 +132,31 @@ public static async Task AssertOnAddAlertConfirmPage(this IPage page) await page.WaitForUrlPathAsync($"/alerts/add/confirm"); } + public static async Task AssertOnAddAlertLinkPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/alerts/add/link"); + } + + public static async Task AssertOnAddAlertStartDatePage(this IPage page) + { + await page.WaitForUrlPathAsync($"/alerts/add/start-date"); + } + + public static async Task AssertOnAddAlertEndDatePage(this IPage page) + { + await page.WaitForUrlPathAsync($"/alerts/add/end-date"); + } + + public static async Task AssertOnAddAlertReasonPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/alerts/add/reason"); + } + + public static async Task AssertOnAddAlertCheckAnswersPage(this IPage page) + { + await page.WaitForUrlPathAsync($"/alerts/add/check-answers"); + } + public static async Task AssertOnAlertDetailPage(this IPage page, Guid alertId) { await page.WaitForUrlPathAsync($"/alerts/{alertId}"); @@ -324,7 +359,7 @@ public static async Task FillEmailInput(this IPage page, string email) public static async Task SubmitAddAlertIndexPage(this IPage page, string alertType, string? details, string link, DateOnly startDate) { - await page.AssertOnAddAlertPage(); + await page.AssertOnAddAlertTypePage(); await page.FillAsync("label:text-is('Alert type')", alertType); if (details != null) { diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/CheckAnswersTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/CheckAnswersTests.cs new file mode 100644 index 0000000000..e44759e56a --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/CheckAnswersTests.cs @@ -0,0 +1,212 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class CheckAnswersTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1), + EndDate = new DateOnly(2021, 1, 1), + UploadEvidence = false + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/check-answers?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_MissingDataInJourneyState_RedirectsToReasonPage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/reason?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1), + HasEndDate = true, + EndDate = new DateOnly(2021, 1, 1), + UploadEvidence = false + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1), + EndDate = new DateOnly(2021, 1, 1), + UploadEvidence = false + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/check-answers?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_Confirm_CreatesAlertCreatesEventCompletesJourneyAndRedirectsWithFlashMessage() + { + // Arrange + var alertTypeId = (await TestData.ReferenceDataCache.GetAlertTypes()).Where(a => a.IsActive).RandomOne().AlertTypeId; + var details = "Some details"; + var link = "http://example.com"; + var startDate = new DateOnly(2021, 1, 1); + var endDate = new DateOnly(2023, 2, 10); + var reason = "Some reason"; + var evidenceFileId = Guid.NewGuid(); + var evidenceFileName = "test.pdf"; + + var person = await TestData.CreatePerson(); + + EventPublisher.Clear(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = alertTypeId, + Details = details, + Link = link, + StartDate = startDate, + HasEndDate = true, + EndDate = endDate, + Reason = reason, + UploadEvidence = true, + EvidenceFileId = evidenceFileId, + EvidenceFileName = evidenceFileName + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/check-answers?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + var redirectResponse = await response.FollowRedirect(HttpClient); + var redirectDoc = await redirectResponse.GetDocument(); + AssertEx.HtmlDocumentHasFlashSuccess(redirectDoc, "Alert added"); + + EventPublisher.AssertEventsSaved(e => + { + var expectedAlertCreatedEvent = new AlertCreatedEvent() + { + EventId = Guid.Empty, + CreatedUtc = Clock.UtcNow, + RaisedBy = GetCurrentUserId(), + PersonId = person.PersonId, + Reason = reason, + Alert = new() + { + AlertId = Guid.Empty, + AlertTypeId = alertTypeId, + Details = details, + ExternalLink = link, + StartDate = startDate, + EndDate = endDate + }, + EvidenceFile = new() + { + FileId = evidenceFileId, + Name = evidenceFileName + } + }; + + var actualAlertCreatedEvent = Assert.IsType(e); + Assert.Equivalent(expectedAlertCreatedEvent with { EventId = actualAlertCreatedEvent.EventId }, actualAlertCreatedEvent); + }); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.True(journeyInstance.Completed); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + HasEndDate = true, + EndDate = new DateOnly(2021, 1, 1), + UploadEvidence = false + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/check-answers/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/DetailsTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/DetailsTests.cs new file mode 100644 index 0000000000..7524e55082 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/DetailsTests.cs @@ -0,0 +1,199 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class DetailsTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/details?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_MissingDataInJourneyState_Redirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/type?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(); + var details = "My details"; + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = details + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponse(response); + Assert.Equal(details, doc.GetElementById("Details")?.TextContent); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/details?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithMissingDataInJourneyState_Redirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/type?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_WhenDetailsIsBlank_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "Details", "Enter details"); + } + + [Fact] + public async Task Post_ValidInput_RedirectsToLinkPage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContentBuilder() + { + { "Details", "My details" } + } + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/link?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/details/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/EndDateTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/EndDateTests.cs new file mode 100644 index 0000000000..36aaff3b6a --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/EndDateTests.cs @@ -0,0 +1,242 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class EndDateTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/end-date?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_MissingDataInJourneyState_RedirectsTostartDatePage() + { + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/end-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/start-date?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/end-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(); + var endDate = new DateOnly(2023, 2, 10); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1), + EndDate = endDate + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/end-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponse(response); + Assert.Equal($"{endDate:%d}", doc.GetElementById("EndDate.Day")?.GetAttribute("value")); + Assert.Equal($"{endDate:%M}", doc.GetElementById("EndDate.Month")?.GetAttribute("value")); + Assert.Equal($"{endDate:yyyy}", doc.GetElementById("EndDate.Year")?.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1), + EndDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/end-date?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithMissingDataInJourneyState_RedirectsToStartDatePage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/end-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["EndDate.Day"] = "1", + ["EndDate.Month"] = "1", + ["EndDate.Year"] = "2021" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/start-date?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_WhenEndDateOptionIsYesAndNoEndDateIsEntered_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/end-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["HasEndDate"] = "True" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "HasEndDate", "Select yes if there is an end date for this alert"); + } + + [Fact] + public async Task Post_WithValidInput_RedirectsToReasonPage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/end-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["HasEndDate"] = "True", + ["EndDate.Day"] = "2", + ["EndDate.Month"] = "3", + ["EndDate.Year"] = "2023" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/reason?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/end-date/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/IndexTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/IndexTests.cs new file mode 100644 index 0000000000..13f2722897 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/IndexTests.cs @@ -0,0 +1,21 @@ +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class IndexTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_RedirectsToAlertAddCategory() + { + // Arrange + var person = await TestData.CreatePerson(); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add?personId={person.PersonId}"); + + // Act + var response = await HttpClient.SendAsync(request); // Initializes journey + response = await response.FollowRedirect(HttpClient); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/category?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/LinkTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/LinkTests.cs new file mode 100644 index 0000000000..e06f5f4a53 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/LinkTests.cs @@ -0,0 +1,213 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class LinkTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/link?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_MissingDataInJourneyState_Redirects() + { + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/link?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/details?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/link?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(); + var link = TestData.GenerateUrl(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + Link = link + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/link?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponse(response); + Assert.Equal(link, doc.GetElementById("Link")?.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/link?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithMissingDataInJourneyState_Redirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/link?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/details?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_WithInvalidLinkUrl_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/link?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["Link"] = "bob" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "Link", "Enter a valid URL"); + } + + [Theory] + [InlineData("http://example.com")] + [InlineData("")] + public async Task Post_ValidInput_RedirectsToStartDatePage(string linkUrl) + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/link?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["Link"] = linkUrl + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/start-date?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/link/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/ReasonTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/ReasonTests.cs new file mode 100644 index 0000000000..d90e6572ae --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/ReasonTests.cs @@ -0,0 +1,299 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class ReasonTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/reason?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(); + var reason = "My Reason"; + var evidenceFileId = Guid.NewGuid(); + var evidenceFileName = "evidence.jpg"; + var evidenceFileSizeDescription = "1 MB"; + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2021, 1, 1), + Reason = reason, + UploadEvidence = true, + EvidenceFileId = evidenceFileId, + EvidenceFileName = evidenceFileName, + EvidenceFileSizeDescription = evidenceFileSizeDescription + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponse(response); + Assert.Equal(reason, doc.GetElementById("Detail")?.TextContent); + var radioButtons = doc.GetElementsByName("UploadEvidence"); + var selectedRadioButton = radioButtons.Single(r => r.HasAttribute("checked")); + Assert.Equal("True", selectedRadioButton.GetAttribute("value")); + var uploadedEvidenceLink = doc.GetElementByTestId("uploaded-evidence-link"); + Assert.NotNull(uploadedEvidenceLink); + Assert.Equal($"{evidenceFileName} ({evidenceFileSizeDescription})", uploadedEvidenceLink!.TextContent); + + } + + [Fact] + public async Task Get_MissingDataInJourneyState_RedirectsToStartDatePage() + { + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/start-date?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1) + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/reason?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["Reason"] = "Reason", + ["UploadEvidence"] = "False" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WhenNoUploadEvidenceOptionIsSelected_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["Reason"] = "Reason" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "UploadEvidence", "Select yes if you want to upload evidence"); + } + + [Fact] + public async Task Post_WhenUploadEvidenceOptionIsYesAndNoFileIsSelected_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["Reason"] = "Reason", + ["UploadEvidence"] = "True" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "EvidenceFile", "Select a file"); + } + + [Fact] + public async Task Post_WhenEvidenceFileIsInvalidType_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var multipartContent = CreateFormFileUpload(".cs"); + multipartContent.Add(new StringContent("My reason to add an alert"), "Reason"); + multipartContent.Add(new StringContent("True"), "UploadEvidence"); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = multipartContent + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "EvidenceFile", "The selected file must be a BMP, CSV, DOC, DOCX, EML, JPEG, JPG, MBOX, MSG, ODS, ODT, PDF, PNG, TIF, TXT, XLS or XLSX"); + } + + [Fact] + public async Task Post_ValidInput_RedirectsToCheckAnswersPage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var multipartContent = CreateFormFileUpload(".pdf"); + multipartContent.Add(new StringContent("My reason to add an alert"), "Reason"); + multipartContent.Add(new StringContent("True"), "UploadEvidence"); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/reason?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = multipartContent + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/check-answers?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = new DateOnly(2022, 1, 1), + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/reason/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private MultipartFormDataContent CreateFormFileUpload(string fileExtension) + { + var byteArrayContent = new ByteArrayContent(new byte[] { }); + byteArrayContent.Headers.Add("Content-Type", "application/octet-stream"); + + var multipartContent = new MultipartFormDataContent + { + { byteArrayContent, "EvidenceFile", $"evidence{fileExtension}" } + }; + + return multipartContent; + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/StartDateTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/StartDateTests.cs new file mode 100644 index 0000000000..82f83f312c --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/StartDateTests.cs @@ -0,0 +1,233 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class StartDateTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/start-date?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_MissingDataInJourneyState_RedirectsToDetailsPage() + { + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/details?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(); + var startDate = new DateOnly(2021, 1, 1); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details", + StartDate = startDate + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponse(response); + Assert.Equal($"{startDate:%d}", doc.GetElementById("StartDate.Day")?.GetAttribute("value")); + Assert.Equal($"{startDate:%M}", doc.GetElementById("StartDate.Month")?.GetAttribute("value")); + Assert.Equal($"{startDate:yyyy}", doc.GetElementById("StartDate.Year")?.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/start-date?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["StartDate.Day"] = "1", + ["StartDate.Month"] = "1", + ["StartDate.Year"] = "2021" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WithMissingDataInJourneyState_RedirectsToDetailsPage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid() + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["StartDate.Day"] = "1", + ["StartDate.Month"] = "1", + ["StartDate.Year"] = "2021" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/details?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_WhenNoStartDateIsEntered_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "StartDate", "Enter a start date"); + } + + [Fact] + public async Task Post_WithValidInput_RedirectsToEndDatePage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/start-date?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["StartDate.Day"] = "1", + ["StartDate.Month"] = "1", + ["StartDate.Year"] = "2021" + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.StartsWith($"/alerts/add/end-date?personId={person.PersonId}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = Guid.NewGuid(), + Details = "Details" + }); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/start-date/cancel?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/TypeTests.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/TypeTests.cs new file mode 100644 index 0000000000..08c226a276 --- /dev/null +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.SupportUi.Tests/PageTests/Alerts/AddAlert/TypeTests.cs @@ -0,0 +1,154 @@ +using TeachingRecordSystem.SupportUi.Pages.Alerts.AddAlert; + +namespace TeachingRecordSystem.SupportUi.Tests.PageTests.Alerts.AddAlert; + +public class TypeTests(HostFixture hostFixture) : TestBase(hostFixture) +{ + [Fact] + public async Task Get_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/type?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Get_WithPersonIdForValidPerson_ReturnsOk() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/type?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status200OK, (int)response.StatusCode); + } + + [Fact] + public async Task Get_ValidRequestWithPopulatedDataInJourneyState_PopulatesModelFromJourneyState() + { + // Arrange + var person = await TestData.CreatePerson(); + var alertType = await TestData.ReferenceDataCache.GetAlertTypeById(Guid.Parse("ed0cd700-3fb2-4db0-9403-ba57126090ed")); // Prohibition by the Secretary of State - misconduct + + var journeyInstance = await CreateJourneyInstance(person.PersonId, new AddAlertState + { + AlertTypeId = alertType.AlertTypeId + }); + + var request = new HttpRequestMessage(HttpMethod.Get, $"/alerts/add/type?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + var doc = await AssertEx.HtmlResponse(response); + var radioButtons = doc.GetElementsByName("AlertTypeId"); + var selectedRadioButton = radioButtons.Single(r => r.HasAttribute("checked")); + Assert.Equal(alertType.AlertTypeId.ToString(), selectedRadioButton.GetAttribute("value")); + } + + [Fact] + public async Task Post_WithPersonIdForNonExistentPerson_ReturnsNotFound() + { + // Arrange + var personId = Guid.NewGuid(); + + var journeyInstance = await CreateJourneyInstance(personId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/type?personId={personId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["AlertTypeId"] = Guid.NewGuid().ToString() + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status404NotFound, (int)response.StatusCode); + } + + [Fact] + public async Task Post_WhenAlertTypeHasNotBeenSelected_ReturnsError() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/type?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + await AssertEx.HtmlResponseHasError(response, "AlertTypeId", "Select an alert type"); + } + + [Fact] + public async Task Post_ValidInput_RedirectsToDetailsPage() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/type?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}") + { + Content = new FormUrlEncodedContent(new Dictionary + { + ["AlertTypeId"] = Guid.NewGuid().ToString() + }) + }; + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + Assert.Equal($"/alerts/add/details?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}", response.Headers.Location?.OriginalString); + } + + [Fact] + public async Task Post_Cancel_DeletesJourneyAndRedirects() + { + // Arrange + var person = await TestData.CreatePerson(); + + var journeyInstance = await CreateJourneyInstance(person.PersonId); + + var request = new HttpRequestMessage(HttpMethod.Post, $"/alerts/add/type/CANCEL?personId={person.PersonId}&{journeyInstance.GetUniqueIdQueryParameter()}"); + + // Act + var response = await HttpClient.SendAsync(request); + + // Assert + Assert.Equal(StatusCodes.Status302Found, (int)response.StatusCode); + + journeyInstance = await ReloadJourneyInstance(journeyInstance); + Assert.Null(journeyInstance); + } + + private async Task> CreateJourneyInstance(Guid personId, AddAlertState? state = null) => + await CreateJourneyInstance( + JourneyNames.AddAlert, + state ?? new AddAlertState(), + new KeyValuePair("personId", personId)); +} diff --git a/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/TestData.CreatePerson.cs b/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/TestData.CreatePerson.cs index 10a19872d4..4c45ce1ec0 100644 --- a/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/TestData.CreatePerson.cs +++ b/TeachingRecordSystem/tests/TeachingRecordSystem.TestCommon/TestData.CreatePerson.cs @@ -630,6 +630,7 @@ public class CreatePersonAlertBuilder private Option _externalLink; private Option _startDate; private Option _endDate; + private Option _reason; private Option _createdByUser; private Option _createdUtc; @@ -675,6 +676,12 @@ public CreatePersonAlertBuilder WithEndDate(DateOnly? endDate) return this; } + public CreatePersonAlertBuilder WithReason(string? reason) + { + _reason = Option.Some(reason); + return this; + } + public CreatePersonAlertBuilder WithCreatedUtc(DateTime? createdUtc) { _createdUtc = Option.Some(createdUtc); @@ -701,6 +708,7 @@ internal async Task Execute(CreatePersonBuilder createPersonBuilder, Test var externalLink = _externalLink.ValueOr(testData.GenerateUrl()); var startDate = _startDate.ValueOr(testData.GenerateDate(min: new DateOnly(2000, 1, 1))); var endDate = _endDate.ValueOr((DateOnly?)null); + var reason = _reason.ValueOr(testData.GenerateLoremIpsum()); var createdByUser = _createdByUser.ValueOr(EventModels.RaisedByUserInfo.FromUserId(Core.DataStore.Postgres.Models.SystemUser.SystemUserId)); var createdUtc = _createdUtc.ValueOr(testData.Clock.UtcNow); @@ -727,7 +735,9 @@ internal async Task Execute(CreatePersonBuilder createPersonBuilder, Test CreatedUtc = createdUtc!.Value, RaisedBy = createdByUser, Alert = TeachingRecordSystem.Core.Events.Models.Alert.FromModel(alert), - PersonId = personId + PersonId = personId, + Reason = reason, + EvidenceFile = null }; dbContext.AddEvent(createdEvent);