Release v0.1.7
This commit is contained in:
@@ -10,7 +10,7 @@ readme = "README.md"
|
|||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
authors = [{ name = "GovOPlaN" }]
|
authors = [{ name = "GovOPlaN" }]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"govoplan-core>=0.1.6",
|
"govoplan-core>=0.1.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
[tool.setuptools.packages.find]
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER
|
from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPABILITY_AUTH_PRINCIPAL_RESOLVER
|
||||||
from govoplan_core.core.identity import CAPABILITY_IDENTITY_DIRECTORY
|
from govoplan_core.core.identity import CAPABILITY_IDENTITY_DIRECTORY
|
||||||
from govoplan_core.core.module_guards import persistent_table_uninstall_guard
|
from govoplan_core.core.module_guards import persistent_table_uninstall_guard
|
||||||
@@ -58,7 +60,12 @@ manifest = ModuleManifest(
|
|||||||
permissions=PERMISSIONS,
|
permissions=PERMISSIONS,
|
||||||
role_templates=ROLE_TEMPLATES,
|
role_templates=ROLE_TEMPLATES,
|
||||||
route_factory=_route_factory,
|
route_factory=_route_factory,
|
||||||
migration_spec=MigrationSpec(module_id="identity", metadata=Base.metadata),
|
migration_spec=MigrationSpec(
|
||||||
|
module_id="identity",
|
||||||
|
metadata=Base.metadata,
|
||||||
|
script_location=str(Path(__file__).with_name("migrations") / "versions"),
|
||||||
|
migration_after=("access",),
|
||||||
|
),
|
||||||
uninstall_guard_providers=(
|
uninstall_guard_providers=(
|
||||||
persistent_table_uninstall_guard(
|
persistent_table_uninstall_guard(
|
||||||
identity_models.Identity,
|
identity_models.Identity,
|
||||||
|
|||||||
1
src/govoplan_identity/backend/migrations/__init__.py
Normal file
1
src/govoplan_identity/backend/migrations/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"""Identity module migrations."""
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
"""identity directory
|
||||||
|
|
||||||
|
Revision ID: 5c6d7e8f9a10
|
||||||
|
Revises: 4a5b6c7d8e9f
|
||||||
|
Create Date: 2026-07-11 00:00:00.000000
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
revision = "5c6d7e8f9a10"
|
||||||
|
down_revision = "4a5b6c7d8e9f"
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def _tables() -> set[str]:
|
||||||
|
return set(sa.inspect(op.get_bind()).get_table_names())
|
||||||
|
|
||||||
|
|
||||||
|
def _indexes(table_name: str) -> set[str]:
|
||||||
|
if table_name not in _tables():
|
||||||
|
return set()
|
||||||
|
return {item["name"] for item in sa.inspect(op.get_bind()).get_indexes(table_name)}
|
||||||
|
|
||||||
|
|
||||||
|
def _create_index_if_missing(name: str, table_name: str, columns: list[str], *, unique: bool = False, **kwargs) -> None:
|
||||||
|
if table_name in _tables() and name not in _indexes(table_name):
|
||||||
|
op.create_index(name, table_name, columns, unique=unique, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _drop_index_if_exists(name: str, table_name: str) -> None:
|
||||||
|
if table_name in _tables() and name in _indexes(table_name):
|
||||||
|
op.drop_index(name, table_name=table_name)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
tables = _tables()
|
||||||
|
if "identity_identities" not in tables:
|
||||||
|
op.create_table(
|
||||||
|
"identity_identities",
|
||||||
|
sa.Column("id", sa.String(length=36), nullable=False),
|
||||||
|
sa.Column("display_name", sa.String(length=255), nullable=True),
|
||||||
|
sa.Column("external_subject", sa.String(length=255), nullable=True),
|
||||||
|
sa.Column("source", sa.String(length=50), nullable=False),
|
||||||
|
sa.Column("is_active", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("settings", sa.JSON(), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint("id", name=op.f("pk_identity_identities")),
|
||||||
|
)
|
||||||
|
_create_index_if_missing(op.f("ix_identity_identities_external_subject"), "identity_identities", ["external_subject"])
|
||||||
|
|
||||||
|
tables = _tables()
|
||||||
|
if "identity_account_links" not in tables:
|
||||||
|
op.create_table(
|
||||||
|
"identity_account_links",
|
||||||
|
sa.Column("id", sa.String(length=36), nullable=False),
|
||||||
|
sa.Column("identity_id", sa.String(length=36), nullable=False),
|
||||||
|
sa.Column("account_id", sa.String(length=36), nullable=False),
|
||||||
|
sa.Column("is_primary", sa.Boolean(), nullable=False),
|
||||||
|
sa.Column("source", sa.String(length=50), nullable=False),
|
||||||
|
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False),
|
||||||
|
sa.ForeignKeyConstraint(
|
||||||
|
["identity_id"],
|
||||||
|
["identity_identities.id"],
|
||||||
|
name=op.f("fk_identity_account_links_identity_id_identity_identities"),
|
||||||
|
ondelete="CASCADE",
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id", name=op.f("pk_identity_account_links")),
|
||||||
|
sa.UniqueConstraint("identity_id", "account_id", name="uq_identity_module_account_links_identity_account"),
|
||||||
|
)
|
||||||
|
_create_index_if_missing(op.f("ix_identity_account_links_account_id"), "identity_account_links", ["account_id"])
|
||||||
|
_create_index_if_missing(op.f("ix_identity_account_links_identity_id"), "identity_account_links", ["identity_id"])
|
||||||
|
_create_index_if_missing(
|
||||||
|
"uq_identity_module_account_links_primary_account",
|
||||||
|
"identity_account_links",
|
||||||
|
["account_id"],
|
||||||
|
unique=True,
|
||||||
|
sqlite_where=sa.text("is_primary = 1"),
|
||||||
|
postgresql_where=sa.text("is_primary IS TRUE"),
|
||||||
|
)
|
||||||
|
_create_index_if_missing(
|
||||||
|
"uq_identity_module_account_links_primary_identity",
|
||||||
|
"identity_account_links",
|
||||||
|
["identity_id"],
|
||||||
|
unique=True,
|
||||||
|
sqlite_where=sa.text("is_primary = 1"),
|
||||||
|
postgresql_where=sa.text("is_primary IS TRUE"),
|
||||||
|
)
|
||||||
|
|
||||||
|
tables = _tables()
|
||||||
|
if {"access_identities", "access_identity_account_links"}.issubset(tables):
|
||||||
|
op.execute("""
|
||||||
|
INSERT INTO identity_identities
|
||||||
|
(id, display_name, external_subject, source, is_active, settings, created_at, updated_at)
|
||||||
|
SELECT id, display_name, external_subject, source, is_active, settings, created_at, updated_at
|
||||||
|
FROM access_identities source_identity
|
||||||
|
WHERE NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM identity_identities target_identity
|
||||||
|
WHERE target_identity.id = source_identity.id
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
op.execute("""
|
||||||
|
INSERT INTO identity_account_links
|
||||||
|
(id, identity_id, account_id, is_primary, source, created_at, updated_at)
|
||||||
|
SELECT id, identity_id, account_id, is_primary, source, created_at, updated_at
|
||||||
|
FROM access_identity_account_links source_link
|
||||||
|
WHERE EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM identity_identities target_identity
|
||||||
|
WHERE target_identity.id = source_link.identity_id
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM identity_account_links target_link
|
||||||
|
WHERE target_link.id = source_link.id
|
||||||
|
)
|
||||||
|
AND NOT EXISTS (
|
||||||
|
SELECT 1
|
||||||
|
FROM identity_account_links target_link
|
||||||
|
WHERE target_link.identity_id = source_link.identity_id
|
||||||
|
AND target_link.account_id = source_link.account_id
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
_drop_index_if_exists("uq_identity_module_account_links_primary_identity", "identity_account_links")
|
||||||
|
_drop_index_if_exists("uq_identity_module_account_links_primary_account", "identity_account_links")
|
||||||
|
_drop_index_if_exists(op.f("ix_identity_account_links_identity_id"), "identity_account_links")
|
||||||
|
_drop_index_if_exists(op.f("ix_identity_account_links_account_id"), "identity_account_links")
|
||||||
|
if "identity_account_links" in _tables():
|
||||||
|
op.drop_table("identity_account_links")
|
||||||
|
_drop_index_if_exists(op.f("ix_identity_identities_external_subject"), "identity_identities")
|
||||||
|
if "identity_identities" in _tables():
|
||||||
|
op.drop_table("identity_identities")
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
"""Identity module migration versions."""
|
||||||
Reference in New Issue
Block a user