Skip to content

Commit

Permalink
Feature/Create the KRR database schema (#203)
Browse files Browse the repository at this point in the history
* Correct name of container and solution folder

* Fix comment typos

* Use pattern matching for type check

* Refactoring GetUserListByUuid to better fit it with the other methods

* Correct typo in comment

* Refactoring to arrow function for simplification

* Cleaning up namespace for Core's ServiceCollectionExtensions

* Add suffix "Service" to IUnitContactPoints

* Correct namespace ..User.ContactPoints -> Unit.ContactPoints for IUnitContactPointsService

* Simplify list initialization

* Generate database models

* Move the database context class to its own folder

* Update the ContextClassName attribute

* Create a new Migration folder and attach the database creation script

* Regenerate the data models

* Delete the DROP DATABASE IF EXISTS statement

* Delete an index that could be used to search for person data by a supplier identifier

* Add statements to grant two users, we have, access to the schema

* Remove the database creation statement

* Regenerate the Person data model

---------

Co-authored-by: Hallgeir Garnes-Gutvik <[email protected]>
  • Loading branch information
Ahmed-Ghanam and hggutvik authored Oct 14, 2024
1 parent 6e04d24 commit b9182bb
Show file tree
Hide file tree
Showing 7 changed files with 360 additions and 1 deletion.
42 changes: 42 additions & 0 deletions src/Altinn.Profile.Integrations/Migration/profiledb.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
-- Create schema if it doesn't exist
CREATE SCHEMA IF NOT EXISTS contact_and_reservation;

-- Grant access to the schema
GRANT ALL ON SCHEMA contact_and_reservation TO platform_profile_admin;
GRANT USAGE ON SCHEMA contact_and_reservation TO platform_profile;

-- Create table MailboxSupplier
CREATE TABLE IF NOT EXISTS contact_and_reservation.mailbox_supplier (
mailbox_supplier_id INT GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) PRIMARY KEY,
org_number_ak CHAR(9) NOT NULL,
CONSTRAINT unique_org_number_ak UNIQUE (org_number_ak)
);

-- Create table Metadata
CREATE TABLE IF NOT EXISTS contact_and_reservation.metadata (
latest_change_number BIGINT PRIMARY KEY,
exported TIMESTAMPTZ
);

-- Create table Person
CREATE TABLE IF NOT EXISTS contact_and_reservation.person (
contact_and_reservation_user_id INT GENERATED ALWAYS AS IDENTITY (START WITH 1 INCREMENT BY 1) PRIMARY KEY,
fnumber_ak CHAR(11) NOT NULL UNIQUE,
reservation BOOLEAN,
description VARCHAR(20),
mobile_phone_number VARCHAR(20),
mobile_phone_number_last_updated TIMESTAMPTZ,
mobile_phone_number_last_verified TIMESTAMPTZ,
email_address VARCHAR(400),
email_address_last_updated TIMESTAMPTZ,
email_address_last_verified TIMESTAMPTZ,
mailbox_address VARCHAR(50),
mailbox_supplier_id_fk INT,
x509_certificate TEXT,
language_code CHAR(2) NULL,
CONSTRAINT fk_mailbox_supplier FOREIGN KEY (mailbox_supplier_id_fk) REFERENCES contact_and_reservation.mailbox_supplier (mailbox_supplier_id),
CONSTRAINT chk_language_code CHECK (language_code ~* '^[a-z]{2}$')
);

-- Indexes for performance
CREATE INDEX idx_fnumber_ak ON contact_and_reservation.person (fnumber_ak);
3 changes: 2 additions & 1 deletion src/Altinn.Profile/Altinn.Profile.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
<PackageReference Include="Azure.Security.KeyVault.Secrets" Version="4.6.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
<PackageReference Include="JWTCookieAuthentication" Version="4.0.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.8.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.7.3" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
</ItemGroup>
Expand Down
77 changes: 77 additions & 0 deletions src/Altinn.Profile/Models/DbContext/ProfiledbContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable

using Microsoft.EntityFrameworkCore;

namespace Altinn.Profile.Models;

/// <summary>
/// Represents the database context for the profile database.
/// </summary>
public partial class ProfileDbContext : DbContext
{
/// <summary>
/// Initializes a new instance of the <see cref="ProfileDbContext"/> class.
/// </summary>
/// <param name="options">The options to be used by a <see cref="DbContext"/>.</param>
public ProfileDbContext(DbContextOptions<ProfileDbContext> options)
: base(options)
{
}

/// <summary>
/// Gets or sets the <see cref="DbSet{MailboxSupplier}"/> representing the mailbox suppliers.
/// </summary>
public virtual DbSet<MailboxSupplier> MailboxSuppliers { get; set; }

/// <summary>
/// Gets or sets the <see cref="DbSet{Metadata}"/> representing the metadata.
/// </summary>
public virtual DbSet<Metadata> Metadata { get; set; }

/// <summary>
/// Gets or sets the <see cref="DbSet{Person}"/> representing the people.
/// </summary>
public virtual DbSet<Person> People { get; set; }

/// <summary>
/// Configures the schema needed for the context.
/// </summary>
/// <param name="modelBuilder">The builder being used to construct the model for this context.</param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MailboxSupplier>(entity =>
{
entity.HasKey(e => e.MailboxSupplierId).HasName("mailbox_supplier_pkey");
entity.Property(e => e.MailboxSupplierId).UseIdentityAlwaysColumn();
entity.Property(e => e.OrgNumberAk).IsFixedLength();
});

modelBuilder.Entity<Metadata>(entity =>
{
entity.HasKey(e => e.LatestChangeNumber).HasName("metadata_pkey");
entity.Property(e => e.LatestChangeNumber).ValueGeneratedNever();
});

modelBuilder.Entity<Person>(entity =>
{
entity.HasKey(e => e.ContactAndReservationUserId).HasName("person_pkey");
entity.Property(e => e.ContactAndReservationUserId).UseIdentityAlwaysColumn();
entity.Property(e => e.FnumberAk).IsFixedLength();
entity.Property(e => e.LanguageCode).IsFixedLength();
entity.HasOne(d => d.MailboxSupplierIdFkNavigation).WithMany(p => p.People).HasConstraintName("fk_mailbox_supplier");
});

OnModelCreatingPartial(modelBuilder);
}

/// <summary>
/// A partial method that can be used to configure the model further.
/// </summary>
/// <param name="modelBuilder">The builder being used to construct the model for this context.</param>
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
40 changes: 40 additions & 0 deletions src/Altinn.Profile/Models/MailboxSupplier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

using Microsoft.EntityFrameworkCore;

namespace Altinn.Profile.Models;

/// <summary>
/// Represents a mailbox supplier in the contact and reservation schema.
/// </summary>
[Table("mailbox_supplier", Schema = "contact_and_reservation")]
[Index("OrgNumberAk", Name = "unique_org_number_ak", IsUnique = true)]
public partial class MailboxSupplier
{
/// <summary>
/// Gets or sets the unique identifier for the mailbox supplier.
/// </summary>
[Key]
[Column("mailbox_supplier_id")]
public int MailboxSupplierId { get; set; }

/// <summary>
/// Gets or sets the organization number of the mailbox supplier.
/// </summary>
[Required]
[Column("org_number_ak")]
[StringLength(9)]
public string OrgNumberAk { get; set; }

/// <summary>
/// Gets or sets the collection of people associated with the mailbox supplier.
/// </summary>
[InverseProperty("MailboxSupplierIdFkNavigation")]
public virtual ICollection<Person> People { get; set; } = new List<Person>();
}
28 changes: 28 additions & 0 deletions src/Altinn.Profile/Models/Metadata.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Altinn.Profile.Models;

/// <summary>
/// Represents metadata in the contact and reservation schema.
/// </summary>
[Table("metadata", Schema = "contact_and_reservation")]
public partial class Metadata
{
/// <summary>
/// Gets or sets the latest change number.
/// </summary>
[Key]
[Column("latest_change_number")]
public long LatestChangeNumber { get; set; }

/// <summary>
/// Gets or sets the date and time when the metadata was exported.
/// </summary>
[Column("exported")]
public DateTime? Exported { get; set; }
}
117 changes: 117 additions & 0 deletions src/Altinn.Profile/Models/Person.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// <auto-generated> This file has been auto generated by EF Core Power Tools. </auto-generated>
#nullable disable

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

using Microsoft.EntityFrameworkCore;

namespace Altinn.Profile.Models;
/// <summary>
/// Represents a person in the contact and reservation schema.
/// </summary>
[Table("person", Schema = "contact_and_reservation")]
[Index("FnumberAk", Name = "idx_fnumber_ak")]
[Index("FnumberAk", Name = "person_fnumber_ak_key", IsUnique = true)]
public partial class Person
{
/// <summary>
/// Gets or sets the unique identifier for the contact and reservation user.
/// </summary>
[Key]
[Column("contact_and_reservation_user_id")]
public int ContactAndReservationUserId { get; set; }

/// <summary>
/// Gets or sets the F-number (a unique identifier) of the person.
/// </summary>
[Required]
[Column("fnumber_ak")]
[StringLength(11)]
public string FnumberAk { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the person has a reservation.
/// </summary>
[Column("reservation")]
public bool? Reservation { get; set; }

/// <summary>
/// Gets or sets the description of the person.
/// </summary>
[Column("description")]
[StringLength(20)]
public string Description { get; set; }

/// <summary>
/// Gets or sets the mobile phone number of the person.
/// </summary>
[Column("mobile_phone_number")]
[StringLength(20)]
public string MobilePhoneNumber { get; set; }

/// <summary>
/// Gets or sets the date and time when the mobile phone number was last updated.
/// </summary>
[Column("mobile_phone_number_last_updated")]
public DateTime? MobilePhoneNumberLastUpdated { get; set; }

/// <summary>
/// Gets or sets the date and time when the mobile phone number was last verified.
/// </summary>
[Column("mobile_phone_number_last_verified")]
public DateTime? MobilePhoneNumberLastVerified { get; set; }

/// <summary>
/// Gets or sets the email address of the person.
/// </summary>
[Column("email_address")]
[StringLength(400)]
public string EmailAddress { get; set; }

/// <summary>
/// Gets or sets the date and time when the email address was last updated.
/// </summary>
[Column("email_address_last_updated")]
public DateTime? EmailAddressLastUpdated { get; set; }

/// <summary>
/// Gets or sets the date and time when the email address was last verified.
/// </summary>
[Column("email_address_last_verified")]
public DateTime? EmailAddressLastVerified { get; set; }

/// <summary>
/// Gets or sets the mailbox address of the person.
/// </summary>
[Column("mailbox_address")]
[StringLength(50)]
public string MailboxAddress { get; set; }

/// <summary>
/// Gets or sets the foreign key to the mailbox supplier.
/// </summary>
[Column("mailbox_supplier_id_fk")]
public int? MailboxSupplierIdFk { get; set; }

/// <summary>
/// Gets or sets the X.509 certificate of the person.
/// </summary>
[Column("x509_certificate")]
public string X509Certificate { get; set; }

/// <summary>
/// Gets or sets the language code of the person.
/// </summary>
[Column("language_code")]
[StringLength(2)]
public string LanguageCode { get; set; }

/// <summary>
/// Gets or sets the navigation property to the mailbox supplier.
/// </summary>
[ForeignKey("MailboxSupplierIdFk")]
[InverseProperty("People")]
public virtual MailboxSupplier MailboxSupplierIdFkNavigation { get; set; }
}
54 changes: 54 additions & 0 deletions src/Altinn.Profile/efpt.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"CodeGenerationMode": 4,
"ContextClassName": "ProfileDbContext",
"ContextNamespace": null,
"FilterSchemas": false,
"IncludeConnectionString": false,
"ModelNamespace": null,
"OutputContextPath": null,
"OutputPath": "Models",
"PreserveCasingWithRegex": true,
"ProjectRootNamespace": "Altinn.Profile",
"Schemas": null,
"SelectedHandlebarsLanguage": 2,
"SelectedToBeGenerated": 0,
"T4TemplatePath": null,
"Tables": [
{
"Name": "contact_and_reservation.mailbox_supplier",
"ObjectType": 0
},
{
"Name": "contact_and_reservation.metadata",
"ObjectType": 0
},
{
"Name": "contact_and_reservation.person",
"ObjectType": 0
}
],
"UiHint": null,
"UncountableWords": null,
"UseAsyncStoredProcedureCalls": true,
"UseBoolPropertiesWithoutDefaultSql": false,
"UseDatabaseNames": false,
"UseDateOnlyTimeOnly": true,
"UseDbContextSplitting": false,
"UseDecimalDataAnnotationForSprocResult": true,
"UseFluentApiOnly": false,
"UseHandleBars": false,
"UseHierarchyId": false,
"UseInflector": true,
"UseLegacyPluralizer": false,
"UseManyToManyEntity": false,
"UseNoDefaultConstructor": false,
"UseNoNavigations": false,
"UseNoObjectFilter": false,
"UseNodaTime": false,
"UseNullableReferences": false,
"UsePrefixNavigationNaming": false,
"UseSchemaFolders": false,
"UseSchemaNamespaces": false,
"UseSpatial": false,
"UseT4": false
}

0 comments on commit b9182bb

Please sign in to comment.