diff --git a/app/repositories/permissions_repo.py b/app/repositories/permissions_repo.py index 5c19b93..393b58a 100644 --- a/app/repositories/permissions_repo.py +++ b/app/repositories/permissions_repo.py @@ -1,4 +1,4 @@ -from sqlalchemy import and_, delete, or_, select +from sqlalchemy import and_, delete, literal, or_, select from sqlalchemy.orm import Session from app.models.company import Company @@ -16,6 +16,7 @@ class PermissionsRepository: def list_by_user(self, user_id: str, authentik_sub: str) -> list[tuple[str, str, str | None, str, str]]: direct_stmt = ( select( + literal("direct"), UserScopePermission.scope_type, Company.company_key, Site.site_key, @@ -30,6 +31,7 @@ class PermissionsRepository: ) group_stmt = ( select( + literal("group"), PermissionGroupPermission.scope_type, PermissionGroupPermission.scope_id, PermissionGroupPermission.system, @@ -44,10 +46,11 @@ class PermissionsRepository: result: list[tuple[str, str, str | None, str, str]] = [] dedup = set() for row in rows: - if len(row) == 5: - scope_type, scope_id, system_key, module_key, action = row + source = row[0] + if source == "group": + _, scope_type, scope_id, system_key, module_key, action = row else: - scope_type, company_key, site_key, module_key, action = row + _, scope_type, company_key, site_key, module_key, action = row scope_id = company_key if scope_type == "company" else site_key system_key = module_key.split(".", 1)[0] if isinstance(module_key, str) and "." in module_key else None key = (scope_type, scope_id or "", system_key, module_key, action) diff --git a/scripts/init_schema.sql b/scripts/init_schema.sql index 3e4c524..3197aad 100644 --- a/scripts/init_schema.sql +++ b/scripts/init_schema.sql @@ -2,30 +2,13 @@ BEGIN; CREATE EXTENSION IF NOT EXISTS pgcrypto; -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'record_status') THEN - CREATE TYPE record_status AS ENUM ('active','inactive'); - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'client_status') THEN - CREATE TYPE client_status AS ENUM ('active','inactive'); - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'scope_type') THEN - CREATE TYPE scope_type AS ENUM ('company','site'); - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'permission_action') THEN - CREATE TYPE permission_action AS ENUM ('view','create','update','delete','manage'); - END IF; -END -$$; - CREATE TABLE IF NOT EXISTS users ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), authentik_sub TEXT NOT NULL UNIQUE, authentik_user_id INTEGER, email TEXT UNIQUE, display_name TEXT, - status record_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() @@ -43,7 +26,7 @@ CREATE TABLE IF NOT EXISTS companies ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), company_key TEXT NOT NULL UNIQUE, name TEXT NOT NULL, - status record_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -53,7 +36,7 @@ CREATE TABLE IF NOT EXISTS sites ( site_key TEXT NOT NULL UNIQUE, company_id UUID NOT NULL REFERENCES companies(id) ON DELETE CASCADE, name TEXT NOT NULL, - status record_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -62,7 +45,7 @@ CREATE TABLE IF NOT EXISTS systems ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), system_key TEXT NOT NULL UNIQUE, name TEXT NOT NULL, - status record_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -71,7 +54,7 @@ CREATE TABLE IF NOT EXISTS modules ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), module_key TEXT NOT NULL UNIQUE, name TEXT NOT NULL, - status record_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -93,8 +76,8 @@ CREATE TABLE IF NOT EXISTS user_scope_permissions ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, module_id UUID NOT NULL REFERENCES modules(id) ON DELETE CASCADE, - action permission_action NOT NULL, - scope_type scope_type NOT NULL, + action VARCHAR(32) NOT NULL, + scope_type VARCHAR(16) NOT NULL, company_id UUID REFERENCES companies(id) ON DELETE CASCADE, site_id UUID REFERENCES sites(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), @@ -113,7 +96,7 @@ CREATE TABLE IF NOT EXISTS permission_groups ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), group_key TEXT NOT NULL UNIQUE, name TEXT NOT NULL, - status record_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); @@ -142,7 +125,7 @@ CREATE TABLE IF NOT EXISTS api_clients ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), client_key TEXT NOT NULL UNIQUE, name TEXT NOT NULL, - status client_status NOT NULL DEFAULT 'active', + status VARCHAR(16) NOT NULL DEFAULT 'active', api_key_hash TEXT NOT NULL, allowed_origins JSONB NOT NULL DEFAULT '[]'::jsonb, allowed_ips JSONB NOT NULL DEFAULT '[]'::jsonb, diff --git a/scripts/migrate_enum_to_text.sql b/scripts/migrate_enum_to_text.sql new file mode 100644 index 0000000..32ea04e --- /dev/null +++ b/scripts/migrate_enum_to_text.sql @@ -0,0 +1,27 @@ +BEGIN; + +-- users / master tables +ALTER TABLE users ALTER COLUMN status TYPE VARCHAR(16) USING status::text; +ALTER TABLE companies ALTER COLUMN status TYPE VARCHAR(16) USING status::text; +ALTER TABLE sites ALTER COLUMN status TYPE VARCHAR(16) USING status::text; +ALTER TABLE systems ALTER COLUMN status TYPE VARCHAR(16) USING status::text; +ALTER TABLE modules ALTER COLUMN status TYPE VARCHAR(16) USING status::text; +ALTER TABLE permission_groups ALTER COLUMN status TYPE VARCHAR(16) USING status::text; + +-- api_clients +ALTER TABLE api_clients ALTER COLUMN status TYPE VARCHAR(16) USING status::text; + +-- user scoped permissions +ALTER TABLE user_scope_permissions ALTER COLUMN action TYPE VARCHAR(32) USING action::text; +ALTER TABLE user_scope_permissions ALTER COLUMN scope_type TYPE VARCHAR(16) USING scope_type::text; + +-- keep check constraint compatible with varchar +ALTER TABLE user_scope_permissions DROP CONSTRAINT IF EXISTS user_scope_permissions_check; +ALTER TABLE user_scope_permissions + ADD CONSTRAINT user_scope_permissions_check + CHECK ( + ((scope_type = 'company' AND company_id IS NOT NULL AND site_id IS NULL) + OR (scope_type = 'site' AND site_id IS NOT NULL AND company_id IS NULL)) + ); + +COMMIT;