Printer assignment end to end, and a container that keeps a site's files
Assign printers to a MACHINE and let whichever PC controls it install them, with the observed half kept strictly apart from the assigned half: a collector report can never write an assignment row. Adoption is explicit. Adds a singular relationship type so defaultprinter can mean exactly one, client scripts that converge a bay's queues and correct a drifted one in place, and a wave gate so a fleet-wide driver rollout cannot stampede its own share. On the container side: the compose stack never persisted the instance directory, so a rebuild discarded plugins.json and every upload. It is a volume now, the image ships instance/ owned by the app user so the mountpoint is writable, and the database moves to MySQL 8.4 LTS, which the Windows runbook has recommended since 8.0 went end of life. The image also could not build at all: the frontend stage never copied the plugin staging script it runs. Adds a topology migration guide covering IIS to Docker and back.
This commit is contained in:
46
migrations/versions/7d34_singular_relationship_types.py
Normal file
46
migrations/versions/7d34_singular_relationship_types.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""Let a relationship type say "at most one of these per asset".
|
||||
|
||||
A PC has one default printer. The unique constraint on assetrelationships is
|
||||
(source, target, type), which happily accepts two DIFFERENT defaults on one
|
||||
asset - and the resolver then takes the oldest, so setting a new default through
|
||||
the generic relationships card left the old one winning, silently.
|
||||
|
||||
Cardinality belongs to the TYPE, not to the printers plugin: the next type that
|
||||
means "exactly one" (a primary user, a primary location) gets the rule for free,
|
||||
and core's create path is where every write already passes.
|
||||
|
||||
Revision ID: 7d34_singular_relationship_types
|
||||
Revises: 7d33_buildings_and_levels
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = '7d34_singular_relationship_types'
|
||||
down_revision = '7d33_buildings_and_levels'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
inspector = sa.inspect(bind)
|
||||
columns = {column['name'] for column in inspector.get_columns('relationshiptypes')}
|
||||
if 'issingular' not in columns:
|
||||
op.add_column('relationshiptypes',
|
||||
sa.Column('issingular', sa.Boolean(), nullable=False,
|
||||
server_default=sa.false()))
|
||||
|
||||
# defaultprinter is the type this exists for, and it is already in use, so
|
||||
# set it here rather than waiting for a re-seed: a site that upgrades and
|
||||
# does not re-seed would otherwise keep the old silent behaviour.
|
||||
op.execute("UPDATE relationshiptypes SET issingular = 1 "
|
||||
"WHERE LOWER(relationshiptype) = 'defaultprinter'")
|
||||
|
||||
|
||||
def downgrade():
|
||||
bind = op.get_bind()
|
||||
inspector = sa.inspect(bind)
|
||||
columns = {column['name'] for column in inspector.get_columns('relationshiptypes')}
|
||||
if 'issingular' in columns:
|
||||
op.drop_column('relationshiptypes', 'issingular')
|
||||
Reference in New Issue
Block a user