diff --git a/Core/Configurations/PostgresqlConfigurationBuilder/Class2.cs b/Core/Configurations/PostgresqlConfigurationBuilder/Class2.cs
index f1cb84f..1c8e1cb 100644
--- a/Core/Configurations/PostgresqlConfigurationBuilder/Class2.cs
+++ b/Core/Configurations/PostgresqlConfigurationBuilder/Class2.cs
@@ -1,12 +1,9 @@
using Microsoft.Extensions.Configuration;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
namespace Core.Configurations.PostgresqlConfigurationBuilder
{
+ ///
+ /// LISTEN / NOTIFY in Postgresql
+ ///
public static class PostgresConfigurationExtensions
{
public static IConfigurationBuilder AddPostgresConfiguration(
diff --git a/Database/Identity/DbSetup.cs b/Database/Identity/DbSetup.cs
index a8ab1b0..09d2fe4 100644
--- a/Database/Identity/DbSetup.cs
+++ b/Database/Identity/DbSetup.cs
@@ -3,77 +3,94 @@ using System.Data;
namespace Database.Identity
{
- public class DbSetup
- {
- private readonly IDbConnection _db;
+ public class DbSetup
+ {
+ private readonly IDbConnection _db;
+ string _schema;
- public DbSetup(IDbConnection db)
- {
- _db = db;
- }
+ public DbSetup(IDbConnection db)
+ {
+ _db = db;
+ }
- public void CreateDatabase()
- {
- var schema = "dev";
+ public async Task CreateDatabase(string schema)
+ {
+ _schema = schema;
- if (_db.State != ConnectionState.Open)
- _db.Open();
+ if (_db.State != ConnectionState.Open)
+ _db.Open();
- using var transaction = _db.BeginTransaction();
- try
- {
- // Create tables
- _db.Execute(@$"
- CREATE TABLE IF NOT EXISTS {schema}.users (
- id SERIAL PRIMARY KEY,
- email VARCHAR(256) NOT NULL UNIQUE,
- password_hash VARCHAR(256) NOT NULL,
- security_stamp VARCHAR(36) NOT NULL,
- email_confirmed BOOLEAN NOT NULL DEFAULT FALSE,
- created_date TIMESTAMP NOT NULL,
- last_login_date TIMESTAMP NULL
- );
+ using var transaction = _db.BeginTransaction();
+ try
+ {
+ await CreateUserTable();
+ await CreateTenantTable();
+ await CreateUserTenantTable();
+ await SetupRLS();
- CREATE TABLE IF NOT EXISTS {schema}.tenants (
- id SERIAL PRIMARY KEY,
- connection_string VARCHAR(500) NOT NULL,
- created_date TIMESTAMP NOT NULL,
- created_by INTEGER REFERENCES users(id),
- is_active BOOLEAN DEFAULT true
- );
+ transaction.Commit();
+ }
+ catch
+ {
+ transaction.Rollback();
+ throw;
+ }
+ }
- CREATE TABLE IF NOT EXISTS {schema}.user_tenants (
- user_id INTEGER REFERENCES users(id),
- tenant_id INTEGER REFERENCES tenants(id),
- created_date TIMESTAMP NOT NULL,
- PRIMARY KEY (user_id, tenant_id)
- );
+ private async Task CreateUserTable()
+ {
+ await _db.ExecuteSqlAsync(@$"
+ CREATE TABLE IF NOT EXISTS {_schema}.users (
+ id SERIAL PRIMARY KEY,
+ email VARCHAR(256) NOT NULL UNIQUE,
+ password_hash VARCHAR(256) NOT NULL,
+ security_stamp VARCHAR(36) NOT NULL,
+ email_confirmed BOOLEAN NOT NULL DEFAULT FALSE,
+ created_date TIMESTAMP NOT NULL,
+ last_login_date TIMESTAMP NULL
+ );");
+ }
- -- Enable RLS på både tenants og user_tenants
- ALTER TABLE {schema}.tenants ENABLE ROW LEVEL SECURITY;
- ALTER TABLE {schema}.user_tenants ENABLE ROW LEVEL SECURITY;
+ private async Task CreateTenantTable()
+ {
+ await _db.ExecuteSqlAsync(@$"
+ CREATE TABLE IF NOT EXISTS {_schema}.tenants (
+ id SERIAL PRIMARY KEY,
+ connection_string VARCHAR(500) NOT NULL,
+ created_date TIMESTAMP NOT NULL,
+ created_by INTEGER REFERENCES {_schema}.users(id),
+ is_active BOOLEAN DEFAULT true
+ );");
+ }
- -- RLS policy for tenants
- DROP POLICY IF EXISTS tenant_access ON {schema}.tenants;
- CREATE POLICY tenant_access ON {schema}.tenants
- USING (id IN (
- SELECT tenant_id
- FROM {schema}.user_tenants
- WHERE user_id = current_setting('app.user_id', TRUE)::INTEGER
- ));
+ private async Task CreateUserTenantTable()
+ {
+ await _db.ExecuteSqlAsync(@$"
+ CREATE TABLE IF NOT EXISTS {_schema}.user_tenants (
+ user_id INTEGER REFERENCES {_schema}.users(id),
+ tenant_id INTEGER REFERENCES {_schema}.tenants(id),
+ created_date TIMESTAMP NOT NULL,
+ PRIMARY KEY (user_id, tenant_id)
+ );");
+ }
- -- RLS policy for user_tenants
- DROP POLICY IF EXISTS user_tenant_access ON {schema}.user_tenants;
- CREATE POLICY user_tenant_access ON {schema}.user_tenants
- USING (user_id = current_setting('app.user_id', TRUE)::INTEGER);");
+ private async Task SetupRLS()
+ {
+ await _db.ExecuteSqlAsync(@$"
+ ALTER TABLE {_schema}.tenants ENABLE ROW LEVEL SECURITY;
+ ALTER TABLE {_schema}.user_tenants ENABLE ROW LEVEL SECURITY;
- transaction.Commit();
- }
- catch
- {
- transaction.Rollback();
- throw;
- }
- }
- }
+ DROP POLICY IF EXISTS tenant_access ON {_schema}.tenants;
+ CREATE POLICY tenant_access ON {_schema}.tenants
+ USING (id IN (
+ SELECT tenant_id
+ FROM {_schema}.user_tenants
+ WHERE user_id = current_setting('app.user_id', TRUE)::INTEGER
+ ));
+
+ DROP POLICY IF EXISTS user_tenant_access ON {_schema}.user_tenants;
+ CREATE POLICY user_tenant_access ON {_schema}.user_tenants
+ USING (user_id = current_setting('app.user_id', TRUE)::INTEGER);");
+ }
+ }
}
diff --git a/Database/Tenants/TenantSetupService.cs b/Database/Tenants/TenantSetupService.cs
index 81a646c..9ea033d 100644
--- a/Database/Tenants/TenantSetupService.cs
+++ b/Database/Tenants/TenantSetupService.cs
@@ -17,9 +17,9 @@ namespace Database.Tenants
public async Task CreateTenantInDatabase(string schema, string user, string password)
{
if (!Regex.IsMatch(schema, "^[a-zA-Z0-9_]+$"))
- {
throw new ArgumentException("Invalid schema name");
- }
+
+
await CreateUser(user, password);
await CreateSchema(schema);
await CreateRolesTable(schema);
diff --git a/PlanTempus.sln b/PlanTempus.sln
index add7632..d85aa5c 100644
--- a/PlanTempus.sln
+++ b/PlanTempus.sln
@@ -10,7 +10,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "Application\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Database", "Database\Database.csproj", "{D5096A7F-E6D4-4C87-874E-2D9A6BEAD57F}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPostgresLISTEN", "TestPostgresLISTEN\TestPostgresLISTEN.csproj", "{743EF625-6C74-419C-A492-AA069956F471}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPostgresql", "TestPostgresLISTEN\TestPostgresql.csproj", "{743EF625-6C74-419C-A492-AA069956F471}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -46,3 +46,4 @@ Global
SolutionGuid = {AF20C396-63E0-48AE-A4EA-5D24A20C4845}
EndGlobalSection
EndGlobal
+Global
diff --git a/TestPostgresLISTEN/TestPostgresLISTEN.csproj b/TestPostgresLISTEN/TestPostgresql.csproj
similarity index 100%
rename from TestPostgresLISTEN/TestPostgresLISTEN.csproj
rename to TestPostgresLISTEN/TestPostgresql.csproj
diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj
index 3ab9fcb..6e294c1 100644
--- a/Tests/Tests.csproj
+++ b/Tests/Tests.csproj
@@ -17,6 +17,7 @@
+
diff --git a/Tests/UnitTest1.cs b/Tests/UnitTest1.cs
index 675313e..d1492dc 100644
--- a/Tests/UnitTest1.cs
+++ b/Tests/UnitTest1.cs
@@ -19,8 +19,8 @@ namespace Tests
conn.ExecuteSql("SELECT 1 as p");
- var sql = "SELECT * FROM swp.foo";
- var customers = conn.Query(sql, commandType:CommandType.Text);
+ //var sql = "SELECT * FROM swp.foo";
+ //var customers = conn.Query(sql, commandType:CommandType.Text);
}
@@ -30,9 +30,19 @@ namespace Tests
var conn = Container.Resolve();
}
+ [TestMethod]
+ public async Task TryDbSetup()
+ {
+ var conn = Container.Resolve();
+
+ var dbSetup = new Database.Identity.DbSetup(conn);
+ await dbSetup.CreateDatabase("swp");
+ }
+
+
[TestMethod]
- public void MyTestMethod()
+ public void SetupPostgresql_LISTEN()
{
var builder = new ConfigurationBuilder()
.AddPostgresConfiguration(options =>
diff --git a/Tests/appsettings.dev.json b/Tests/appsettings.dev.json
index 0e3cd9a..bd7624b 100644
--- a/Tests/appsettings.dev.json
+++ b/Tests/appsettings.dev.json
@@ -1,7 +1,7 @@
{
"AllowedHosts": "*",
"ConnectionStrings": {
- "ptdb": "Host=192.168.1.57;Port=5432;Database=ptdb01;User Id=sathumper;Password=3911;"
+ "ptdb": "Host=192.168.1.57;Port=5432;Database=ptdb01;User Id=postgres;Password=3911;"
},
"ApplicationInsights": {
"ConnectionString": "InstrumentationKey=6d2e76ee-5343-4691-a5e3-81add43cb584;IngestionEndpoint=https://northeurope-0.in.applicationinsights.azure.com/"