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 675b91e79..c896f0099 100644 --- a/backend/webapi/Features/Parties/ProfileStatus.Model.cs +++ b/backend/webapi/Features/Parties/ProfileStatus.Model.cs @@ -294,7 +294,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/charts/pidp/templates/pidp-route.yaml b/charts/pidp/templates/pidp-route.yaml deleted file mode 100644 index 1ff2f9206..000000000 --- a/charts/pidp/templates/pidp-route.yaml +++ /dev/null @@ -1,24 +0,0 @@ -{{- if .Values.routes.enabled -}} -{{- $fullName := include "pidp.fullname" . -}} -{{ $release := .Release.Name }} -{{ $isPR := hasPrefix "pr-" .Release.Name }} - -kind: Route -apiVersion: route.openshift.io/v1 -metadata: - name: {{ $fullName }}-route - labels: - {{- include "pidp.labels" . | nindent 4 }} -spec: - to: - kind: Service - name: {{ $release }}-ingress - tls: - termination: edge - insecureEdgeTerminationPolicy: Redirect - destinationCACertificate: '' - port: - targetPort: http - wildcardPolicy: None - -{{- end }} diff --git a/deploy/pr_values.yaml b/deploy/pr_values.yaml index bcee89247..a3cdd02ec 100644 --- a/deploy/pr_values.yaml +++ b/deploy/pr_values.yaml @@ -5,7 +5,7 @@ global: image: registry: image-registry.openshift-image-registry.svc:5000/d8a8f9-tools tag: dev - license_plate: "d8a8f9" + license_plate: "f088b1" database: autoCreate: true @@ -40,10 +40,4 @@ plr-intake: rabbitmq: autoCreate: true - host: rabbitmq://pidp:password@rabbitmq:5672/ - -ingress: - enabled: false - -routes: - enabled: true \ No newline at end of file + host: rabbitmq://pidp:password@rabbitmq:5672/ \ No newline at end of file diff --git a/workspace/apps/pidp/src/app/core/party/discovery-resource.service.ts b/workspace/apps/pidp/src/app/core/party/discovery-resource.service.ts index 4da447652..5b0da838e 100644 --- a/workspace/apps/pidp/src/app/core/party/discovery-resource.service.ts +++ b/workspace/apps/pidp/src/app/core/party/discovery-resource.service.ts @@ -25,7 +25,7 @@ export enum DiscoveryStatus { AlreadyLinkedError, CredentialExistsError, ExpiredCredentialLinkTicketError, - AccountLinkingError + AccountLinkingError, } @Injectable({ @@ -38,7 +38,7 @@ export class DiscoveryResource { * @description * Get the party's ID based on the access token user ID, * creates a party if one does not already exist, - * or discovers that the User is a new BC Provider (and so cannot create a Party). + * or discovers that the User is a new BCProvider (and so cannot create a Party). */ public discover(): Observable { return this.apiResource.post('discovery', null); diff --git a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application-resource.service.ts b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application-resource.service.ts index bcf39b1d8..f05dc847d 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application-resource.service.ts +++ b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application-resource.service.ts @@ -34,7 +34,7 @@ export class BcProviderApplicationResource { .pipe(map((upn) => upn)); } - // Currently automatically links to BC Provider + // Currently automatically links to BCProvider public createLinkTicket(partyId: number): NoContent { return this.apiResource .post(`${this.getResourcePath(partyId)}/link-ticket`, { diff --git a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.html b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.html index cf2b2fb68..96c90d0cd 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.html +++ b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.html @@ -2,21 +2,20 @@
-

BC Provider account information

+

BCProvider account information

- Welcome {{ (fullName$ | async) }} to your BC Provider knowledge - center! + Welcome {{ (fullName$ | async) }} to your BCProvider knowledge center!

The OneHealthID Service is designed to use the digital identity created - by the BC Services Card as a foundation for your BC Provider account. + by the BC Services Card as a foundation for your BCProvider account.

- Whether you are existing, or new to BC Provider, we have you covered. + Whether you are existing, or new to BCProvider, we have you covered.

OneHealthID is looking for a one-time setup if you are an existing BC @@ -25,19 +24,19 @@

- Do you not have a BC Provider account? setup is quick and easy. + Do you not have a BCProvider account? setup is quick and easy.

- Interested in BC Provider? + Interested in BCProvider?

For brand new users that are looking for the flexibility and - security of BC Services card and a BC Provider account. + security of BC Services card and a BCProvider account.

@@ -99,13 +98,13 @@

- Advantage with BC Provider + Advantage with BCProvider

After this quick uplift you will have the flexibility to then - login to OneHealthID with your BC Provider, or your BC Services - Card account info. All you have to do is log into BC Provider + login to OneHealthID with your BCProvider, or your BC Services + Card account info. All you have to do is log into BCProvider with your existing information, and we will automatically take care of the secure uplift.

@@ -132,7 +131,7 @@

-

You get more out of OneHealthID when you sign in with BC Provider.

+

You get more out of OneHealthID when you sign in with BCProvider.

  1. Go to Microsoft account and select @@ -169,7 +168,7 @@

    You get more out of OneHealthID when you sign in with BC Provider.

    -

    You get more out of OneHealthID when you sign in with BC Provider.

    +

    You get more out of OneHealthID when you sign in with BCProvider.

    Your password must be 8 to 256 characters long, with at least one letter and one number or special character. Strong passwords include both upper- @@ -242,7 +241,7 @@

    Create an account

    Let's get started
    - using BC Provider today! + using BCProvider today!
@@ -261,7 +260,7 @@

Create an account

Let's get started

- using BC Provider today! + using BCProvider today!
@@ -283,7 +282,7 @@

Create an account

diff --git a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.ts b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.ts index 299327afa..68e8655b1 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.ts +++ b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-application/bc-provider-application.page.ts @@ -132,7 +132,7 @@ export class BcProviderApplicationPage title: 'Access', path: AccessRoutes.routePath(AccessRoutes.ACCESS_REQUESTS), }, - { title: 'BC Provider account information', path: '' }, + { title: 'BCProvider account information', path: '' }, ]; public fullName$!: Observable; diff --git a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.html b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.html index 4eb455c1c..ef2141067 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.html +++ b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.html @@ -2,7 +2,7 @@
-

BC Provider Account Management

+

BCProvider Account Management

Set a new password or reset your MFA at your convenience

@@ -95,7 +95,7 @@

Set new password

(click)="toggleTooltip('mfa')">

- Reset your multifactor authentication (MFA) + Reset your multi-factor authentication (MFA)

Only available if you login with BCSC

diff --git a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.scss b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.scss index 96501d789..9a44344cf 100644 --- a/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.scss +++ b/workspace/apps/pidp/src/app/features/access/pages/bc-provider-edit/bc-provider-edit.page.scss @@ -57,6 +57,9 @@ --header-margin: unset; --avatar-size: 4rem; --content-padding: var(--gap); + ul li{ + list-style-type: decimal; + } } .viewport-medium { 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..b4769b386 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 @@ -124,7 +124,7 @@ export class BcProviderEditPage title: 'Access', path: AccessRoutes.routePath(AccessRoutes.ACCESS_REQUESTS), }, - { title: 'BC Provider Account', path: '' }, + { title: 'BCProvider Account', path: '' }, ]; // ui-page is handling this. @@ -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/guards/high-assurance-credential.guard.spec.ts b/workspace/apps/pidp/src/app/features/auth/guards/high-assurance-credential.guard.spec.ts index 18b0b8d9e..fe7f434d4 100644 --- a/workspace/apps/pidp/src/app/features/auth/guards/high-assurance-credential.guard.spec.ts +++ b/workspace/apps/pidp/src/app/features/auth/guards/high-assurance-credential.guard.spec.ts @@ -66,7 +66,7 @@ describe('highAssuranceCredentialGuard', () => { }); }); - given('the user is authenticated with a BC Provider', (done) => { + given('the user is authenticated with a BCProvider', (done) => { authorizedUserServiceSpy.accessorSpies.getters.identityProvider$.mockReturnValue( of(IdentityProvider.BC_PROVIDER), ); diff --git a/workspace/apps/pidp/src/app/features/auth/pages/auto-login/auto-login.page.ts b/workspace/apps/pidp/src/app/features/auth/pages/auto-login/auto-login.page.ts index 10a051cc7..873581144 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/auto-login/auto-login.page.ts +++ b/workspace/apps/pidp/src/app/features/auth/pages/auto-login/auto-login.page.ts @@ -18,7 +18,7 @@ export class AutoLoginPage implements OnInit { private authService: AuthService, private route: ActivatedRoute, private router: Router, - ) {} + ) { } public ngOnInit(): void { const idpHint = this.route.snapshot.queryParamMap.get('idp_hint') ?? ''; @@ -28,6 +28,7 @@ export class AutoLoginPage implements OnInit { .login({ idpHint: idpHint, redirectUri: this.config.applicationUrl, + prompt: 'login' }) .subscribe(); } else { diff --git a/workspace/apps/pidp/src/app/features/auth/pages/bc-provider-uplift/bc-provider-uplift.page.html b/workspace/apps/pidp/src/app/features/auth/pages/bc-provider-uplift/bc-provider-uplift.page.html index 1d8fe883d..fe07c8284 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/bc-provider-uplift/bc-provider-uplift.page.html +++ b/workspace/apps/pidp/src/app/features/auth/pages/bc-provider-uplift/bc-provider-uplift.page.html @@ -13,7 +13,7 @@
BC Provider uplift @@ -22,10 +22,10 @@

Keeping you safe

- Your BC Provider account is currently missing a key component which lets + Your BCProvider account is currently missing a key component which lets us know it is you.
You will need to perform a one-time setup with your BC Services Card.
- Once complete, please continue using your BC Provider account. + Once complete, please continue using your BCProvider account.

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.html b/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.html index 9c09b92ef..7f6e1dff6 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.html +++ b/workspace/apps/pidp/src/app/features/auth/pages/link-account-confirm/link-account-confirm.page.html @@ -82,7 +82,7 @@

BC Services Card

alt="contact" />
-

BC Provider

+

BCProvider

Access a growing number of provincial health applications

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..0abfd5059 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 { @@ -132,7 +142,7 @@ export class LinkAccountConfirmPage implements OnInit { case IdentityProvider.BC_PROVIDER: { const idpId = (user as BcProviderUser).idpId; const accountName = idpId.endsWith('@bcp') ? idpId.slice(0, -4) : idpId; - return `the BC Provider account ${accountName}`; + return `the BCProvider account ${accountName}`; } default: return 'a new account'; diff --git a/workspace/apps/pidp/src/app/features/auth/pages/link-account-error/link-account-error.page.html b/workspace/apps/pidp/src/app/features/auth/pages/link-account-error/link-account-error.page.html index dcb593be4..be0b45ec4 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/link-account-error/link-account-error.page.html +++ b/workspace/apps/pidp/src/app/features/auth/pages/link-account-error/link-account-error.page.html @@ -13,7 +13,7 @@
BC Provider uplift diff --git a/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.html b/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.html index 8eb42d633..1db316b74 100644 --- a/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.html +++ b/workspace/apps/pidp/src/app/features/auth/pages/login/login.page.html @@ -97,7 +97,7 @@

class="login-button-secondary" mat-stroked-button (click)="onLogin(IdentityProvider.BC_PROVIDER)"> - BC Provider + BCProvider

+
+ + + How do I reset my MFA on BCProvider? + +
    +
  • Click Access
  • +
  • Click BCProvider Account
  • +
  • On the right-hand side click “Reset my MFA” link
  • +
  • Click continue, system will unpair your phone
  • +
  • After completely the unpairing, you will be prompted to login
  • +
  • Select the BCProvider acccount
  • +
  • Enter your current password
  • +
  • + After successfully logging into your account, you will be prompted + to setup MFA on a phone or tablet. +
  • +
+
+
Frequently asked questions

BC E-Substance Reporting
- BC Provider
+ BCProvider
Connect Extranet Website
Driver Fitness Practitioner Portal
Driver Medical Fitness Testing
diff --git a/workspace/apps/pidp/src/app/features/faq/pages/mfa-setup/mfa-setup.page.html b/workspace/apps/pidp/src/app/features/faq/pages/mfa-setup/mfa-setup.page.html index 2d7dabd19..68dac0b6e 100644 --- a/workspace/apps/pidp/src/app/features/faq/pages/mfa-setup/mfa-setup.page.html +++ b/workspace/apps/pidp/src/app/features/faq/pages/mfa-setup/mfa-setup.page.html @@ -25,7 +25,7 @@

BCProvider Active Directory Multi-factor Authentication (MFA) Setup

.

- The BCprovider uses Multi-Factor Authentication (MFA) is an additional + The BCProvider uses Multi-Factor Authentication (MFA) is an additional layer of security that helps protect your online accounts and sensitive information. It enhances the traditional username and password login process by requiring at least two or more forms of verification. This diff --git a/workspace/apps/pidp/src/app/features/organization-info/pages/endorsements/endorsements.page.ts b/workspace/apps/pidp/src/app/features/organization-info/pages/endorsements/endorsements.page.ts index 53a7b453f..576610d3f 100644 --- a/workspace/apps/pidp/src/app/features/organization-info/pages/endorsements/endorsements.page.ts +++ b/workspace/apps/pidp/src/app/features/organization-info/pages/endorsements/endorsements.page.ts @@ -216,6 +216,13 @@ export class EndorsementsPage ? this.resource .approveEndorsementRequest(this.partyService.partyId, requestId) .pipe( + switchMap( + () => + (this.nonActionableEndorsementRequests$ = + this.getNonActionableEndorsementRequests( + this.partyService.partyId, + )), + ), switchMap( () => (this.actionableEndorsementRequests$ = diff --git a/workspace/apps/pidp/src/app/features/portal/state/access/bc-provider-portal-section.class.ts b/workspace/apps/pidp/src/app/features/portal/state/access/bc-provider-portal-section.class.ts index 39431673b..af87ee7f9 100644 --- a/workspace/apps/pidp/src/app/features/portal/state/access/bc-provider-portal-section.class.ts +++ b/workspace/apps/pidp/src/app/features/portal/state/access/bc-provider-portal-section.class.ts @@ -30,7 +30,7 @@ export class BcProviderPortalSection implements IPortalSection { private router: Router, ) { this.key = 'bcProvider'; - this.heading = 'BC Provider Account'; + this.heading = 'BCProvider Account'; this.description = `A reusable credential for access to health data in BC.`; this.keyWords = profileStatus.status.bcProvider.keyWords || []; } 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/app/features/profile/pages/account-linking/account-linking.constants.ts b/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.constants.ts index 1cd43b407..44b276467 100644 --- a/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.constants.ts +++ b/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.constants.ts @@ -4,5 +4,5 @@ export const linkedAccountCardText = { [IdentityProvider.BCSC]: 'BC Services Card', [IdentityProvider.PHSA]: 'Health Authority ID', [IdentityProvider.IDIR]: 'IDIR Account', - [IdentityProvider.BC_PROVIDER]: 'BC Provider Account', + [IdentityProvider.BC_PROVIDER]: 'BCProvider Account', }; diff --git a/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.page.html b/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.page.html index db59c4669..a07a0c55f 100644 --- a/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.page.html +++ b/workspace/apps/pidp/src/app/features/profile/pages/account-linking/account-linking.page.html @@ -109,7 +109,7 @@

BC Services Card

alt="contact" />
-

BC Provider

+

BCProvider

Access a growing number of provincial health applications

(this.getResourcePath(id), payload) .pipe( - tap(() => - this.toastService.openSuccessToast( - 'College licence information has been updated', - ), - ), + tap((res) => { + if (res !== null) { + this.toastService.openSuccessToast( + 'College licence information has been updated', + ); + } + }), catchError((error: HttpErrorResponse) => { this.toastService.openErrorToast( 'College licence information could not be updated', diff --git a/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.html b/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.html index 5fc5c0aac..50318507f 100644 --- a/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.html +++ b/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.html @@ -56,6 +56,12 @@ (click)="navigateTo(ProfileRoutes.routePath(ProfileRoutes.USER_ACCESS_AGREEMENT))" >User Access Agreement + Password and MFA reset
@@ -115,6 +121,12 @@ (click)="navigateTo(ProfileRoutes.routePath(ProfileRoutes.USER_ACCESS_AGREEMENT))" >User Access Agreement + Password and MFA reset { + return this.apiResource + .get(this.getResourcePath(partyId)) + .pipe( + catchError((error: HttpErrorResponse) => { + return throwError(() => error); + }), + ); + } + + protected getResourcePath(partyId: number): string { + return `parties/${partyId}/credentials`; + } +} diff --git a/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.scss b/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.scss index 6571377b9..72e095eeb 100644 --- a/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.scss +++ b/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.scss @@ -61,6 +61,7 @@ h1 { flex-direction: column; // Expand to fit horizontally flex: var(--content-flex); + height: 100%; } & .content-header-box { diff --git a/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.ts b/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.ts index 70ba8fdb3..0e1412b55 100644 --- a/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.ts +++ b/workspace/apps/pidp/src/app/features/shell/components/navbar-menu/nav-menu.ts @@ -4,6 +4,8 @@ import { EventEmitter, Input, OnChanges, + OnDestroy, + OnInit, Output, SimpleChanges, ViewChild, @@ -24,6 +26,8 @@ import { RouterOutlet, } from '@angular/router'; +import { Observable, Subject, takeUntil } from 'rxjs'; + import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { faBell } from '@fortawesome/free-regular-svg-icons'; @@ -37,9 +41,15 @@ import { } from '@bcgov/shared/ui'; import { RoutePath } from '@bcgov/shared/utils'; +import { PartyService } from '@app/core/party/party.service'; +import { AccessRoutes } from '@app/features/access/access.routes'; +import { IdentityProvider } from '@app/features/auth/enums/identity-provider.enum'; import { AlertCode } from '@app/features/portal/enums/alert-code.enum'; import { ProfileRoutes } from '@app/features/profile/profile.routes'; +import { Credential } from './nav-menu.model'; +import { NavMenuResource } from './nav-menu.resource.service'; + @Component({ selector: 'app-nav-menu', templateUrl: './nav-menu.html', @@ -62,7 +72,7 @@ import { ProfileRoutes } from '@app/features/profile/profile.routes'; NgClass, ], }) -export class NavMenuComponent implements OnChanges { +export class NavMenuComponent implements OnChanges, OnInit, OnDestroy { @Input() public alerts: AlertCode[] | null = []; @Input() public menuItems!: DashboardMenuItem[]; @Input() public emailSupport!: string; @@ -79,21 +89,41 @@ export class NavMenuComponent implements OnChanges { public isLogoutMenuItemVisible = false; public isTopMenuVisible = false; public ProfileRoutes = ProfileRoutes; + public AccessRoutes = AccessRoutes; public showCollegeAlert = false; public faBell = faBell; public AlertCode = AlertCode; + public credentials: Credential[] = []; + public credentials$: Observable; + private unsubscribe$ = new Subject(); + public IdentityProvider = IdentityProvider; public constructor( private viewportService: ViewportService, private router: Router, + private resource: NavMenuResource, + private partyService: PartyService, ) { this.viewportService.viewportBroadcast$.subscribe((viewport) => this.onViewportChange(viewport), ); + const partyId = this.partyService.partyId; + this.credentials$ = this.resource.getCredentials(partyId); + } + + public ngOnInit(): void { + this.handleLinkedAccounts(); } + public ngOnChanges(_: SimpleChanges): void { this.refresh(); } + + public ngOnDestroy(): void { + this.unsubscribe$.next(); + this.unsubscribe$.complete(); + } + public onMiniMenuButtonClick(): void { // Toggle display of the sidenav. this.isSidenavOpened = !this.isSidenavOpened; @@ -137,6 +167,11 @@ export class NavMenuComponent implements OnChanges { } return undefined; } + + public hasCredential(idp: IdentityProvider): boolean { + return this.credentials.some((c) => c.identityProvider === idp); + } + public onLogout(): void { this.logout.emit(); } @@ -146,6 +181,14 @@ export class NavMenuComponent implements OnChanges { } } + private handleLinkedAccounts(): void { + this.credentials$ + .pipe(takeUntil(this.unsubscribe$)) + .subscribe((credentials) => { + this.credentials = credentials; + }); + } + private onViewportChange(viewport: PidpViewport): void { this.viewport = viewport; this.refresh(); diff --git a/workspace/apps/pidp/src/app/shared/components/success-dialog/components/dialog-bcprovider-create.component.ts b/workspace/apps/pidp/src/app/shared/components/success-dialog/components/dialog-bcprovider-create.component.ts index d24617886..600ddb217 100644 --- a/workspace/apps/pidp/src/app/shared/components/success-dialog/components/dialog-bcprovider-create.component.ts +++ b/workspace/apps/pidp/src/app/shared/components/success-dialog/components/dialog-bcprovider-create.component.ts @@ -3,7 +3,7 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'app-dialog-bcprovider-create', template: `

- BC Provider account {{ username }} has been created.
+ BCProvider account {{ username }} has been created.
You will now have the option to sign in to our system with these credentials.
Please note, this is not an email address.
You will not be able to diff --git a/workspace/apps/pidp/src/app/shared/pipes/is-high-assurance.pipe.spec.ts b/workspace/apps/pidp/src/app/shared/pipes/is-high-assurance.pipe.spec.ts index 4a1338f8e..4f72914f5 100644 --- a/workspace/apps/pidp/src/app/shared/pipes/is-high-assurance.pipe.spec.ts +++ b/workspace/apps/pidp/src/app/shared/pipes/is-high-assurance.pipe.spec.ts @@ -14,7 +14,7 @@ describe('IsHighAssurancePipe', () => { expect(pipe.transform(IdentityProvider.BCSC)).toEqual(true); }); - it('returns true when BC Provider', () => { + it('returns true when BCProvider', () => { expect(pipe.transform(IdentityProvider.BC_PROVIDER)).toEqual(true); }); 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 f56849bfa..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 }}

- - +
+ + +
{ + const adjustSubmitFocus = document.querySelector( + '#submit', + ) as HTMLButtonElement; + if (adjustSubmitFocus) adjustSubmitFocus.focus(); + }); } private getOptions(dialogOptions: DialogOptions): DialogOptions { diff --git a/workspace/libs/shared/ui/src/lib/components/dialogs/dialog-options.model.ts b/workspace/libs/shared/ui/src/lib/components/dialogs/dialog-options.model.ts index f792d026b..3952afeaf 100644 --- a/workspace/libs/shared/ui/src/lib/components/dialogs/dialog-options.model.ts +++ b/workspace/libs/shared/ui/src/lib/components/dialogs/dialog-options.model.ts @@ -30,4 +30,5 @@ export interface DialogOptions { /** overload the dialog height, if undefined the default value will be used */ height?: string; class?: string; + progressBar?: boolean; }