Host-side identifier (systemd unit name and /var/lib/left4me dirs) is now
str(server.id), centralized in services/server_identity.server_unit_name.
Server.name becomes a free-form display label, required and unique per
user (was [a-z0-9_-]{1,64} and globally unique).
Migration 0006 swaps the old global UNIQUE(name) for UNIQUE(user_id, name).
Web routes already keyed on id; templates only used name for display.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
44 lines
1.4 KiB
Python
44 lines
1.4 KiB
Python
"""server name unique per user
|
|
|
|
Revision ID: 0006_server_name_per_user
|
|
Revises: 0005_script_overlays
|
|
Create Date: 2026-05-08
|
|
"""
|
|
from typing import Sequence, Union
|
|
|
|
from alembic import op
|
|
|
|
|
|
revision: str = "0006_server_name_per_user"
|
|
down_revision: Union[str, Sequence[str], None] = "0005_script_overlays"
|
|
branch_labels: Union[str, Sequence[str], None] = None
|
|
depends_on: Union[str, Sequence[str], None] = None
|
|
|
|
|
|
# 0001_initial defined `name` with column-level `unique=True`, which SQLite
|
|
# stored as an unnamed UNIQUE constraint. The naming_convention here lets
|
|
# batch_alter_table refer to it as "uq_servers_name" so we can drop it before
|
|
# recreating the table with the new (user_id, name) composite.
|
|
_NAMING_CONVENTION = {"uq": "uq_%(table_name)s_%(column_0_name)s"}
|
|
|
|
|
|
def upgrade() -> None:
|
|
with op.batch_alter_table(
|
|
"servers",
|
|
naming_convention=_NAMING_CONVENTION,
|
|
recreate="always",
|
|
) as batch_op:
|
|
batch_op.drop_constraint("uq_servers_name", type_="unique")
|
|
batch_op.create_unique_constraint(
|
|
"uq_servers_user_name", ["user_id", "name"]
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
with op.batch_alter_table(
|
|
"servers",
|
|
naming_convention=_NAMING_CONVENTION,
|
|
recreate="always",
|
|
) as batch_op:
|
|
batch_op.drop_constraint("uq_servers_user_name", type_="unique")
|
|
batch_op.create_unique_constraint("uq_servers_name", ["name"])
|