Update migrate script with the latest database changes.
This commit is contained in:
+28
-35
@@ -13,8 +13,7 @@ Or via the CLI entry point (if installed):
|
||||
|
||||
import asyncio
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import base64url
|
||||
from uuid import UUID
|
||||
|
||||
from paskia.authsession import EXPIRES
|
||||
|
||||
@@ -36,13 +35,6 @@ SQL_DB_DEFAULT = "sqlite+aiosqlite:///paskia.sqlite"
|
||||
JSON_DB_DEFAULT = "paskia.jsonl"
|
||||
|
||||
|
||||
def _bytes_to_str(b: bytes | None) -> str | None:
|
||||
"""Convert bytes to base64url string."""
|
||||
if b is None:
|
||||
return None
|
||||
return base64url.enc(b)
|
||||
|
||||
|
||||
async def migrate_from_sql(
|
||||
sql_db_path: str = SQL_DB_DEFAULT,
|
||||
json_db_path: str = JSON_DB_DEFAULT,
|
||||
@@ -76,12 +68,11 @@ async def migrate_from_sql(
|
||||
|
||||
# Initialize destination JSON database
|
||||
json_db = JSONDB(json_db_path)
|
||||
json_db.load()
|
||||
await json_db.load()
|
||||
|
||||
print(f"Migrating from {sql_db_path} to {json_db_path}...")
|
||||
|
||||
# Build all data directly without saving (we'll save once at the end)
|
||||
with json_db._lock:
|
||||
# Track old permission ID -> new scope mapping for migration
|
||||
# Also track org-specific admin permissions to consolidate
|
||||
old_org_admin_pattern = re.compile(r"^auth:org:([0-9a-f-]+)$", re.IGNORECASE)
|
||||
@@ -96,7 +87,7 @@ async def migrate_from_sql(
|
||||
|
||||
# Migrate permissions with UUID keys and scope field
|
||||
# Always create exactly one common auth:org:admin permission for all org admin needs
|
||||
org_admin_perm_uuid = str(uuid7.create())
|
||||
org_admin_perm_uuid: UUID = uuid7.create()
|
||||
json_db._data.permissions[org_admin_perm_uuid] = _PermissionData(
|
||||
scope="auth:org:admin",
|
||||
display_name="Org Admin",
|
||||
@@ -119,7 +110,7 @@ async def migrate_from_sql(
|
||||
continue
|
||||
|
||||
# Regular permission - create with UUID key
|
||||
perm_uuid = str(uuid7.create())
|
||||
perm_uuid: UUID = uuid7.create()
|
||||
json_db._data.permissions[perm_uuid] = _PermissionData(
|
||||
scope=perm.id, # Old ID becomes the scope
|
||||
display_name=perm.display_name,
|
||||
@@ -133,8 +124,8 @@ async def migrate_from_sql(
|
||||
# Migrate organizations
|
||||
orgs = await sql_db.list_organizations()
|
||||
for org in orgs:
|
||||
key = str(org.uuid)
|
||||
json_db._data.orgs[key] = _OrgData(
|
||||
org_key: UUID = org.uuid
|
||||
json_db._data.orgs[org_key] = _OrgData(
|
||||
display_name=org.display_name,
|
||||
)
|
||||
# Update permissions to allow this org to grant them (by scope)
|
||||
@@ -143,24 +134,24 @@ async def migrate_from_sql(
|
||||
# Find permission with this scope and add org
|
||||
for pid, p in json_db._data.permissions.items():
|
||||
if p.scope == new_scope:
|
||||
p.orgs[key] = True
|
||||
p.orgs[org_key] = True
|
||||
break
|
||||
# Ensure every org can grant auth:org:admin
|
||||
json_db._data.permissions[org_admin_perm_uuid].orgs[key] = True
|
||||
json_db._data.permissions[org_admin_perm_uuid].orgs[org_key] = True
|
||||
print(f" Migrated {len(orgs)} organizations")
|
||||
|
||||
# Migrate roles - convert old permission IDs to scopes
|
||||
role_count = 0
|
||||
for org in orgs:
|
||||
for role in org.roles:
|
||||
key = str(role.uuid)
|
||||
role_key: UUID = role.uuid
|
||||
# Convert old permission IDs to scopes
|
||||
new_permissions = {}
|
||||
for old_perm_id in role.permissions or []:
|
||||
new_scope = perm_id_to_scope.get(old_perm_id, old_perm_id)
|
||||
new_permissions[new_scope] = True
|
||||
json_db._data.roles[key] = _RoleData(
|
||||
org=str(role.org_uuid),
|
||||
json_db._data.roles[role_key] = _RoleData(
|
||||
org=role.org_uuid,
|
||||
display_name=role.display_name,
|
||||
permissions=new_permissions,
|
||||
)
|
||||
@@ -173,10 +164,10 @@ async def migrate_from_sql(
|
||||
user_models = result.scalars().all()
|
||||
for um in user_models:
|
||||
user = um.as_dataclass()
|
||||
key = str(user.uuid)
|
||||
json_db._data.users[key] = _UserData(
|
||||
user_key: UUID = user.uuid
|
||||
json_db._data.users[user_key] = _UserData(
|
||||
display_name=user.display_name,
|
||||
role=str(user.role_uuid),
|
||||
role=user.role_uuid,
|
||||
created_at=user.created_at or datetime.now(timezone.utc),
|
||||
last_seen=user.last_seen,
|
||||
visits=user.visits,
|
||||
@@ -189,11 +180,11 @@ async def migrate_from_sql(
|
||||
cred_models = result.scalars().all()
|
||||
for cm in cred_models:
|
||||
cred = cm.as_dataclass()
|
||||
key = str(cred.uuid)
|
||||
json_db._data.credentials[key] = _CredentialData(
|
||||
cred_key: UUID = cred.uuid
|
||||
json_db._data.credentials[cred_key] = _CredentialData(
|
||||
credential_id=cred.credential_id,
|
||||
user=str(cred.user_uuid),
|
||||
aaguid=str(cred.aaguid),
|
||||
user=cred.user_uuid,
|
||||
aaguid=cred.aaguid,
|
||||
public_key=cred.public_key,
|
||||
sign_count=cred.sign_count,
|
||||
created_at=cred.created_at,
|
||||
@@ -208,10 +199,10 @@ async def migrate_from_sql(
|
||||
session_models = result.scalars().all()
|
||||
for sm in session_models:
|
||||
sess = sm.as_dataclass()
|
||||
key_b64 = _bytes_to_str(sess.key)
|
||||
json_db._data.sessions[key_b64] = _SessionData(
|
||||
user=str(sess.user_uuid),
|
||||
credential=str(sess.credential_uuid),
|
||||
session_key: bytes = sess.key
|
||||
json_db._data.sessions[session_key] = _SessionData(
|
||||
user=sess.user_uuid,
|
||||
credential=sess.credential_uuid,
|
||||
host=sess.host,
|
||||
ip=sess.ip,
|
||||
user_agent=sess.user_agent,
|
||||
@@ -225,9 +216,9 @@ async def migrate_from_sql(
|
||||
token_models = result.scalars().all()
|
||||
for tm in token_models:
|
||||
token = tm.as_dataclass()
|
||||
key_b64 = _bytes_to_str(token.key)
|
||||
json_db._data.reset_tokens[key_b64] = _ResetTokenData(
|
||||
user=str(token.user_uuid),
|
||||
token_key: bytes = token.key
|
||||
json_db._data.reset_tokens[token_key] = _ResetTokenData(
|
||||
user=token.user_uuid,
|
||||
expiry=token.expiry,
|
||||
token_type=token.token_type,
|
||||
)
|
||||
@@ -236,7 +227,9 @@ async def migrate_from_sql(
|
||||
# Queue and flush all changes with actor "migrate"
|
||||
json_db._current_actor = "migrate"
|
||||
json_db._queue_change()
|
||||
json_db.flush()
|
||||
from paskia.db.jsonl import flush_changes
|
||||
|
||||
await flush_changes(json_db.db_path, json_db._pending_changes)
|
||||
|
||||
print("Migration complete!")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user