From 087f8ce0e9a5852944e1f2dc3c5e1cfddc519748 Mon Sep 17 00:00:00 2001 From: "Janus C. H. Knudsen" Date: Fri, 14 Feb 2025 20:14:01 +0100 Subject: [PATCH] Renaming from tenant to organization --- Core/Entities/Users/Class1.cs | 6 +- .../SetupConfiguration.cs | 10 +- Database/Core/DDL/SetupIdentitySystem.cs | 38 ++--- Database/Core/UserService.cs | 61 ++++---- Database/Tenants/InitializeTenantData.cs | 6 +- SetupInfrastructure/Program.cs | 6 +- .../.dbeaver/.credentials-config.json.bak | Bin 128 -> 128 bytes SqlManagement/.dbeaver/.data-sources.json.bak | 34 +--- .../.dbeaver/.project-metadata.json.bak | 2 +- .../.dbeaver/credentials-config.json | Bin 128 -> 224 bytes SqlManagement/.dbeaver/data-sources.json | 37 +++++ SqlManagement/.dbeaver/project-metadata.json | 2 +- SqlManagement/Scripts/Script.sql | 0 SqlManagement/Scripts/SmartConfigSystem.sql | 148 +----------------- SqlManagement/Scripts/grant-privileges.sql | 20 ++- Tests/PostgresTests.cs | 2 +- 16 files changed, 129 insertions(+), 243 deletions(-) create mode 100644 SqlManagement/Scripts/Script.sql diff --git a/Core/Entities/Users/Class1.cs b/Core/Entities/Users/Class1.cs index 1ddd5cf..3f13ae8 100644 --- a/Core/Entities/Users/Class1.cs +++ b/Core/Entities/Users/Class1.cs @@ -17,7 +17,7 @@ namespace Core.Entities.Users public DateTime? LastLoginDate { get; set; } } - public class Tenant + public class Organization { public int Id { get; set; } public string ConnectionString { get; set; } @@ -26,10 +26,10 @@ namespace Core.Entities.Users public bool IsActive { get; set; } } - public class UserTenant + public class UserOrganization { public int UserId { get; set; } - public int TenantId { get; set; } + public int OrganizationId { get; set; } public DateTime CreatedDate { get; set; } } } diff --git a/Database/ConfigurationManagementSystem/SetupConfiguration.cs b/Database/ConfigurationManagementSystem/SetupConfiguration.cs index d307b13..27b5974 100644 --- a/Database/ConfigurationManagementSystem/SetupConfiguration.cs +++ b/Database/ConfigurationManagementSystem/SetupConfiguration.cs @@ -90,8 +90,8 @@ public class SetupConfiguration : Core.IDbConfigure void CreateConfigurationIndexes() { const string sql = @" - CREATE INDEX idx_app_configuration_key ON app_configuration(""key""); - CREATE INDEX idx_app_configuration_validity ON app_configuration(valid_from, expires_at);"; + CREATE INDEX IF NOT EXISTS idx_app_configuration_key ON app_configuration(""key""); + CREATE INDEX IF NOT EXISTS idx_app_configuration_validity ON app_configuration(valid_from, expires_at);"; ExecuteSql(sql); } @@ -106,7 +106,7 @@ public class SetupConfiguration : Core.IDbConfigure END; $$ LANGUAGE plpgsql; - CREATE TRIGGER trg_app_configuration_modified_at + CREATE OR REPLACE TRIGGER trg_app_configuration_modified_at BEFORE UPDATE ON app_configuration FOR EACH ROW EXECUTE FUNCTION update_app_configuration_modified_at();"; @@ -124,7 +124,7 @@ public class SetupConfiguration : Core.IDbConfigure END; $$ LANGUAGE plpgsql; - CREATE TRIGGER trg_app_configuration_notify + CREATE OR REPLACE TRIGGER trg_app_configuration_notify AFTER INSERT OR UPDATE ON app_configuration FOR EACH ROW EXECUTE FUNCTION notify_app_configuration_change();"; @@ -169,7 +169,7 @@ public class SetupConfiguration : Core.IDbConfigure END; $$ LANGUAGE plpgsql; - CREATE TRIGGER trg_app_configuration_history + CREATE OR REPLACE TRIGGER trg_app_configuration_history AFTER INSERT OR UPDATE OR DELETE ON app_configuration FOR EACH ROW EXECUTE FUNCTION log_app_configuration_changes();"; ExecuteSql(sql); diff --git a/Database/Core/DDL/SetupIdentitySystem.cs b/Database/Core/DDL/SetupIdentitySystem.cs index c32556f..2e39809 100644 --- a/Database/Core/DDL/SetupIdentitySystem.cs +++ b/Database/Core/DDL/SetupIdentitySystem.cs @@ -31,8 +31,8 @@ namespace Database.Core.DDL try { CreateUsersTable(); - CreateTenantsTable(); - CreateUserTenantsTable(); + CreateOrganizationsTable(); + CreateUserOrganizationsTable(); SetupRLS(); _transaction.Commit(); @@ -78,12 +78,12 @@ namespace Database.Core.DDL } /// - /// Creates the tenants table + /// Creates the organizations table /// - void CreateTenantsTable() + void CreateOrganizationsTable() { var sql = @" - CREATE TABLE IF NOT EXISTS tenants ( + CREATE TABLE IF NOT EXISTS organizations ( id SERIAL PRIMARY KEY, connection_string VARCHAR(500) NOT NULL, is_active BOOLEAN NOT NULL DEFAULT TRUE, @@ -96,17 +96,17 @@ namespace Database.Core.DDL } /// - /// Creates the user_tenants table + /// Creates the user_organizations table /// - void CreateUserTenantsTable() + void CreateUserOrganizationsTable() { var sql = @" - CREATE TABLE IF NOT EXISTS user_tenants ( + CREATE TABLE IF NOT EXISTS user_organizations ( user_id INTEGER NOT NULL REFERENCES users(id), - tenant_id INTEGER NOT NULL REFERENCES tenants(id), + organization_id INTEGER NOT NULL REFERENCES organizations(id), pin_code VARCHAR(10) NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (user_id, tenant_id) + PRIMARY KEY (user_id, organization_id) );"; ExecuteSql(sql); @@ -114,23 +114,23 @@ namespace Database.Core.DDL } /// - /// Sets up Row Level Security (RLS) for the tenants and user_tenants tables. + /// Sets up Row Level Security (RLS) for the organizations and user_organizations tables. /// void SetupRLS() { var sql = new[] { - "ALTER TABLE tenants ENABLE ROW LEVEL SECURITY;", - "ALTER TABLE user_tenants ENABLE ROW LEVEL SECURITY;", - "DROP POLICY IF EXISTS tenant_access ON tenants;", - @"CREATE POLICY tenant_access ON tenants + "ALTER TABLE organizations ENABLE ROW LEVEL SECURITY;", + "ALTER TABLE user_organizations ENABLE ROW LEVEL SECURITY;", + "DROP POLICY IF EXISTS organization_access ON organizations;", + @"CREATE POLICY organization_access ON organizations USING (id IN ( - SELECT tenant_id - FROM user_tenants + SELECT organization_id + FROM user_organizations WHERE user_id = current_setting('app.user_id', TRUE)::INTEGER ));", - "DROP POLICY IF EXISTS user_tenant_access ON user_tenants;", - @"CREATE POLICY user_tenant_access ON user_tenants + "DROP POLICY IF EXISTS user_organization_access ON user_organizations;", + @"CREATE POLICY user_organization_access ON user_organizations USING (user_id = current_setting('app.user_id', TRUE)::INTEGER);" }; diff --git a/Database/Core/UserService.cs b/Database/Core/UserService.cs index bf78ddb..c6b1cb5 100644 --- a/Database/Core/UserService.cs +++ b/Database/Core/UserService.cs @@ -6,6 +6,8 @@ namespace Database.Core { public class UserService { + public record UserCreateCommand(string CorrelationId, string Email, string Password); + private readonly IDbConnection _db; public UserService(IDbConnection db) @@ -13,56 +15,57 @@ namespace Database.Core _db = db; } - public async Task CreateUserWithTenant(string email, string password, string tenantConnectionString) + public async Task CreateUser(UserCreateCommand command) { - var schema = "dev"; - if (_db.State != ConnectionState.Open) - _db.Open(); - - using var transaction = _db.BeginTransaction(); - try + var user = new User { - // Create user - var user = new User - { - Email = email, - PasswordHash = PasswordHasher.HashPassword(password), - SecurityStamp = Guid.NewGuid().ToString(), - EmailConfirmed = false, - CreatedDate = DateTime.UtcNow - }; + Email = command.Email, + PasswordHash = PasswordHasher.HashPassword(command.Password), + SecurityStamp = Guid.NewGuid().ToString(), + EmailConfirmed = false, + CreatedDate = DateTime.UtcNow + }; - var userId = await _db.ExecuteScalarAsync(@$" - INSERT INTO {schema}.users (email, password_hash, security_stamp, email_confirmed, created_date) + var userId = await _db.ExecuteScalarAsync(@$" + INSERT INTO users (email, password_hash, security_stamp, email_confirmed, created_at) VALUES (@Email, @PasswordHash, @SecurityStamp, @EmailConfirmed, @CreatedDate) RETURNING id", user); - // Create tenant - var tenant = new Tenant + } + public async Task CreateOrganization(int userId, string organizationConnectionString) + { + var schema = "dev"; + + + using var transaction = _db.OpenWithTransaction(); + try + { + // Create organization + var organization = new Organization { - ConnectionString = tenantConnectionString, + ConnectionString = organizationConnectionString, CreatedDate = DateTime.UtcNow, CreatedBy = userId, IsActive = true }; - var tenantId = await _db.ExecuteScalarAsync(@$" - INSERT INTO {schema}.tenants (connection_string, created_date, created_by, is_active) + var organizationId = await _db.ExecuteScalarAsync(@$" + INSERT INTO {schema}.organizations (connection_string, created_date, created_by, is_active) VALUES (@ConnectionString, @CreatedDate, @CreatedBy, @IsActive) - RETURNING id", tenant); + RETURNING id", organization); - // Link user to tenant - var userTenant = new UserTenant + // Link user to organization + var userOrganization = new UserOrganization { UserId = userId, - TenantId = tenantId, + OrganizationId = organizationId, CreatedDate = DateTime.UtcNow }; await _db.ExecuteAsync(@$" - INSERT INTO {schema}.user_tenants (user_id, tenant_id, created_date) - VALUES (@UserId, @TenantId, @CreatedDate)", userTenant); + INSERT INTO {schema}.user_organizations (user_id, organization_id, created_date) + VALUES (@UserId, @OrganizationId, @CreatedDate)", userOrganization); transaction.Commit(); } diff --git a/Database/Tenants/InitializeTenantData.cs b/Database/Tenants/InitializeTenantData.cs index 7322025..17bb73a 100644 --- a/Database/Tenants/InitializeTenantData.cs +++ b/Database/Tenants/InitializeTenantData.cs @@ -1,13 +1,13 @@ using Insight.Database; using System.Data; -namespace Database.Tenants +namespace Database.Organizations { - internal class InitializeTenantData + internal class InitializeOrganizationData { private readonly IDbConnection _db; - public InitializeTenantData(IDbConnection db) + public InitializeOrganizationData(IDbConnection db) { _db = db; } diff --git a/SetupInfrastructure/Program.cs b/SetupInfrastructure/Program.cs index 3032f3c..af340fd 100644 --- a/SetupInfrastructure/Program.cs +++ b/SetupInfrastructure/Program.cs @@ -52,7 +52,7 @@ namespace SetupInfrastructure sw.Start(); var setupApplicationUser = _container.Resolve(); setupApplicationUser.With(new Database.Core.DCL.SetupApplicationUser.Command { Password = "3911", Schema = "system", User = "sathumper" }); - Console.Write($"DONE, took: {sw.ElapsedMilliseconds} ms"); + Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms"); Console.WriteLine("::"); Console.WriteLine("::"); @@ -64,12 +64,12 @@ namespace SetupInfrastructure var setupIdentitySystem = _container.Resolve(); setupIdentitySystem.With(new Database.Core.DDL.SetupIdentitySystem.Command()); - Console.Write($"DONE, took: {sw.ElapsedMilliseconds} ms"); + Console.WriteLine($"DONE, took: {sw.ElapsedMilliseconds} ms"); Console.WriteLine("::"); Console.WriteLine("::"); - Console.Write("Database.Core.DDL.SetupIdentitySystem..."); + Console.Write("Database.ConfigurationManagementSystem.SetupConfiguration..."); sw.Restart(); var setupConfigurationSystem = _container.Resolve(); setupConfigurationSystem.With(new Database.ConfigurationManagementSystem.SetupConfiguration.Command()); diff --git a/SqlManagement/.dbeaver/.credentials-config.json.bak b/SqlManagement/.dbeaver/.credentials-config.json.bak index 95f3cea6469d8f67ce9340e2c12a54199ef068f9..01ccc39b1537d77f2f1b585352dc1367f52ae040 100644 GIT binary patch literal 128 zcmV-`0Du4YokuMl!$RAly?TzJq)PQ*zVJYqxAfVN1HDYXS{frXOGuf|Y&GB&J-es3 zYyc@`KW1ZGJZ<&kAwBU)8F2j)W3UlZDxH~{7M}nN?lId60!TFmeZ1_I6F)L literal 128 zcmV-`0Du2R^tH4eGO#*A^oTJI>kkn4?7F#?JcmxS6rLK_PjLujxEd2mXFwk}4d^); z=matx@z=`kkcjG^m5L;VWi87Lx*LIJp!tc@_Bhmcl%c-rlSHFz9^fxKlCDsl(CMb0@&>s^I$I#xZQ2q(XWC diff --git a/SqlManagement/.dbeaver/.data-sources.json.bak b/SqlManagement/.dbeaver/.data-sources.json.bak index ba364e4..46e1081 100644 --- a/SqlManagement/.dbeaver/.data-sources.json.bak +++ b/SqlManagement/.dbeaver/.data-sources.json.bak @@ -9,7 +9,8 @@ "configuration": { "host": "192.168.1.57", "port": "5432", - "url": "jdbc:postgresql://192.168.1.57:5432/", + "database": "ptmain", + "url": "jdbc:postgresql://192.168.1.57:5432/ptmain", "configurationType": "MANUAL", "home": "postgresql_client", "type": "dev", @@ -32,34 +33,9 @@ "postgresql.dd.tag.string": "false" }, "auth-model": "native" - } - }, - "postgres-jdbc-19484872d85-cd2a4a40116e706": { - "provider": "postgresql", - "driver": "postgres-jdbc", - "name": "UB-KK01-sathumper", - "configuration": { - "host": "192.168.1.57", - "port": "5432", - "database": "postgres", - "url": "jdbc:postgresql://192.168.1.57:5432/postgres", - "configurationType": "MANUAL", - "home": "postgresql_client", - "type": "dev", - "closeIdleConnection": true, - "provider-properties": { - "@dbeaver-show-non-default-db@": "true", - "@dbeaver-chosen-role@": "", - "@dbeaver-show-template-db@": "false", - "@dbeaver-show-unavailable-db@": "false", - "show-database-statistics": "false", - "@dbeaver-read-all-data-types-db@": "false", - "read-keys-with-columns": "false", - "@dbeaver-use-prepared-statements-db@": "false", - "postgresql.dd.plain.string": "false", - "postgresql.dd.tag.string": "false" - }, - "auth-model": "native" + }, + "custom-properties": { + "SQLEditor.outputPanel.autoShow": "false" } } }, diff --git a/SqlManagement/.dbeaver/.project-metadata.json.bak b/SqlManagement/.dbeaver/.project-metadata.json.bak index 1adf556..91b0730 100644 --- a/SqlManagement/.dbeaver/.project-metadata.json.bak +++ b/SqlManagement/.dbeaver/.project-metadata.json.bak @@ -1 +1 @@ -{"resources":{"Scripts/Script-11.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"sandbox"},"Scripts/SmartConfigSystem.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"sandbox"},"Scripts/grant-privileges.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"sandbox"}}} \ No newline at end of file +{"resources":{"Scripts/SmartConfigSystem.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"ptdb01"},"Scripts/grant-privileges.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"ptdb01"}}} \ No newline at end of file diff --git a/SqlManagement/.dbeaver/credentials-config.json b/SqlManagement/.dbeaver/credentials-config.json index d6c80afc254583713caff2e2a1bb3947285d94c6..078ce164b62fefb467c426ae6f0bea4116f1d303 100644 GIT binary patch literal 224 zcmV<603ZJYf=2J?v>yL_x6$2e22fF^6Ub% z5}dL_!8`4+W+LcDa;N$u$j zs^!cpV=z~#*!sTo&p;17LGMG*z;B~ty}V5g0!FBRtA$p9(?mRz(5G_ToMc6Hh)!=% a!#rX&m3H-l0R0@CF(puM5&wBxuIg^mG;?|Y literal 128 zcmV-`0Du2kD%BA*)(SqfL*-wIFS-A+rO<5!l_>U4_ia@3b$<);LOZR8a?d5$HRCr$b2q diff --git a/SqlManagement/.dbeaver/data-sources.json b/SqlManagement/.dbeaver/data-sources.json index 6bd4c37..5e6aa2e 100644 --- a/SqlManagement/.dbeaver/data-sources.json +++ b/SqlManagement/.dbeaver/data-sources.json @@ -6,6 +6,43 @@ "driver": "postgres-jdbc", "name": "UB-KK01-postgres", "save-password": true, + "configuration": { + "host": "192.168.1.57", + "port": "5432", + "database": "ptmain", + "url": "jdbc:postgresql://192.168.1.57:5432/ptmain", + "configurationType": "MANUAL", + "home": "postgresql_client", + "type": "dev", + "closeIdleConnection": true, + "properties": { + "connectTimeout": "20", + "loginTimeout": "20", + "escapeSyntaxCallMode": "callIfNoReturn" + }, + "provider-properties": { + "@dbeaver-show-non-default-db@": "true", + "@dbeaver-chosen-role@": "", + "@dbeaver-show-template-db@": "false", + "@dbeaver-show-unavailable-db@": "false", + "show-database-statistics": "false", + "@dbeaver-read-all-data-types-db@": "false", + "read-keys-with-columns": "false", + "@dbeaver-use-prepared-statements-db@": "false", + "postgresql.dd.plain.string": "false", + "postgresql.dd.tag.string": "false" + }, + "auth-model": "native" + }, + "custom-properties": { + "SQLEditor.outputPanel.autoShow": "false" + } + }, + "postgres-jdbc-1950174dc2f-6bd6c7100db1cc5c": { + "provider": "postgresql", + "driver": "postgres-jdbc", + "name": "UB-KK01-sathumper", + "save-password": true, "configuration": { "host": "192.168.1.57", "port": "5432", diff --git a/SqlManagement/.dbeaver/project-metadata.json b/SqlManagement/.dbeaver/project-metadata.json index 1adf556..f792e7c 100644 --- a/SqlManagement/.dbeaver/project-metadata.json +++ b/SqlManagement/.dbeaver/project-metadata.json @@ -1 +1 @@ -{"resources":{"Scripts/Script-11.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"sandbox"},"Scripts/SmartConfigSystem.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"sandbox"},"Scripts/grant-privileges.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"sandbox"}}} \ No newline at end of file +{"resources":{"Scripts/Script-1.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"ptmain"},"Scripts/Script.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"ptmain","default-schema":"system"},"Scripts/SmartConfigSystem.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"ptdb01","default-schema":"public"},"Scripts/grant-privileges.sql":{"default-datasource":"postgres-jdbc-1948450a8b4-5fc9eec404e65c44","default-catalog":"ptmain"}}} \ No newline at end of file diff --git a/SqlManagement/Scripts/Script.sql b/SqlManagement/Scripts/Script.sql new file mode 100644 index 0000000..e69de29 diff --git a/SqlManagement/Scripts/SmartConfigSystem.sql b/SqlManagement/Scripts/SmartConfigSystem.sql index 087f265..abd40c8 100644 --- a/SqlManagement/Scripts/SmartConfigSystem.sql +++ b/SqlManagement/Scripts/SmartConfigSystem.sql @@ -1,144 +1,4 @@ - -drop schema "public" -show search_path; - -set schema "ptmain"; - -CREATE SCHEMA if not exists ptmain; -GRANT USAGE, CREATE ON SCHEMA ptmain TO sathumper; -GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA ptmain TO sathumper; -GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA ptmain TO sathumper; - -ALTER DEFAULT PRIVILEGES IN SCHEMA ptmain -GRANT ALL PRIVILEGES ON TABLES TO sathumper; - - --- Create schema if not exists - -insert into --- Create main configuration table -CREATE TABLE app_configuration ( - id BIGSERIAL PRIMARY KEY, - key VARCHAR(255) NOT NULL, - value TEXT NOT NULL, - label VARCHAR(255), - content_type VARCHAR(255) DEFAULT 'text/plain', - valid_from TIMESTAMPTZ, - expires_at TIMESTAMPTZ, - created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - modified_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - etag UUID DEFAULT gen_random_uuid(), - CONSTRAINT app_configuration_key_unique UNIQUE (key, valid_from) -); - --- Create history table -CREATE TABLE app_configuration_history ( - history_id BIGSERIAL PRIMARY KEY, - operation CHAR(1) NOT NULL, -- I = Insert, U = Update, D = Delete - changed_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, - changed_by TEXT NOT NULL DEFAULT CURRENT_USER, - -- Original columns - id BIGINT NOT NULL, - key VARCHAR(255) NOT NULL, - value TEXT NOT NULL, - label VARCHAR(255), - content_type VARCHAR(255), - valid_from TIMESTAMPTZ, - expires_at TIMESTAMPTZ, - created_at TIMESTAMPTZ NOT NULL, - modified_at TIMESTAMPTZ NOT NULL, - etag UUID -); - - - --- Create function for updating modified_at -CREATE OR REPLACE FUNCTION update_modified_at() -RETURNS TRIGGER AS $$ -BEGIN - NEW.modified_at = CURRENT_TIMESTAMP; - RETURN NEW; -END; -$$ LANGUAGE plpgsql; - --- Create history tracking function -CREATE OR REPLACE FUNCTION track_configuration_history() -RETURNS TRIGGER AS $$ -BEGIN - -- Indsæt historikpost baseret på operationstypen - IF TG_OP = 'INSERT' THEN - INSERT INTO app_configuration_history( - operation, - id, key, value, label, content_type, valid_from, expires_at, - created_at, modified_at, etag - ) - VALUES ( - 'I', - NEW.id, NEW.key, NEW.value, NEW.label, NEW.content_type, NEW.valid_from, - NEW.expires_at, NEW.created_at, NEW.modified_at, NEW.etag - ); - ELSIF TG_OP = 'UPDATE' OR TG_OP = 'DELETE' THEN - -- Brug OLD for både UPDATE og DELETE - INSERT INTO app_configuration_history( - operation, - id, key, value, label, content_type, valid_from, expires_at, - created_at, modified_at, etag - ) - VALUES ( - CASE - WHEN TG_OP = 'UPDATE' THEN 'U' - WHEN TG_OP = 'DELETE' THEN 'D' - END, - OLD.id, OLD.key, OLD.value, OLD.label, OLD.content_type, OLD.valid_from, - OLD.expires_at, OLD.created_at, OLD.modified_at, OLD.etag - ); - END IF; - - -- Returner NULL for AFTER-trigger - RETURN NULL; -EXCEPTION - WHEN others THEN - -- Log fejl og rejs undtagelse - RAISE EXCEPTION 'Fejl i track_configuration_history: %', SQLERRM; -END; -$$ LANGUAGE plpgsql; - --- Create triggers -CREATE TRIGGER trg_app_configuration_modified_at - BEFORE UPDATE ON app_configuration - FOR EACH ROW - EXECUTE FUNCTION update_modified_at(); - -CREATE TRIGGER trg_app_configuration_history - AFTER INSERT OR UPDATE OR DELETE ON app_configuration - FOR EACH ROW - EXECUTE FUNCTION track_configuration_history(); - -CREATE TRIGGER trg_app_configuration_notify - AFTER INSERT OR UPDATE ON app_configuration - FOR EACH ROW - EXECUTE FUNCTION notify_config_change(); - --- Comments -COMMENT ON TABLE app_configuration IS 'Application configuration with temporal validity'; -COMMENT ON TABLE app_configuration_history IS 'Historical changes to application configuration'; -COMMENT ON COLUMN app_configuration_history.operation IS 'Type of operation: I=Insert, U=Update, D=Delete'; -COMMENT ON COLUMN app_configuration_history.changed_at IS 'When the change occurred'; -COMMENT ON COLUMN app_configuration_history.changed_by IS 'User who made the change'; - - -DELETE from ptmain.app_configuration - --- Email templates configuration -INSERT INTO ptmain.app_configuration ("key",value,"label",content_type,valid_from,expires_at,created_at,modified_at,etag) VALUES - ('Debug','true',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','f1348731-9396-4f1d-b40a-7fbd23a897d2'::uuid), - ('Database:ConnectionString','"Server=db.example.com;Port=5432"',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','2aa0bc3e-fa24-449a-8f25-a76d9b4d535e'::uuid), - ('Database:Timeout','30',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','d25ebb14-49f6-4e33-9ac7-a3253705d0fb'::uuid), - ('Database:UseSSL','true',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','f4d52ec4-b723-4561-9b18-0e7a68b89a17'::uuid), - ('Logging:FileOptions','{"Path": "/var/logs/app.log", "MaxSizeMB": 100, "RetentionDays": 7}',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','06c0891d-a860-4acc-917a-d0877f511c1b'::uuid), - ('Features:Experimental','{"Enabled": true, "RolloutPercentage": 25, "AllowedUserGroups": ["beta"]}',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','0136fdef-51d9-4909-82ef-f72053ce6d6d'::uuid), - ('API:Endpoints','"/api/users"',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','fe362b69-a486-48ad-9165-2e623e2e6f70'::uuid), - ('API:Endpoints','"/api/products"',NULL,'text/plain',NULL,NULL,'2025-02-02 14:25:22.200058+01','2025-02-02 14:25:22.200058+01','c087e2d4-1f38-4814-b4dd-f30c463dc6d1'::uuid); - - - + SELECT substring(datname, 5)::integer as dbnumber + FROM pg_database + WHERE datname LIKE 'ptdb%' + ORDER BY dbnumber DESC \ No newline at end of file diff --git a/SqlManagement/Scripts/grant-privileges.sql b/SqlManagement/Scripts/grant-privileges.sql index 2626a4d..ec169fd 100644 --- a/SqlManagement/Scripts/grant-privileges.sql +++ b/SqlManagement/Scripts/grant-privileges.sql @@ -4,14 +4,24 @@ CREATE ROLE sathumper WITH LOGIN PASSWORD '3911'; -CREATE SCHEMA ptmain; -GRANT USAGE, CREATE ON SCHEMA ptmain TO sathumper; -GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA ptmain TO sathumper; -GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA ptmain TO sathumper; +CREATE SCHEMA "system"; +GRANT USAGE, CREATE ON SCHEMA "system" TO sathumper; +GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA "system" TO sathumper; +GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA "system" TO sathumper; -ALTER DEFAULT PRIVILEGES IN SCHEMA ptmain +ALTER DEFAULT PRIVILEGES IN SCHEMA "system" GRANT ALL PRIVILEGES ON TABLES TO sathumper; +SELECT usename, useconfig +FROM pg_user +WHERE useconfig IS NOT NULL + AND useconfig::text LIKE '%search_path%' + +ALTER ROLE sathumper1 SET search_path='ss32' + + CREATE USER fm WITH PASSWORD 'asd' + + await _db.ExecuteAsync(sql); \ No newline at end of file diff --git a/Tests/PostgresTests.cs b/Tests/PostgresTests.cs index c0e79ea..61be7c2 100644 --- a/Tests/PostgresTests.cs +++ b/Tests/PostgresTests.cs @@ -49,7 +49,7 @@ namespace Tests } [TestMethod] - public void TryTenantSetupService() + public void TryOrganizationSetupService() { var conn = Container.Resolve(); }