diff --git a/backend/webapi/Data/Configuration/PrpAuthorizedLicenceConfiguration.cs b/backend/webapi/Data/Configuration/PrpAuthorizedLicenceConfiguration.cs deleted file mode 100644 index c2ff6eb16..000000000 --- a/backend/webapi/Data/Configuration/PrpAuthorizedLicenceConfiguration.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Pidp.Data.Configuration; - -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Metadata.Builders; - -using Pidp.Models; - -public class PrpAuthorizedLicenceConfiguration : IEntityTypeConfiguration -{ - public virtual void Configure(EntityTypeBuilder builder) - { - builder.HasIndex(x => x.LicenceNumber) - .IsUnique(); - } -} diff --git a/backend/webapi/Data/Migrations/20241115192035_DeletePRPAuthorizedLicenceTable.Designer.cs b/backend/webapi/Data/Migrations/20241115192035_DeletePRPAuthorizedLicenceTable.Designer.cs new file mode 100644 index 000000000..ab563a2d2 --- /dev/null +++ b/backend/webapi/Data/Migrations/20241115192035_DeletePRPAuthorizedLicenceTable.Designer.cs @@ -0,0 +1,1553 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Pidp.Data; + +#nullable disable + +namespace Pidp.Data.Migrations +{ + [DbContext(typeof(PidpDbContext))] + [Migration("20241115192035_DeletePRPAuthorizedLicenceTable")] + partial class DeletePRPAuthorizedLicenceTable + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Pidp.Models.AccessRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessTypeCode") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.Property("RequestedOn") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("PartyId"); + + b.ToTable("AccessRequest"); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("Pidp.Models.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("City") + .IsRequired() + .HasColumnType("text"); + + b.Property("CountryCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("Postal") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProvinceCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Street") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CountryCode"); + + b.HasIndex("ProvinceCode"); + + b.ToTable("Address"); + + b.HasDiscriminator("Discriminator").HasValue("Address"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Pidp.Models.Banner", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Component") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Header") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Banner"); + }); + + modelBuilder.Entity("Pidp.Models.BusinessEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Severity") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator("Discriminator").HasValue("BusinessEvent"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Pidp.Models.ClientLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalInformation") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("LogLevel") + .HasColumnType("integer"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ClientLog"); + }); + + modelBuilder.Entity("Pidp.Models.Credential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IdpId") + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PartyId"); + + b.HasIndex("UserId") + .IsUnique() + .HasFilter("\"UserId\" != '00000000-0000-0000-0000-000000000000'"); + + b.ToTable("Credential", t => + { + t.HasCheckConstraint("CHK_Credential_AtLeastOneIdentifier", "((\"UserId\" != '00000000-0000-0000-0000-000000000000') or (\"IdpId\" is not null))"); + }); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkErrorLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CredentialLinkTicketId") + .HasColumnType("integer"); + + b.Property("ExistingCredentialId") + .HasColumnType("integer"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CredentialLinkTicketId"); + + b.HasIndex("ExistingCredentialId"); + + b.ToTable("CredentialLinkErrorLog"); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Claimed") + .HasColumnType("boolean"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LinkToIdentityProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.Property("Token") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PartyId"); + + b.ToTable("CredentialLinkTicket"); + }); + + modelBuilder.Entity("Pidp.Models.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Cc") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("DateSent") + .HasColumnType("timestamp with time zone"); + + b.Property("LatestStatus") + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("MsgId") + .HasColumnType("uuid"); + + b.Property("SendType") + .IsRequired() + .HasColumnType("text"); + + b.Property("SentTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("StatusMessage") + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdateCount") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("EmailLog"); + }); + + modelBuilder.Entity("Pidp.Models.Endorsement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Endorsement"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("EndorsementId") + .HasColumnType("integer"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EndorsementId"); + + b.HasIndex("PartyId"); + + b.ToTable("EndorsementRelationship"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalInformation") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PreApproved") + .HasColumnType("boolean"); + + b.Property("ReceivingPartyId") + .HasColumnType("integer"); + + b.Property("RecipientEmail") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequestingPartyId") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("StatusDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Token") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ReceivingPartyId"); + + b.HasIndex("RequestingPartyId"); + + b.ToTable("EndorsementRequest"); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.AccessType", b => + { + b.Property("Code") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("AccessTypeLookup"); + + b.HasData( + new + { + Code = 1, + Name = "Special Authority eForms" + }, + new + { + Code = 2, + Name = "HCIMWeb Account Transfer" + }, + new + { + Code = 3, + Name = "HCIMWeb Enrolment" + }, + new + { + Code = 4, + Name = "Driver Medical Fitness" + }, + new + { + Code = 5, + Name = "MS Teams for Clinical Use - Privacy Officer" + }, + new + { + Code = 6, + Name = "Prescription Refill eForm for Pharmacists" + }, + new + { + Code = 7, + Name = "Provider Reporting Portal" + }, + new + { + Code = 8, + Name = "MS Teams for Clinical Use - Clinic Member" + }, + new + { + Code = 9, + Name = "Access Harmonization User Access Agreement" + }, + new + { + Code = 10, + Name = "Immunization Entry eForm" + }); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.College", b => + { + b.Property("Code") + .HasColumnType("integer"); + + b.Property("Acronym") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("CollegeLookup"); + + b.HasData( + new + { + Code = 1, + Acronym = "CPSBC", + Name = "College of Physicians and Surgeons of BC" + }, + new + { + Code = 2, + Acronym = "CPBC", + Name = "College of Pharmacists of BC" + }, + new + { + Code = 3, + Acronym = "BCCNM", + Name = "BC College of Nurses and Midwives" + }, + new + { + Code = 4, + Acronym = "CNPBC", + Name = "College of Naturopathic Physicians of BC" + }, + new + { + Code = 5, + Acronym = "CDSBC", + Name = "College of Dental Surgeons of British Columbia" + }, + new + { + Code = 6, + Acronym = "COBC", + Name = "College of Optometrists of British Columbia" + }); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.Country", b => + { + b.Property("Code") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("CountryLookup"); + + b.HasData( + new + { + Code = "CA", + Name = "Canada" + }, + new + { + Code = "US", + Name = "United States" + }); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.Province", b => + { + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("ProvinceLookup"); + + b.HasData( + new + { + Code = "AB", + CountryCode = "CA", + Name = "Alberta" + }, + new + { + Code = "BC", + CountryCode = "CA", + Name = "British Columbia" + }, + new + { + Code = "MB", + CountryCode = "CA", + Name = "Manitoba" + }, + new + { + Code = "NB", + CountryCode = "CA", + Name = "New Brunswick" + }, + new + { + Code = "NL", + CountryCode = "CA", + Name = "Newfoundland and Labrador" + }, + new + { + Code = "NS", + CountryCode = "CA", + Name = "Nova Scotia" + }, + new + { + Code = "ON", + CountryCode = "CA", + Name = "Ontario" + }, + new + { + Code = "PE", + CountryCode = "CA", + Name = "Prince Edward Island" + }, + new + { + Code = "QC", + CountryCode = "CA", + Name = "Quebec" + }, + new + { + Code = "SK", + CountryCode = "CA", + Name = "Saskatchewan" + }, + new + { + Code = "NT", + CountryCode = "CA", + Name = "Northwest Territories" + }, + new + { + Code = "NU", + CountryCode = "CA", + Name = "Nunavut" + }, + new + { + Code = "YT", + CountryCode = "CA", + Name = "Yukon" + }, + new + { + Code = "AL", + CountryCode = "US", + Name = "Alabama" + }, + new + { + Code = "AK", + CountryCode = "US", + Name = "Alaska" + }, + new + { + Code = "AS", + CountryCode = "US", + Name = "American Samoa" + }, + new + { + Code = "AZ", + CountryCode = "US", + Name = "Arizona" + }, + new + { + Code = "AR", + CountryCode = "US", + Name = "Arkansas" + }, + new + { + Code = "CA", + CountryCode = "US", + Name = "California" + }, + new + { + Code = "CO", + CountryCode = "US", + Name = "Colorado" + }, + new + { + Code = "CT", + CountryCode = "US", + Name = "Connecticut" + }, + new + { + Code = "DE", + CountryCode = "US", + Name = "Delaware" + }, + new + { + Code = "DC", + CountryCode = "US", + Name = "District of Columbia" + }, + new + { + Code = "FL", + CountryCode = "US", + Name = "Florida" + }, + new + { + Code = "GA", + CountryCode = "US", + Name = "Georgia" + }, + new + { + Code = "GU", + CountryCode = "US", + Name = "Guam" + }, + new + { + Code = "HI", + CountryCode = "US", + Name = "Hawaii" + }, + new + { + Code = "ID", + CountryCode = "US", + Name = "Idaho" + }, + new + { + Code = "IL", + CountryCode = "US", + Name = "Illinois" + }, + new + { + Code = "IN", + CountryCode = "US", + Name = "Indiana" + }, + new + { + Code = "IA", + CountryCode = "US", + Name = "Iowa" + }, + new + { + Code = "KS", + CountryCode = "US", + Name = "Kansas" + }, + new + { + Code = "KY", + CountryCode = "US", + Name = "Kentucky" + }, + new + { + Code = "LA", + CountryCode = "US", + Name = "Louisiana" + }, + new + { + Code = "ME", + CountryCode = "US", + Name = "Maine" + }, + new + { + Code = "MD", + CountryCode = "US", + Name = "Maryland" + }, + new + { + Code = "MA", + CountryCode = "US", + Name = "Massachusetts" + }, + new + { + Code = "MI", + CountryCode = "US", + Name = "Michigan" + }, + new + { + Code = "MN", + CountryCode = "US", + Name = "Minnesota" + }, + new + { + Code = "MS", + CountryCode = "US", + Name = "Mississippi" + }, + new + { + Code = "MO", + CountryCode = "US", + Name = "Missouri" + }, + new + { + Code = "MT", + CountryCode = "US", + Name = "Montana" + }, + new + { + Code = "NE", + CountryCode = "US", + Name = "Nebraska" + }, + new + { + Code = "NV", + CountryCode = "US", + Name = "Nevada" + }, + new + { + Code = "NH", + CountryCode = "US", + Name = "New Hampshire" + }, + new + { + Code = "NJ", + CountryCode = "US", + Name = "New Jersey" + }, + new + { + Code = "NM", + CountryCode = "US", + Name = "New Mexico" + }, + new + { + Code = "NY", + CountryCode = "US", + Name = "New York" + }, + new + { + Code = "NC", + CountryCode = "US", + Name = "North Carolina" + }, + new + { + Code = "ND", + CountryCode = "US", + Name = "North Dakota" + }, + new + { + Code = "MP", + CountryCode = "US", + Name = "Northern Mariana Islands" + }, + new + { + Code = "OH", + CountryCode = "US", + Name = "Ohio" + }, + new + { + Code = "OK", + CountryCode = "US", + Name = "Oklahoma" + }, + new + { + Code = "OR", + CountryCode = "US", + Name = "Oregon" + }, + new + { + Code = "PA", + CountryCode = "US", + Name = "Pennsylvania" + }, + new + { + Code = "PR", + CountryCode = "US", + Name = "Puerto Rico" + }, + new + { + Code = "RI", + CountryCode = "US", + Name = "Rhode Island" + }, + new + { + Code = "SC", + CountryCode = "US", + Name = "South Carolina" + }, + new + { + Code = "SD", + CountryCode = "US", + Name = "South Dakota" + }, + new + { + Code = "TN", + CountryCode = "US", + Name = "Tennessee" + }, + new + { + Code = "TX", + CountryCode = "US", + Name = "Texas" + }, + new + { + Code = "UM", + CountryCode = "US", + Name = "United States Minor Outlying Islands" + }, + new + { + Code = "UT", + CountryCode = "US", + Name = "Utah" + }, + new + { + Code = "VT", + CountryCode = "US", + Name = "Vermont" + }, + new + { + Code = "VI", + CountryCode = "US", + Name = "Virgin Islands, U.S." + }, + new + { + Code = "VA", + CountryCode = "US", + Name = "Virginia" + }, + new + { + Code = "WA", + CountryCode = "US", + Name = "Washington" + }, + new + { + Code = "WV", + CountryCode = "US", + Name = "West Virginia" + }, + new + { + Code = "WI", + CountryCode = "US", + Name = "Wisconsin" + }, + new + { + Code = "WY", + CountryCode = "US", + Name = "Wyoming" + }); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinic", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PrivacyOfficerId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PrivacyOfficerId"); + + b.ToTable("MSTeamsClinic"); + }); + + modelBuilder.Entity("Pidp.Models.Party", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Birthdate") + .HasColumnType("date"); + + b.Property("Cpn") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("OpId") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("PreferredFirstName") + .HasColumnType("text"); + + b.Property("PreferredLastName") + .HasColumnType("text"); + + b.Property("PreferredMiddleName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OpId") + .IsUnique(); + + b.ToTable("Party"); + }); + + modelBuilder.Entity("Pidp.Models.PartyLicenceDeclaration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CollegeCode") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenceNumber") + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollegeCode"); + + b.HasIndex("PartyId") + .IsUnique(); + + b.ToTable("PartyLicenceDeclaration"); + }); + + modelBuilder.Entity("Pidp.Models.HcimAccountTransfer", b => + { + b.HasBaseType("Pidp.Models.AccessRequest"); + + b.Property("LdapUsername") + .IsRequired() + .HasColumnType("text"); + + b.ToTable("HcimAccountTransfer"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicMemberEnrolment", b => + { + b.HasBaseType("Pidp.Models.AccessRequest"); + + b.Property("ClinicId") + .HasColumnType("integer"); + + b.HasIndex("ClinicId"); + + b.ToTable("MSTeamsClinicMemberEnrolment"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicAddress", b => + { + b.HasBaseType("Pidp.Models.Address"); + + b.Property("ClinicId") + .HasColumnType("integer"); + + b.HasIndex("ClinicId") + .IsUnique(); + + b.ToTable("Address"); + + b.HasDiscriminator().HasValue("MSTeamsClinicAddress"); + }); + + modelBuilder.Entity("Pidp.Models.BCProviderPasswordReset", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("BCProviderPasswordReset"); + }); + + modelBuilder.Entity("Pidp.Models.CollegeLicenceSearchError", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("CollegeLicenceSearchError"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleAssigned", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("LicenceStatusRoleAssigned"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleUnassigned", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("LicenceStatusRoleUnassigned"); + }); + + modelBuilder.Entity("Pidp.Models.PartyNotInPlr", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("PartyNotInPlr"); + }); + + modelBuilder.Entity("Pidp.Models.AccessRequest", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany("AccessRequests") + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.Address", b => + { + b.HasOne("Pidp.Models.Lookups.Country", "Country") + .WithMany() + .HasForeignKey("CountryCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.Lookups.Province", "Province") + .WithMany() + .HasForeignKey("ProvinceCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + + b.Navigation("Province"); + }); + + modelBuilder.Entity("Pidp.Models.Credential", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany("Credentials") + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkErrorLog", b => + { + b.HasOne("Pidp.Models.CredentialLinkTicket", "CredentialLinkTicket") + .WithMany() + .HasForeignKey("CredentialLinkTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.Credential", "ExistingCredential") + .WithMany() + .HasForeignKey("ExistingCredentialId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CredentialLinkTicket"); + + b.Navigation("ExistingCredential"); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkTicket", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRelationship", b => + { + b.HasOne("Pidp.Models.Endorsement", "Endorsement") + .WithMany("EndorsementRelationships") + .HasForeignKey("EndorsementId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Endorsement"); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRequest", b => + { + b.HasOne("Pidp.Models.Party", "ReceivingParty") + .WithMany() + .HasForeignKey("ReceivingPartyId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Pidp.Models.Party", "RequestingParty") + .WithMany() + .HasForeignKey("RequestingPartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReceivingParty"); + + b.Navigation("RequestingParty"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinic", b => + { + b.HasOne("Pidp.Models.Party", "PrivacyOfficer") + .WithMany() + .HasForeignKey("PrivacyOfficerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PrivacyOfficer"); + }); + + modelBuilder.Entity("Pidp.Models.PartyLicenceDeclaration", b => + { + b.HasOne("Pidp.Models.Lookups.College", "College") + .WithMany() + .HasForeignKey("CollegeCode"); + + b.HasOne("Pidp.Models.Party", "Party") + .WithOne("LicenceDeclaration") + .HasForeignKey("Pidp.Models.PartyLicenceDeclaration", "PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("College"); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.HcimAccountTransfer", b => + { + b.HasOne("Pidp.Models.AccessRequest", null) + .WithOne() + .HasForeignKey("Pidp.Models.HcimAccountTransfer", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicMemberEnrolment", b => + { + b.HasOne("Pidp.Models.MSTeamsClinic", "Clinic") + .WithMany() + .HasForeignKey("ClinicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.AccessRequest", null) + .WithOne() + .HasForeignKey("Pidp.Models.MSTeamsClinicMemberEnrolment", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clinic"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicAddress", b => + { + b.HasOne("Pidp.Models.MSTeamsClinic", "Clinic") + .WithOne("Address") + .HasForeignKey("Pidp.Models.MSTeamsClinicAddress", "ClinicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clinic"); + }); + + modelBuilder.Entity("Pidp.Models.BCProviderPasswordReset", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.CollegeLicenceSearchError", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleAssigned", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleUnassigned", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.PartyNotInPlr", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.Endorsement", b => + { + b.Navigation("EndorsementRelationships"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinic", b => + { + b.Navigation("Address") + .IsRequired(); + }); + + modelBuilder.Entity("Pidp.Models.Party", b => + { + b.Navigation("AccessRequests"); + + b.Navigation("Credentials"); + + b.Navigation("LicenceDeclaration"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/webapi/Data/Migrations/20241115192035_DeletePRPAuthorizedLicenceTable.cs b/backend/webapi/Data/Migrations/20241115192035_DeletePRPAuthorizedLicenceTable.cs new file mode 100644 index 000000000..1486df52e --- /dev/null +++ b/backend/webapi/Data/Migrations/20241115192035_DeletePRPAuthorizedLicenceTable.cs @@ -0,0 +1,42 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace Pidp.Data.Migrations +{ + /// + public partial class DeletePRPAuthorizedLicenceTable : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PrpAuthorizedLicence"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "PrpAuthorizedLicence", + columns: table => new + { + Id = table.Column(type: "integer", nullable: false) + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), + Claimed = table.Column(type: "boolean", nullable: false), + LicenceNumber = table.Column(type: "text", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PrpAuthorizedLicence", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_PrpAuthorizedLicence_LicenceNumber", + table: "PrpAuthorizedLicence", + column: "LicenceNumber", + unique: true); + } + } +} diff --git a/backend/webapi/Data/Migrations/20241122013506_AccountLinkingBusinessEvents.Designer.cs b/backend/webapi/Data/Migrations/20241122013506_AccountLinkingBusinessEvents.Designer.cs new file mode 100644 index 000000000..2a9abde3c --- /dev/null +++ b/backend/webapi/Data/Migrations/20241122013506_AccountLinkingBusinessEvents.Designer.cs @@ -0,0 +1,1616 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NodaTime; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Pidp.Data; + +#nullable disable + +namespace Pidp.Data.Migrations +{ + [DbContext(typeof(PidpDbContext))] + [Migration("20241122013506_AccountLinkingBusinessEvents")] + partial class AccountLinkingBusinessEvents + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Pidp.Models.AccessRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccessTypeCode") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.Property("RequestedOn") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("PartyId"); + + b.ToTable("AccessRequest"); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("Pidp.Models.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("City") + .IsRequired() + .HasColumnType("text"); + + b.Property("CountryCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(21) + .HasColumnType("character varying(21)"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("Postal") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProvinceCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Street") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("CountryCode"); + + b.HasIndex("ProvinceCode"); + + b.ToTable("Address"); + + b.HasDiscriminator("Discriminator").HasValue("Address"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Pidp.Models.Banner", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Component") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Header") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Status") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Banner"); + }); + + modelBuilder.Entity("Pidp.Models.BusinessEvent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Discriminator") + .IsRequired() + .HasMaxLength(34) + .HasColumnType("character varying(34)"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("RecordedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Severity") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator("Discriminator").HasValue("BusinessEvent"); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("Pidp.Models.ClientLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalInformation") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("LogLevel") + .HasColumnType("integer"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("ClientLog"); + }); + + modelBuilder.Entity("Pidp.Models.Credential", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("IdentityProvider") + .HasColumnType("text"); + + b.Property("IdpId") + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PartyId"); + + b.HasIndex("UserId") + .IsUnique() + .HasFilter("\"UserId\" != '00000000-0000-0000-0000-000000000000'"); + + b.ToTable("Credential", t => + { + t.HasCheckConstraint("CHK_Credential_AtLeastOneIdentifier", "((\"UserId\" != '00000000-0000-0000-0000-000000000000') or (\"IdpId\" is not null))"); + }); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkErrorLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CredentialLinkTicketId") + .HasColumnType("integer"); + + b.Property("ExistingCredentialId") + .HasColumnType("integer"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("CredentialLinkTicketId"); + + b.HasIndex("ExistingCredentialId"); + + b.ToTable("CredentialLinkErrorLog"); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkTicket", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Claimed") + .HasColumnType("boolean"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpiresAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LinkToIdentityProvider") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.Property("Token") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("PartyId"); + + b.ToTable("CredentialLinkTicket"); + }); + + modelBuilder.Entity("Pidp.Models.EmailLog", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Body") + .IsRequired() + .HasColumnType("text"); + + b.Property("Cc") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("DateSent") + .HasColumnType("timestamp with time zone"); + + b.Property("LatestStatus") + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("MsgId") + .HasColumnType("uuid"); + + b.Property("SendType") + .IsRequired() + .HasColumnType("text"); + + b.Property("SentTo") + .IsRequired() + .HasColumnType("text"); + + b.Property("StatusMessage") + .HasColumnType("text"); + + b.Property("Subject") + .IsRequired() + .HasColumnType("text"); + + b.Property("UpdateCount") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("EmailLog"); + }); + + modelBuilder.Entity("Pidp.Models.Endorsement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Active") + .HasColumnType("boolean"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedOn") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("Endorsement"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRelationship", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("EndorsementId") + .HasColumnType("integer"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("EndorsementId"); + + b.HasIndex("PartyId"); + + b.ToTable("EndorsementRelationship"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRequest", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AdditionalInformation") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PreApproved") + .HasColumnType("boolean"); + + b.Property("ReceivingPartyId") + .HasColumnType("integer"); + + b.Property("RecipientEmail") + .IsRequired() + .HasColumnType("text"); + + b.Property("RequestingPartyId") + .HasColumnType("integer"); + + b.Property("Status") + .HasColumnType("integer"); + + b.Property("StatusDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Token") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ReceivingPartyId"); + + b.HasIndex("RequestingPartyId"); + + b.ToTable("EndorsementRequest"); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.AccessType", b => + { + b.Property("Code") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("AccessTypeLookup"); + + b.HasData( + new + { + Code = 1, + Name = "Special Authority eForms" + }, + new + { + Code = 2, + Name = "HCIMWeb Account Transfer" + }, + new + { + Code = 3, + Name = "HCIMWeb Enrolment" + }, + new + { + Code = 4, + Name = "Driver Medical Fitness" + }, + new + { + Code = 5, + Name = "MS Teams for Clinical Use - Privacy Officer" + }, + new + { + Code = 6, + Name = "Prescription Refill eForm for Pharmacists" + }, + new + { + Code = 7, + Name = "Provider Reporting Portal" + }, + new + { + Code = 8, + Name = "MS Teams for Clinical Use - Clinic Member" + }, + new + { + Code = 9, + Name = "Access Harmonization User Access Agreement" + }, + new + { + Code = 10, + Name = "Immunization Entry eForm" + }); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.College", b => + { + b.Property("Code") + .HasColumnType("integer"); + + b.Property("Acronym") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("CollegeLookup"); + + b.HasData( + new + { + Code = 1, + Acronym = "CPSBC", + Name = "College of Physicians and Surgeons of BC" + }, + new + { + Code = 2, + Acronym = "CPBC", + Name = "College of Pharmacists of BC" + }, + new + { + Code = 3, + Acronym = "BCCNM", + Name = "BC College of Nurses and Midwives" + }, + new + { + Code = 4, + Acronym = "CNPBC", + Name = "College of Naturopathic Physicians of BC" + }, + new + { + Code = 5, + Acronym = "CDSBC", + Name = "College of Dental Surgeons of British Columbia" + }, + new + { + Code = 6, + Acronym = "COBC", + Name = "College of Optometrists of British Columbia" + }); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.Country", b => + { + b.Property("Code") + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("CountryLookup"); + + b.HasData( + new + { + Code = "CA", + Name = "Canada" + }, + new + { + Code = "US", + Name = "United States" + }); + }); + + modelBuilder.Entity("Pidp.Models.Lookups.Province", b => + { + b.Property("Code") + .HasColumnType("text"); + + b.Property("CountryCode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("ProvinceLookup"); + + b.HasData( + new + { + Code = "AB", + CountryCode = "CA", + Name = "Alberta" + }, + new + { + Code = "BC", + CountryCode = "CA", + Name = "British Columbia" + }, + new + { + Code = "MB", + CountryCode = "CA", + Name = "Manitoba" + }, + new + { + Code = "NB", + CountryCode = "CA", + Name = "New Brunswick" + }, + new + { + Code = "NL", + CountryCode = "CA", + Name = "Newfoundland and Labrador" + }, + new + { + Code = "NS", + CountryCode = "CA", + Name = "Nova Scotia" + }, + new + { + Code = "ON", + CountryCode = "CA", + Name = "Ontario" + }, + new + { + Code = "PE", + CountryCode = "CA", + Name = "Prince Edward Island" + }, + new + { + Code = "QC", + CountryCode = "CA", + Name = "Quebec" + }, + new + { + Code = "SK", + CountryCode = "CA", + Name = "Saskatchewan" + }, + new + { + Code = "NT", + CountryCode = "CA", + Name = "Northwest Territories" + }, + new + { + Code = "NU", + CountryCode = "CA", + Name = "Nunavut" + }, + new + { + Code = "YT", + CountryCode = "CA", + Name = "Yukon" + }, + new + { + Code = "AL", + CountryCode = "US", + Name = "Alabama" + }, + new + { + Code = "AK", + CountryCode = "US", + Name = "Alaska" + }, + new + { + Code = "AS", + CountryCode = "US", + Name = "American Samoa" + }, + new + { + Code = "AZ", + CountryCode = "US", + Name = "Arizona" + }, + new + { + Code = "AR", + CountryCode = "US", + Name = "Arkansas" + }, + new + { + Code = "CA", + CountryCode = "US", + Name = "California" + }, + new + { + Code = "CO", + CountryCode = "US", + Name = "Colorado" + }, + new + { + Code = "CT", + CountryCode = "US", + Name = "Connecticut" + }, + new + { + Code = "DE", + CountryCode = "US", + Name = "Delaware" + }, + new + { + Code = "DC", + CountryCode = "US", + Name = "District of Columbia" + }, + new + { + Code = "FL", + CountryCode = "US", + Name = "Florida" + }, + new + { + Code = "GA", + CountryCode = "US", + Name = "Georgia" + }, + new + { + Code = "GU", + CountryCode = "US", + Name = "Guam" + }, + new + { + Code = "HI", + CountryCode = "US", + Name = "Hawaii" + }, + new + { + Code = "ID", + CountryCode = "US", + Name = "Idaho" + }, + new + { + Code = "IL", + CountryCode = "US", + Name = "Illinois" + }, + new + { + Code = "IN", + CountryCode = "US", + Name = "Indiana" + }, + new + { + Code = "IA", + CountryCode = "US", + Name = "Iowa" + }, + new + { + Code = "KS", + CountryCode = "US", + Name = "Kansas" + }, + new + { + Code = "KY", + CountryCode = "US", + Name = "Kentucky" + }, + new + { + Code = "LA", + CountryCode = "US", + Name = "Louisiana" + }, + new + { + Code = "ME", + CountryCode = "US", + Name = "Maine" + }, + new + { + Code = "MD", + CountryCode = "US", + Name = "Maryland" + }, + new + { + Code = "MA", + CountryCode = "US", + Name = "Massachusetts" + }, + new + { + Code = "MI", + CountryCode = "US", + Name = "Michigan" + }, + new + { + Code = "MN", + CountryCode = "US", + Name = "Minnesota" + }, + new + { + Code = "MS", + CountryCode = "US", + Name = "Mississippi" + }, + new + { + Code = "MO", + CountryCode = "US", + Name = "Missouri" + }, + new + { + Code = "MT", + CountryCode = "US", + Name = "Montana" + }, + new + { + Code = "NE", + CountryCode = "US", + Name = "Nebraska" + }, + new + { + Code = "NV", + CountryCode = "US", + Name = "Nevada" + }, + new + { + Code = "NH", + CountryCode = "US", + Name = "New Hampshire" + }, + new + { + Code = "NJ", + CountryCode = "US", + Name = "New Jersey" + }, + new + { + Code = "NM", + CountryCode = "US", + Name = "New Mexico" + }, + new + { + Code = "NY", + CountryCode = "US", + Name = "New York" + }, + new + { + Code = "NC", + CountryCode = "US", + Name = "North Carolina" + }, + new + { + Code = "ND", + CountryCode = "US", + Name = "North Dakota" + }, + new + { + Code = "MP", + CountryCode = "US", + Name = "Northern Mariana Islands" + }, + new + { + Code = "OH", + CountryCode = "US", + Name = "Ohio" + }, + new + { + Code = "OK", + CountryCode = "US", + Name = "Oklahoma" + }, + new + { + Code = "OR", + CountryCode = "US", + Name = "Oregon" + }, + new + { + Code = "PA", + CountryCode = "US", + Name = "Pennsylvania" + }, + new + { + Code = "PR", + CountryCode = "US", + Name = "Puerto Rico" + }, + new + { + Code = "RI", + CountryCode = "US", + Name = "Rhode Island" + }, + new + { + Code = "SC", + CountryCode = "US", + Name = "South Carolina" + }, + new + { + Code = "SD", + CountryCode = "US", + Name = "South Dakota" + }, + new + { + Code = "TN", + CountryCode = "US", + Name = "Tennessee" + }, + new + { + Code = "TX", + CountryCode = "US", + Name = "Texas" + }, + new + { + Code = "UM", + CountryCode = "US", + Name = "United States Minor Outlying Islands" + }, + new + { + Code = "UT", + CountryCode = "US", + Name = "Utah" + }, + new + { + Code = "VT", + CountryCode = "US", + Name = "Vermont" + }, + new + { + Code = "VI", + CountryCode = "US", + Name = "Virgin Islands, U.S." + }, + new + { + Code = "VA", + CountryCode = "US", + Name = "Virginia" + }, + new + { + Code = "WA", + CountryCode = "US", + Name = "Washington" + }, + new + { + Code = "WV", + CountryCode = "US", + Name = "West Virginia" + }, + new + { + Code = "WI", + CountryCode = "US", + Name = "Wisconsin" + }, + new + { + Code = "WY", + CountryCode = "US", + Name = "Wyoming" + }); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinic", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("PrivacyOfficerId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("PrivacyOfficerId"); + + b.ToTable("MSTeamsClinic"); + }); + + modelBuilder.Entity("Pidp.Models.Party", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Birthdate") + .HasColumnType("date"); + + b.Property("Cpn") + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("Email") + .HasColumnType("text"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("OpId") + .HasColumnType("text"); + + b.Property("Phone") + .HasColumnType("text"); + + b.Property("PreferredFirstName") + .HasColumnType("text"); + + b.Property("PreferredLastName") + .HasColumnType("text"); + + b.Property("PreferredMiddleName") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("OpId") + .IsUnique(); + + b.ToTable("Party"); + }); + + modelBuilder.Entity("Pidp.Models.PartyLicenceDeclaration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CollegeCode") + .HasColumnType("integer"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("LicenceNumber") + .HasColumnType("text"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone"); + + b.Property("PartyId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollegeCode"); + + b.HasIndex("PartyId") + .IsUnique(); + + b.ToTable("PartyLicenceDeclaration"); + }); + + modelBuilder.Entity("Pidp.Models.HcimAccountTransfer", b => + { + b.HasBaseType("Pidp.Models.AccessRequest"); + + b.Property("LdapUsername") + .IsRequired() + .HasColumnType("text"); + + b.ToTable("HcimAccountTransfer"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicMemberEnrolment", b => + { + b.HasBaseType("Pidp.Models.AccessRequest"); + + b.Property("ClinicId") + .HasColumnType("integer"); + + b.HasIndex("ClinicId"); + + b.ToTable("MSTeamsClinicMemberEnrolment"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicAddress", b => + { + b.HasBaseType("Pidp.Models.Address"); + + b.Property("ClinicId") + .HasColumnType("integer"); + + b.HasIndex("ClinicId") + .IsUnique(); + + b.ToTable("Address"); + + b.HasDiscriminator().HasValue("MSTeamsClinicAddress"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingFailure", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("AccountLinkingFailure"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingFailure+LinkTicketNotFound", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("LinkTicketNotFound"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingSuccess", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("AccountLinkingSuccess"); + }); + + modelBuilder.Entity("Pidp.Models.BCProviderPasswordReset", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("BCProviderPasswordReset"); + }); + + modelBuilder.Entity("Pidp.Models.CollegeLicenceSearchError", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("CollegeLicenceSearchError"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleAssigned", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("LicenceStatusRoleAssigned"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleUnassigned", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("LicenceStatusRoleUnassigned"); + }); + + modelBuilder.Entity("Pidp.Models.PartyNotInPlr", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("PartyNotInPlr"); + }); + + modelBuilder.Entity("Pidp.Models.AccessRequest", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany("AccessRequests") + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.Address", b => + { + b.HasOne("Pidp.Models.Lookups.Country", "Country") + .WithMany() + .HasForeignKey("CountryCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.Lookups.Province", "Province") + .WithMany() + .HasForeignKey("ProvinceCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Country"); + + b.Navigation("Province"); + }); + + modelBuilder.Entity("Pidp.Models.Credential", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany("Credentials") + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkErrorLog", b => + { + b.HasOne("Pidp.Models.CredentialLinkTicket", "CredentialLinkTicket") + .WithMany() + .HasForeignKey("CredentialLinkTicketId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.Credential", "ExistingCredential") + .WithMany() + .HasForeignKey("ExistingCredentialId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CredentialLinkTicket"); + + b.Navigation("ExistingCredential"); + }); + + modelBuilder.Entity("Pidp.Models.CredentialLinkTicket", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRelationship", b => + { + b.HasOne("Pidp.Models.Endorsement", "Endorsement") + .WithMany("EndorsementRelationships") + .HasForeignKey("EndorsementId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Endorsement"); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.EndorsementRequest", b => + { + b.HasOne("Pidp.Models.Party", "ReceivingParty") + .WithMany() + .HasForeignKey("ReceivingPartyId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("Pidp.Models.Party", "RequestingParty") + .WithMany() + .HasForeignKey("RequestingPartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReceivingParty"); + + b.Navigation("RequestingParty"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinic", b => + { + b.HasOne("Pidp.Models.Party", "PrivacyOfficer") + .WithMany() + .HasForeignKey("PrivacyOfficerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PrivacyOfficer"); + }); + + modelBuilder.Entity("Pidp.Models.PartyLicenceDeclaration", b => + { + b.HasOne("Pidp.Models.Lookups.College", "College") + .WithMany() + .HasForeignKey("CollegeCode"); + + b.HasOne("Pidp.Models.Party", "Party") + .WithOne("LicenceDeclaration") + .HasForeignKey("Pidp.Models.PartyLicenceDeclaration", "PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("College"); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.HcimAccountTransfer", b => + { + b.HasOne("Pidp.Models.AccessRequest", null) + .WithOne() + .HasForeignKey("Pidp.Models.HcimAccountTransfer", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicMemberEnrolment", b => + { + b.HasOne("Pidp.Models.MSTeamsClinic", "Clinic") + .WithMany() + .HasForeignKey("ClinicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Pidp.Models.AccessRequest", null) + .WithOne() + .HasForeignKey("Pidp.Models.MSTeamsClinicMemberEnrolment", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clinic"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinicAddress", b => + { + b.HasOne("Pidp.Models.MSTeamsClinic", "Clinic") + .WithOne("Address") + .HasForeignKey("Pidp.Models.MSTeamsClinicAddress", "ClinicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Clinic"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingFailure", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingSuccess", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.BCProviderPasswordReset", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.CollegeLicenceSearchError", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleAssigned", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.LicenceStatusRoleUnassigned", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.PartyNotInPlr", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.Endorsement", b => + { + b.Navigation("EndorsementRelationships"); + }); + + modelBuilder.Entity("Pidp.Models.MSTeamsClinic", b => + { + b.Navigation("Address") + .IsRequired(); + }); + + modelBuilder.Entity("Pidp.Models.Party", b => + { + b.Navigation("AccessRequests"); + + b.Navigation("Credentials"); + + b.Navigation("LicenceDeclaration"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/webapi/Data/Migrations/20241122013506_AccountLinkingBusinessEvents.cs b/backend/webapi/Data/Migrations/20241122013506_AccountLinkingBusinessEvents.cs new file mode 100644 index 000000000..3cd837e4f --- /dev/null +++ b/backend/webapi/Data/Migrations/20241122013506_AccountLinkingBusinessEvents.cs @@ -0,0 +1,22 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Pidp.Data.Migrations +{ + /// + public partial class AccountLinkingBusinessEvents : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + + } + } +} diff --git a/backend/webapi/Data/Migrations/PidpDbContextModelSnapshot.cs b/backend/webapi/Data/Migrations/PidpDbContextModelSnapshot.cs index 758702feb..741e17db0 100644 --- a/backend/webapi/Data/Migrations/PidpDbContextModelSnapshot.cs +++ b/backend/webapi/Data/Migrations/PidpDbContextModelSnapshot.cs @@ -1179,29 +1179,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("PartyLicenceDeclaration"); }); - modelBuilder.Entity("Pidp.Models.PrpAuthorizedLicence", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("Claimed") - .HasColumnType("boolean"); - - b.Property("LicenceNumber") - .IsRequired() - .HasColumnType("text"); - - b.HasKey("Id"); - - b.HasIndex("LicenceNumber") - .IsUnique(); - - b.ToTable("PrpAuthorizedLicence"); - }); - modelBuilder.Entity("Pidp.Models.HcimAccountTransfer", b => { b.HasBaseType("Pidp.Models.AccessRequest"); @@ -1240,6 +1217,47 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue("MSTeamsClinicAddress"); }); + modelBuilder.Entity("Pidp.Models.AccountLinkingFailure", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("AccountLinkingFailure"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingFailure+LinkTicketNotFound", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("LinkTicketNotFound"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingSuccess", b => + { + b.HasBaseType("Pidp.Models.BusinessEvent"); + + b.Property("PartyId") + .ValueGeneratedOnUpdateSometimes() + .HasColumnType("integer") + .HasColumnName("PartyId"); + + b.HasIndex("PartyId"); + + b.ToTable("BusinessEvent"); + + b.HasDiscriminator().HasValue("AccountLinkingSuccess"); + }); + modelBuilder.Entity("Pidp.Models.BCProviderPasswordReset", b => { b.HasBaseType("Pidp.Models.BusinessEvent"); @@ -1493,6 +1511,28 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Clinic"); }); + modelBuilder.Entity("Pidp.Models.AccountLinkingFailure", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("Pidp.Models.AccountLinkingSuccess", b => + { + b.HasOne("Pidp.Models.Party", "Party") + .WithMany() + .HasForeignKey("PartyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + modelBuilder.Entity("Pidp.Models.BCProviderPasswordReset", b => { b.HasOne("Pidp.Models.Party", "Party") diff --git a/backend/webapi/Data/PidpDbContext.cs b/backend/webapi/Data/PidpDbContext.cs index 882dabe2f..afc0204df 100644 --- a/backend/webapi/Data/PidpDbContext.cs +++ b/backend/webapi/Data/PidpDbContext.cs @@ -30,7 +30,6 @@ public class PidpDbContext( public DbSet MSTeamsClinicMemberEnrolments { get; set; } = default!; public DbSet PartyLicenceDeclarations { get; set; } = default!; public DbSet Parties { get; set; } = default!; - public DbSet PrpAuthorizedLicences { get; set; } = default!; /// /// Do not use. Use SaveChangesAsync Instead. diff --git a/backend/webapi/Features/AccessRequests/AccessRequestsController.cs b/backend/webapi/Features/AccessRequests/AccessRequestsController.cs index 1981879b2..ef9e4bdd2 100644 --- a/backend/webapi/Features/AccessRequests/AccessRequestsController.cs +++ b/backend/webapi/Features/AccessRequests/AccessRequestsController.cs @@ -110,7 +110,7 @@ public async Task CreatePrescriptionRefillEformsEnrolment([FromSe .ToActionResult(); [HttpPost("provider-reporting-portal")] - [Authorize(Policy = Policies.BCProviderAuthentication)] + [Authorize(Policy = Policies.HighAssuranceIdentityProvider)] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task CreateProviderReportingPortalEnrolment([FromServices] ICommandHandler handler, diff --git a/backend/webapi/Features/AccessRequests/ProviderReportingPortal.cs b/backend/webapi/Features/AccessRequests/ProviderReportingPortal.cs index 0b3a63836..f8ccae8ff 100644 --- a/backend/webapi/Features/AccessRequests/ProviderReportingPortal.cs +++ b/backend/webapi/Features/AccessRequests/ProviderReportingPortal.cs @@ -14,7 +14,7 @@ namespace Pidp.Features.AccessRequests; public class ProviderReportingPortal { - public static IdentifierType[] AllowedIdentifierTypes => [IdentifierType.PhysiciansAndSurgeons]; + public static IdentifierType[] AllowedIdentifierTypes => [IdentifierType.PhysiciansAndSurgeons, IdentifierType.Pharmacist]; public class Command : ICommand { @@ -51,26 +51,16 @@ public async Task HandleAsync(Command command) }) .SingleAsync(); - var filteredPlrDigest = (await this.plrClient.GetStandingsDigestAsync(dto.Cpn)) - .With(AllowedIdentifierTypes); if (dto.AlreadyEnroled - || !filteredPlrDigest - .HasGoodStanding) + || !(await this.plrClient.GetStandingsDigestAsync(dto.Cpn)) + .With(AllowedIdentifierTypes) + .HasGoodStanding) { this.logger.LogAccessRequestDenied(); return DomainResult.Failed(); } - var prpAuthorization = await this.context.PrpAuthorizedLicences - .SingleOrDefaultAsync(authorizedLicence => filteredPlrDigest.LicenceNumbers.Contains(authorizedLicence.LicenceNumber)); - - if (prpAuthorization == null) - { - this.logger.LogUnauthorizedLicence(command.PartyId, filteredPlrDigest.LicenceNumbers); - return DomainResult.Failed(); - } - if (!await this.keycloakClient.AssignAccessRoles(dto.UserId, MohKeycloakEnrolment.ProviderReportingPortal)) { return DomainResult.Failed(); @@ -83,8 +73,6 @@ public async Task HandleAsync(Command command) RequestedOn = this.clock.GetCurrentInstant() }); - prpAuthorization.Claimed = true; - await this.context.SaveChangesAsync(); return DomainResult.Success(); diff --git a/backend/webapi/Features/Credentials/CredentialsController.cs b/backend/webapi/Features/Credentials/CredentialsController.cs index 1f517c0db..8ec5e3044 100644 --- a/backend/webapi/Features/Credentials/CredentialsController.cs +++ b/backend/webapi/Features/Credentials/CredentialsController.cs @@ -117,11 +117,12 @@ await this.AuthorizationService.SignTokenAsync(new Cookies.CredentialLinkTicket. return result.ToActionResult(); } - [HttpDelete("/api/[controller]")] + [HttpDelete("/api/[controller]/link-ticket/cookie")] + [AllowAnonymous] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public ActionResult DeleteCredential() + public ActionResult DeleteCredentialLinkCookie() { this.Response.Cookies.Append( Cookies.CredentialLinkTicket.Key, diff --git a/backend/webapi/Features/Discovery/Discovery.cs b/backend/webapi/Features/Discovery/Discovery.cs index 87632ec2c..0757fa6a3 100644 --- a/backend/webapi/Features/Discovery/Discovery.cs +++ b/backend/webapi/Features/Discovery/Discovery.cs @@ -72,7 +72,12 @@ public async Task HandleAsync(Query query) if (query.CredentialLinkToken != null) { - return await this.HandleAcountLinkingDiscovery(query, data?.Credential); + var model = await this.HandleAcountLinkingDiscovery(query, data?.Credential); + if (model.Status != Model.StatusCode.AccountLinkInProgress) + { + await this.context.SaveChangesAsync(); + } + return model; } if (data == null) @@ -103,52 +108,58 @@ private async Task HandleAcountLinkingDiscovery(Query query, Credential? if (ticket == null) { this.logger.LogTicketNotFound(query.User.GetUserId(), query.CredentialLinkToken!.Value); + this.context.BusinessEvents.Add(AccountLinkingFailure.CreateTicketNotFound(query.User.GetUserId(), query.CredentialLinkToken.Value, this.clock.GetCurrentInstant())); return new Model { Status = Model.StatusCode.AccountLinkingError }; } + + if (credential != null) + { + // Either the Credential is already linked to the Party, or the Credential already exists on a different Party. + if (credential.PartyId == ticket.PartyId) + { + this.logger.LogCredentialAlreadyLinked(query.User.GetUserId(), ticket.Id, credential.Id); + this.context.BusinessEvents.Add(AccountLinkingFailure.CreateCredentialAlreadyLinked(ticket.PartyId, credential.Id, ticket.Id, this.clock.GetCurrentInstant())); + return new Model + { + PartyId = credential.PartyId, + Status = Model.StatusCode.AlreadyLinked + }; + } + else + { + this.context.CredentialLinkErrorLogs.Add(new CredentialLinkErrorLog + { + CredentialLinkTicketId = ticket.Id, + ExistingCredentialId = credential.Id + }); + + this.logger.LogCredentialAlreadyExists(query.User.GetUserId(), ticket.Id, credential.Id); + this.context.BusinessEvents.Add(AccountLinkingFailure.CreateCredentialExists(ticket.PartyId, credential.Id, ticket.Id, this.clock.GetCurrentInstant())); + return new Model + { + PartyId = credential.PartyId, + Status = Model.StatusCode.CredentialExists + }; + } + } + if (ticket.LinkToIdentityProvider != query.User.GetIdentityProvider()) { this.logger.LogTicketIdpError(query.User.GetUserId(), ticket.Id, ticket.LinkToIdentityProvider, query.User.GetIdentityProvider()); + this.context.BusinessEvents.Add(AccountLinkingFailure.CreateWrongIdentityProvider(ticket.PartyId, ticket.Id, query.User.GetIdentityProvider(), this.clock.GetCurrentInstant())); return new Model { Status = Model.StatusCode.AccountLinkingError }; } if (ticket.ExpiresAt < this.clock.GetCurrentInstant()) { this.logger.LogTicketExpired(query.User.GetUserId(), ticket.Id); + this.context.BusinessEvents.Add(AccountLinkingFailure.CreateTicketExpired(ticket.PartyId, ticket.Id, this.clock.GetCurrentInstant())); return new Model { Status = Model.StatusCode.TicketExpired }; } - if (credential == null) - { - return new Model - { - Status = Model.StatusCode.AccountLinkInProgress - }; - } - - if (credential.PartyId == ticket.PartyId) - { - this.logger.LogCredentialAlreadyLinked(query.User.GetUserId(), ticket.Id, credential.Id); - return new Model - { - PartyId = credential.PartyId, - Status = Model.StatusCode.AlreadyLinked - }; - } - else + return new Model { - this.context.CredentialLinkErrorLogs.Add(new CredentialLinkErrorLog - { - CredentialLinkTicketId = ticket.Id, - ExistingCredentialId = credential.Id - }); - await this.context.SaveChangesAsync(); - - this.logger.LogCredentialAlreadyExists(query.User.GetUserId(), ticket.Id, credential.Id); - return new Model - { - PartyId = credential.PartyId, - Status = Model.StatusCode.CredentialExists - }; - } + Status = Model.StatusCode.AccountLinkInProgress + }; } private async Task HandleUpdatesAsync(Credential credential, bool checkPlr, ClaimsPrincipal user) diff --git a/backend/webapi/Features/Parties/ProfileStatus.Model.cs b/backend/webapi/Features/Parties/ProfileStatus.Model.cs index d17532b65..461779cf8 100644 --- a/backend/webapi/Features/Parties/ProfileStatus.Model.cs +++ b/backend/webapi/Features/Parties/ProfileStatus.Model.cs @@ -310,7 +310,7 @@ protected override StatusCode Compute(ProfileData profile) { return profile switch { - { UserIsBCProvider: false } or { HasPrpAuthorizedLicence: false } => StatusCode.Locked, + { HasBCProviderCredential: false } => StatusCode.Locked, _ when profile.HasEnrolment(AccessTypeCode.ProviderReportingPortal) => StatusCode.Complete, _ when profile.PartyPlrStanding .With(ProviderReportingPortal.AllowedIdentifierTypes) diff --git a/backend/webapi/Features/Parties/ProfileStatus.cs b/backend/webapi/Features/Parties/ProfileStatus.cs index f2499a4ce..fa9bcea30 100644 --- a/backend/webapi/Features/Parties/ProfileStatus.cs +++ b/backend/webapi/Features/Parties/ProfileStatus.cs @@ -106,7 +106,6 @@ public class ProfileData public PlrStandingsDigest EndorsementPlrStanding { get; set; } = default!; public bool HasMSTeamsClinicEndorsement { get; set; } public bool HasPendingEndorsementRequest { get; set; } - public bool HasPrpAuthorizedLicence { get; set; } public PlrStandingsDigest PartyPlrStanding { get; set; } = default!; public bool HasEnrolment(AccessTypeCode accessTypeCode) => this.CompletedEnrolments.Contains(accessTypeCode); @@ -122,15 +121,6 @@ public async Task Finalize( this.userIdentityProvider = user.GetIdentityProvider(); this.PartyPlrStanding = await plrClient.GetStandingsDigestAsync(this.Cpn); - var possiblePrpLicenceNumbers = this.PartyPlrStanding - .With(ProviderReportingPortal.AllowedIdentifierTypes) - .LicenceNumbers; - if (this.UserIsBCProvider && possiblePrpLicenceNumbers.Any()) - { - this.HasPrpAuthorizedLicence = await context.PrpAuthorizedLicences - .AnyAsync(authorizedLicence => possiblePrpLicenceNumbers.Contains(authorizedLicence.LicenceNumber)); - } - var endorsementDtos = await context.ActiveEndorsementRelationships(this.Id) .Select(relationship => new { diff --git a/backend/webapi/Infrastructure/HttpClients/Plr/PlrClientDefinitions.cs b/backend/webapi/Infrastructure/HttpClients/Plr/PlrClientDefinitions.cs index b6711ea96..9f7d8acf2 100644 --- a/backend/webapi/Infrastructure/HttpClients/Plr/PlrClientDefinitions.cs +++ b/backend/webapi/Infrastructure/HttpClients/Plr/PlrClientDefinitions.cs @@ -117,8 +117,6 @@ public class PlrStandingsDigest && record.PlrStatusCode == PlrStatusCode.Pending && record.PlrStatusReasonCode == PlrStatusReasonCode.NonPracticing); - public IEnumerable LicenceNumbers => this.records.Where(record => record.LicenceNumber != null).Select(record => record.LicenceNumber!); - public IEnumerable Cpns => this.records.Select(record => record.Cpn); private PlrStandingsDigest(bool error, IEnumerable? records = null) diff --git a/backend/webapi/Models/BusinessEvent.cs b/backend/webapi/Models/BusinessEvent.cs index 4a16cdd78..0b3db6022 100644 --- a/backend/webapi/Models/BusinessEvent.cs +++ b/backend/webapi/Models/BusinessEvent.cs @@ -83,6 +83,47 @@ public static BCProviderPasswordReset Create(int partyId, string userPrincipalNa } } +public class AccountLinkingSuccess : PartyBusinessEvent +{ + public static AccountLinkingSuccess Create(int partyId, Instant recordedOn) + { + return new AccountLinkingSuccess + { + PartyId = partyId, + Description = $"Party successfully linked their account.", + Severity = LogLevel.Information, + RecordedOn = recordedOn + }; + } +} + +public class AccountLinkingFailure : PartyBusinessEvent +{ + public class LinkTicketNotFound : BusinessEvent { } + public static LinkTicketNotFound CreateTicketNotFound(Guid userId, Guid credentialLinkToken, Instant recordedOn) => new() + { + Description = $"No unclaimed Credential Link Ticket found. User Id: {userId}, Credential Link Token: {credentialLinkToken}", + Severity = LogLevel.Error, + RecordedOn = recordedOn + }; + + public static AccountLinkingFailure CreateCredentialAlreadyLinked(int partyId, int credentialId, int ticketId, Instant recordedOn) => CreateInternal(partyId, $"Credential {credentialId} is already linked. Ticket ID {ticketId}", recordedOn); + public static AccountLinkingFailure CreateCredentialExists(int partyId, int credentialId, int ticketId, Instant recordedOn) => CreateInternal(partyId, $"Credential {credentialId} already exists on another Party. Ticket ID {ticketId}", recordedOn); + public static AccountLinkingFailure CreateTicketExpired(int partyId, int ticketId, Instant recordedOn) => CreateInternal(partyId, $"Ticket {ticketId} expired", recordedOn); + public static AccountLinkingFailure CreateWrongIdentityProvider(int partyId, int ticketId, string? actualIdp, Instant recordedOn) => CreateInternal(partyId, $"New Credential's Identity Provider {actualIdp} does not match Link Ticket {ticketId} expected IDP", recordedOn); + + private static AccountLinkingFailure CreateInternal(int partyId, string failureReason, Instant recordedOn) + { + return new AccountLinkingFailure + { + PartyId = partyId, + Description = $"Party failed to link their account. Reason: {failureReason}.", + Severity = LogLevel.Error, + RecordedOn = recordedOn + }; + } +} + public class CollegeLicenceSearchError : PartyBusinessEvent { public static CollegeLicenceSearchError Create(int partyId, CollegeCode? collegeCode, string? licenceNumber, Instant recordedOn) diff --git a/backend/webapi/Models/PrpAuthorizedLicence.cs b/backend/webapi/Models/PrpAuthorizedLicence.cs deleted file mode 100644 index 6ce72d696..000000000 --- a/backend/webapi/Models/PrpAuthorizedLicence.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Pidp.Models; - -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; - -/// -/// College Licence Numbers from the College of Physicians and Surgeons that have been pre-authorized to use the Provider Reporting Portal enrolment. -/// -[Table(nameof(PrpAuthorizedLicence))] -public class PrpAuthorizedLicence -{ - [Key] - public int Id { get; set; } - public string LicenceNumber { get; set; } = string.Empty; - public bool Claimed { get; set; } -} diff --git a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.ts b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.ts index 13fb605f5..7191447ca 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.ts +++ b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.ts @@ -313,6 +313,7 @@ export class BcProviderEditPage height: '24rem', cancelHide: true, actionHide: true, + progressBar: true, }; this.dialog.open(this.mfaDialogTemplate, { data }); } @@ -335,6 +336,7 @@ export class BcProviderEditPage actionText: 'Continue', actionTypePosition: 'center', cancelHide: true, + progressBar: true, }; this.dialog .open(this.mfaDialogTemplate, { data, disableClose: true }) diff --git a/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.html b/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.html index 055a4ce06..48526d968 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.html +++ b/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.html @@ -15,6 +15,7 @@

Enrol for Access

+
Instructions
Enrol for Access
doctor
diff --git a/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.scss b/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.scss index 992c73889..b70ce388f 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.scss +++ b/workspace/apps/pidp/src/app/features/access/pages/provincial-attachment-system/provincial-attachment-system.page.scss @@ -23,6 +23,11 @@ --header-margin: var(--gap) 0 0; --content-padding: var(--gap) 0; --form-card-width: 25rem; + .card-body { + img.logo { + padding: 1.5rem 0 !important; + } + } } .viewport-all { @@ -41,10 +46,10 @@ .main { display: grid; - grid-template-columns: calc(70% - 15px) calc(30% - 15px); + grid-template-columns: calc(60% - 15px) calc(40% - 15px); gap: 20px; min-height: 340px; - margin: calc(var(--gap) * 2) 0; + margin: calc(var(--gap)) 0; & .card { display: flex; @@ -52,12 +57,21 @@ padding-right: calc(var(--gap) * 0.9); position: relative; line-height: 1.5rem; + margin-left: -1.5rem; + + .stepper-title { + color: #313132; + font-size: 1.5rem; + font-weight: 700; + margin-bottom: calc(var(--gap) / 2); + padding-left: 1.8rem; + } } .pas-button { height: 15rem; background: linear-gradient( 270deg, - rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, 0) 40%, rgba(158, 204, 211, 1) 100% ); img { @@ -65,12 +79,8 @@ z-index: -2; } - img.img-doctor { - object-position: -10px -100px; - } - div.auth-card { - padding: 23px 0px 7px 34px; + padding: 2rem; } .card-container { @@ -90,7 +100,18 @@ } .card-header { - color: #1a5a96; + color: white; + display: flex; + padding: 0.65rem 1rem; + border-radius: 0.25rem; + flex-direction: column; + align-items: flex-start; + gap: 0.5rem; + background: rgba(0, 0, 0, 0.7); + + h3 { + margin: 0; + } } .card-body { @@ -101,14 +122,21 @@ position: relative !important; height: 45px; width: 175px; - padding: 10px; + padding: 1rem 0; } } .card-footer { button { z-index: 1; - padding: 10px 25px; + padding: 0.35rem 2rem; + &:disabled { + border-radius: var(--layout-borderRadius-medium, 0.25rem); + background: var( + --surface-color-primary-button-disabled, + #edebe9 + ); + } } } } @@ -127,7 +155,6 @@ } .viewport-xsmall { - .content-header { margin: 0px 20px 0px 20px; } @@ -141,32 +168,24 @@ display: flex !important; flex-direction: column !important; + & .card { + margin-left: 0 !important; + } + .pas-step-label { line-height: 1.1; } .pas-button { - img.img-doctor { - height: 15rem !important; - object-position: -12px -72px !important; - } - div.auth-card { - padding: 20px 0px 0px 0px !important; + padding: 20px 0px 0px 20px !important; } .card-container { height: 50% !important; - .auth-card-header { - padding-left: 20px; - } - - .auth-card-body { - padding-left: 15px; - } .auth-card-footer { - padding: 15px 0px 0px 30px; + padding: 7.5px 0px 7.5px 0px; } } } diff --git a/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm-resource.service.ts b/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm-resource.service.ts index d5f0ca1a2..5652e0d42 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm-resource.service.ts +++ b/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm-resource.service.ts @@ -1,27 +1,19 @@ import { HttpErrorResponse } from '@angular/common/http'; -import { Inject, Injectable } from '@angular/core'; +import { Injectable } from '@angular/core'; -import { Observable, catchError, map, tap, throwError } from 'rxjs'; +import { Observable, catchError, tap, throwError } from 'rxjs'; -import { APP_CONFIG, AppConfig } from '@app/app.config'; import { ApiHttpClient } from '@app/core/resources/api-http-client.service'; import { ToastService } from '@app/core/services/toast.service'; -import { AuthService } from '../../services/auth.service'; - @Injectable({ providedIn: 'root', }) export class LinkAccountConfirmResource { - public logoutRedirectUrl: string; public constructor( - @Inject(APP_CONFIG) private config: AppConfig, private apiResource: ApiHttpClient, - private authService: AuthService, private toastService: ToastService, - ) { - this.logoutRedirectUrl = `${this.config.applicationUrl}/`; - } + ) {} public linkAccount(): Observable { return this.apiResource.post('credentials', {}).pipe( @@ -39,9 +31,8 @@ export class LinkAccountConfirmResource { ); } - public cancelLink(): Observable | boolean> { - return this.apiResource.delete('credentials').pipe( - map(() => this.authService.logout(this.logoutRedirectUrl)), + public cancelLink(): Observable { + return this.apiResource.delete('credentials/link-ticket/cookie').pipe( catchError((error: HttpErrorResponse) => { this.toastService.openErrorToast( 'Something went wrong. Please try again.', diff --git a/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.ts b/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.ts index 506643d62..195c0fd58 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.ts +++ b/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.ts @@ -1,10 +1,10 @@ import { CommonModule, NgOptimizedImage } from '@angular/common'; -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { Router } from '@angular/router'; -import { Observable, exhaustMap, switchMap, tap } from 'rxjs'; +import { Observable, concatMap, exhaustMap, switchMap, tap } from 'rxjs'; import { LOADING_OVERLAY_DEFAULT_MESSAGE, @@ -18,6 +18,8 @@ import { InjectViewportCssClassDirective, } from '@bcgov/shared/ui'; +import { APP_CONFIG, AppConfig } from '@app/app.config'; +import { AccessRoutes } from '@app/features/access/access.routes'; import { User } from '@app/features/auth/models/user.model'; import { ProfileRoutes } from '@app/features/profile/profile.routes'; import { BreadcrumbComponent } from '@app/shared/components/breadcrumb/breadcrumb.component'; @@ -25,9 +27,9 @@ import { SuccessDialogComponent } from '@app/shared/components/success-dialog/su import { IdentityProvider } from '../../enums/identity-provider.enum'; import { BcProviderUser } from '../../models/bc-provider-user.model'; +import { AuthService } from '../../services/auth.service'; import { AuthorizedUserService } from '../../services/authorized-user.service'; import { LinkAccountConfirmResource } from './link-account-confirm-resource.service'; -import { AccessRoutes } from '@app/features/access/access.routes'; @Component({ selector: 'app-link-account-confirm', @@ -46,23 +48,31 @@ import { AccessRoutes } from '@app/features/access/access.routes'; export class LinkAccountConfirmPage implements OnInit { public user$: Observable; public breadcrumbsData: Array<{ title: string; path: string }> = [ - {title: 'Home', path: ''}, + { title: 'Home', path: '' }, { title: 'Access', path: AccessRoutes.routePath(AccessRoutes.ACCESS_REQUESTS), }, - {title: 'Link Account', path: ''}, + { title: 'Link Account', path: '' }, ]; public showInstructions: boolean = false; + public logoutRedirectUrl: string; public constructor( + @Inject(APP_CONFIG) private config: AppConfig, private dialog: MatDialog, private authorizedUserService: AuthorizedUserService, private linkAccountConfirmResource: LinkAccountConfirmResource, private router: Router, private loadingOverlayService: LoadingOverlayService, + private authService: AuthService, ) { this.user$ = this.authorizedUserService.user$; + this.logoutRedirectUrl = `${this.config.applicationUrl}/`; + } + + public toggleInstructions(): void { + this.showInstructions = !this.showInstructions; } public ngOnInit(): void { @@ -97,9 +107,7 @@ export class LinkAccountConfirmPage implements OnInit { .afterClosed() .pipe( exhaustMap((result) => - result - ? this.link() - : this.linkAccountConfirmResource.cancelLink(), + result ? this.link() : this.cancelLink(), ), ); }), @@ -119,8 +127,10 @@ export class LinkAccountConfirmPage implements OnInit { ); } - public toggleInstructions(): void { - this.showInstructions = !this.showInstructions; + private cancelLink(): Observable { + return this.linkAccountConfirmResource + .cancelLink() + .pipe(concatMap(() => this.authService.logout(this.logoutRedirectUrl))); } private getPendingAccountDescription(user: User): string { diff --git a/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.spec.ts b/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.spec.ts index 129048123..6db912f33 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.spec.ts +++ b/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.spec.ts @@ -25,6 +25,7 @@ import { LoggerService } from '@app/core/services/logger.service'; import { IdentityProvider } from '../../enums/identity-provider.enum'; import { AuthService } from '../../services/auth.service'; +import { LinkAccountConfirmResource } from '../link-account-confirm/link-account-confirm-resource.service'; import { LoginResource } from './login-resource.service'; import { LoginPage, LoginPageRouteData } from './login.page'; @@ -32,6 +33,7 @@ describe('LoginPage', () => { let component: LoginPage; let clientLogsServiceSpy: Spy; + let linkAccountConfirmResourceSpy: Spy; let authServiceSpy: Spy; let matDialogSpy: Spy; let loginResourceSpy: Spy; @@ -72,6 +74,7 @@ describe('LoginPage', () => { provideAutoSpy(ClientLogsService), provideAutoSpy(DocumentService), provideAutoSpy(MatDialog), + provideAutoSpy(LinkAccountConfirmResource), provideAutoSpy(LoginResource), provideAutoSpy(LoggerService), ViewportService, @@ -81,6 +84,9 @@ describe('LoginPage', () => { component = TestBed.inject(LoginPage); clientLogsServiceSpy = TestBed.inject(ClientLogsService); + linkAccountConfirmResourceSpy = TestBed.inject( + LinkAccountConfirmResource, + ); authServiceSpy = TestBed.inject(AuthService); matDialogSpy = TestBed.inject(MatDialog); loginResourceSpy = TestBed.inject(LoginResource); @@ -138,6 +144,7 @@ describe('LoginPage', () => { }); const idpHint = IdentityProvider.IDIR; clientLogsServiceSpy.createClientLog.mockReturnValue(of(void 0)); + linkAccountConfirmResourceSpy.cancelLink.mockReturnValue(of(void 0)); component.ngOnInit(); when('the method is called', () => { @@ -167,6 +174,7 @@ describe('LoginPage', () => { }); const idpHint = IdentityProvider.BCSC; clientLogsServiceSpy.createClientLog.mockReturnValue(of(void 0)); + linkAccountConfirmResourceSpy.cancelLink.mockReturnValue(of(void 0)); matDialogSpy.open.mockReturnValue({ afterClosed: () => of(true), } as MatDialogRef); @@ -202,6 +210,7 @@ describe('LoginPage', () => { mockActivatedRoute.snapshot.routeConfig = { path: 'admin' }; const idpHint = IdentityProvider.BCSC; clientLogsServiceSpy.createClientLog.mockReturnValue(of(void 0)); + linkAccountConfirmResourceSpy.cancelLink.mockReturnValue(of(void 0)); matDialogSpy.open.mockReturnValue({ afterClosed: () => of(true), } as MatDialogRef); diff --git a/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.ts b/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.ts index 1d2a19cfb..014d32b5b 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.ts +++ b/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.ts @@ -39,6 +39,7 @@ import { NeedHelpComponent } from '@app/shared/components/need-help/need-help.co import { IdentityProvider } from '../../enums/identity-provider.enum'; import { AuthService } from '../../services/auth.service'; +import { LinkAccountConfirmResource } from '../link-account-confirm/link-account-confirm-resource.service'; import { BannerFindResponse } from './banner-find.response.model'; import { LoginResource } from './login-resource.service'; import { component } from './login.constants'; @@ -93,6 +94,7 @@ export class LoginPage implements OnInit, AfterViewInit { private dialog: MatDialog, private documentService: DocumentService, private viewportService: ViewportService, + private linkAccountConfirmResource: LinkAccountConfirmResource, private snowplowService: SnowplowService, private loginResource: LoginResource, private logger: LoggerService, @@ -196,7 +198,8 @@ export class LoginPage implements OnInit, AfterViewInit { } private login(idpHint: IdentityProvider): Observable { - return this.createClientLogIfNeeded(idpHint).pipe( + return this.linkAccountConfirmResource.cancelLink().pipe( + switchMap(() => this.createClientLogIfNeeded(idpHint)), switchMap(() => this.authService.login({ idpHint: idpHint, diff --git a/workspace/apps/pidp/src/app/features/portal/state/portal-state.builder.ts b/workspace/apps/pidp/src/app/features/portal/state/portal-state.builder.ts index b867b5353..422c24cb3 100644 --- a/workspace/apps/pidp/src/app/features/portal/state/portal-state.builder.ts +++ b/workspace/apps/pidp/src/app/features/portal/state/portal-state.builder.ts @@ -124,9 +124,7 @@ export class AccessStateBuilder { ], ), ...ArrayUtils.insertResultIf( - // TODO remove permissions when ready for production - this.insertSection('providerReportingPortal', profileStatus) && - this.permissionsService.hasRole([Role.FEATURE_PIDP_DEMO]), + this.insertSection('providerReportingPortal', profileStatus), () => [new ProviderReportingPortalSection(profileStatus, this.router)], ), ...ArrayUtils.insertResultIf( diff --git a/workspace/apps/pidp/src/assets/images/checkup.png b/workspace/apps/pidp/src/assets/images/checkup.png new file mode 100644 index 000000000..a876e8625 Binary files /dev/null and b/workspace/apps/pidp/src/assets/images/checkup.png differ diff --git a/workspace/apps/pidp/src/assets/images/doctor1.jpg b/workspace/apps/pidp/src/assets/images/doctor1.jpg deleted file mode 100644 index 628425b2b..000000000 Binary files a/workspace/apps/pidp/src/assets/images/doctor1.jpg and /dev/null differ diff --git a/workspace/libs/shared/ui/src/lib/components/dialogs/confirm-dialog/confirm-dialog.component.html b/workspace/libs/shared/ui/src/lib/components/dialogs/confirm-dialog/confirm-dialog.component.html index 2a019a471..2e527c71d 100644 --- a/workspace/libs/shared/ui/src/lib/components/dialogs/confirm-dialog/confirm-dialog.component.html +++ b/workspace/libs/shared/ui/src/lib/components/dialogs/confirm-dialog/confirm-dialog.component.html @@ -36,16 +36,18 @@ }">

{{ options.message }}

- - +
+ + +