Initial import: shopdb-flask multi-site asset platform
Flask + Vue rewrite of the classic-ASP shopdb, built as a plugin framework so sister GE Aerospace sites can adopt it. Product version 0.7.0-pre-0.8.0, plugin contract 0.11.0, 966 backend tests. Key entry points: - docs/INSTALL-WINDOWS-IIS.md - tested Windows + IIS install runbook (own-site and subpath deployment methods) - docs/PILOT-DEPLOY.md - production pilot: stand up + import + verify - docs/IMPORT-API.md - schema-agnostic legacy data import contract - scripts/site_imports/wjf/ - West Jefferson reference import loader - docs/adr/ - twelve accepted architecture decision records
This commit is contained in:
205
migrations/versions/7d17_machines_rename.py
Normal file
205
migrations/versions/7d17_machines_rename.py
Normal file
@@ -0,0 +1,205 @@
|
||||
"""Equipment -> machines rename, core half
|
||||
|
||||
Part 1 of the approved equipment -> machines rename (the plugin half lives in
|
||||
plugins/machines/migrations/versions/0002_rename_from_equipment.py):
|
||||
|
||||
1. machinetypes -> modeltypes (+ machinetypeid -> modeltypeid,
|
||||
machinetype -> modeltype, models.machinetypeid -> models.modeltypeid).
|
||||
The table types the vendor MODELS catalog, not machine instances, so
|
||||
the new name is role-accurate and frees "machinetypes" for the plugin.
|
||||
2. Data flips: assettypes 'equipment' -> 'machine' (incl pluginname and
|
||||
tablename), auditlogs.entitytype 'Equipment' -> 'Machine', settings keys
|
||||
identifier_*_equipment_enabled -> identifier_*_machine_enabled,
|
||||
search_equipment_enabled -> search_machine_enabled, and permission
|
||||
rows equipment.* -> machines.* (role links survive).
|
||||
3. alembic_version_equipment -> alembic_version_machines (if present) so
|
||||
the renamed plugin's migration chain resumes seamlessly.
|
||||
|
||||
Idempotent via inspector guards, following the 7c01 pattern. MySQL is the
|
||||
only dialect the core chain runs against in practice.
|
||||
|
||||
Revision ID: 7d17_machines_rename
|
||||
Revises: 7d16_directoryemployees
|
||||
Create Date: 2026-07-11
|
||||
|
||||
"""
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
revision = '7d17_machines_rename'
|
||||
down_revision = '7d16_directoryemployees'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
def _fk_names(insp, table, referred_table):
|
||||
# find FK constraint names on table pointing at referred_table
|
||||
return [fk['name'] for fk in insp.get_foreign_keys(table)
|
||||
if fk.get('referred_table') == referred_table and fk.get('name')]
|
||||
|
||||
|
||||
def upgrade():
|
||||
bind = op.get_bind()
|
||||
insp = sa.inspect(bind)
|
||||
tables = set(insp.get_table_names())
|
||||
|
||||
# -- 1. machinetypes -> modeltypes ------------------------------------
|
||||
if 'machinetypes' in tables and 'modeltypes' not in tables:
|
||||
bind.exec_driver_sql("SET FOREIGN_KEY_CHECKS=0")
|
||||
|
||||
# drop the models -> machinetypes FK and its index before renaming
|
||||
for name in _fk_names(insp, 'models', 'machinetypes'):
|
||||
bind.exec_driver_sql(f"ALTER TABLE models DROP FOREIGN KEY {name}")
|
||||
model_indexes = {ix['name'] for ix in insp.get_indexes('models')}
|
||||
if 'machinetypeid' in model_indexes:
|
||||
bind.exec_driver_sql("ALTER TABLE models DROP KEY machinetypeid")
|
||||
|
||||
bind.exec_driver_sql("RENAME TABLE machinetypes TO modeltypes")
|
||||
bind.exec_driver_sql(
|
||||
"ALTER TABLE modeltypes "
|
||||
"CHANGE machinetypeid modeltypeid INT NOT NULL AUTO_INCREMENT, "
|
||||
"CHANGE machinetype modeltype VARCHAR(100) NOT NULL, "
|
||||
"DROP KEY machinetype, "
|
||||
"ADD UNIQUE KEY modeltype (modeltype)"
|
||||
)
|
||||
bind.exec_driver_sql(
|
||||
"ALTER TABLE models "
|
||||
"CHANGE machinetypeid modeltypeid INT NULL, "
|
||||
"ADD KEY modeltypeid (modeltypeid), "
|
||||
"ADD CONSTRAINT fk_models_modeltypeid "
|
||||
"FOREIGN KEY (modeltypeid) REFERENCES modeltypes (modeltypeid)"
|
||||
)
|
||||
bind.exec_driver_sql("SET FOREIGN_KEY_CHECKS=1")
|
||||
|
||||
# -- 2. data flips ------------------------------------------------------
|
||||
if 'assettypes' in tables:
|
||||
bind.exec_driver_sql(
|
||||
"UPDATE assettypes SET assettype='machine', pluginname='machines', "
|
||||
"tablename='machines' WHERE assettype='equipment'"
|
||||
)
|
||||
if 'auditlogs' in tables:
|
||||
bind.exec_driver_sql(
|
||||
"UPDATE auditlogs SET entitytype='Machine' "
|
||||
"WHERE entitytype='Equipment'"
|
||||
)
|
||||
if 'settings' in tables:
|
||||
_rename_setting_keys(bind, old_marker='_equipment_',
|
||||
new_marker='_machine_')
|
||||
if 'permissions' in tables:
|
||||
_rename_permissions(bind, old_prefix='equipment.',
|
||||
new_prefix='machines.',
|
||||
old_category='equipment', new_category='machines')
|
||||
|
||||
# -- 3. plugin version table --------------------------------------------
|
||||
if ('alembic_version_equipment' in tables
|
||||
and 'alembic_version_machines' not in tables):
|
||||
bind.exec_driver_sql(
|
||||
"RENAME TABLE alembic_version_equipment TO alembic_version_machines"
|
||||
)
|
||||
|
||||
|
||||
def _rename_setting_keys(bind, old_marker, new_marker):
|
||||
"""Rename settings keys embedding the assettype value, collision-safe.
|
||||
|
||||
Covers identifier_<name>_equipment_enabled and search_equipment_enabled.
|
||||
If a row with the new key already exists (fresh seed ran on new code),
|
||||
the old row is dropped instead of renamed.
|
||||
"""
|
||||
# broad fetch; the marker replace below filters non-matches
|
||||
rows = bind.exec_driver_sql(
|
||||
"SELECT settingid, `key` FROM settings"
|
||||
).fetchall()
|
||||
for settingid, key in rows:
|
||||
newkey = key.replace(old_marker, new_marker)
|
||||
if newkey == key:
|
||||
continue
|
||||
exists = bind.exec_driver_sql(
|
||||
"SELECT 1 FROM settings WHERE `key` = %s", (newkey,)
|
||||
).fetchone()
|
||||
if exists:
|
||||
bind.exec_driver_sql(
|
||||
"DELETE FROM settings WHERE settingid = %s", (settingid,))
|
||||
else:
|
||||
bind.exec_driver_sql(
|
||||
"UPDATE settings SET `key` = %s WHERE settingid = %s",
|
||||
(newkey, settingid))
|
||||
|
||||
|
||||
def _rename_permissions(bind, old_prefix, new_prefix, old_category,
|
||||
new_category):
|
||||
"""Rename permission rows in place so role links survive, collision-safe."""
|
||||
rows = bind.exec_driver_sql(
|
||||
"SELECT permissionid, name FROM permissions"
|
||||
).fetchall()
|
||||
for permissionid, name in rows:
|
||||
if not name.startswith(old_prefix):
|
||||
continue
|
||||
newname = new_prefix + name[len(old_prefix):]
|
||||
exists = bind.exec_driver_sql(
|
||||
"SELECT 1 FROM permissions WHERE name = %s", (newname,)
|
||||
).fetchone()
|
||||
if exists:
|
||||
bind.exec_driver_sql(
|
||||
"DELETE FROM permissions WHERE permissionid = %s",
|
||||
(permissionid,))
|
||||
else:
|
||||
bind.exec_driver_sql(
|
||||
"UPDATE permissions SET name = %s, category = %s "
|
||||
"WHERE permissionid = %s",
|
||||
(newname, new_category, permissionid))
|
||||
|
||||
|
||||
def downgrade():
|
||||
bind = op.get_bind()
|
||||
insp = sa.inspect(bind)
|
||||
tables = set(insp.get_table_names())
|
||||
|
||||
if ('alembic_version_machines' in tables
|
||||
and 'alembic_version_equipment' not in tables):
|
||||
bind.exec_driver_sql(
|
||||
"RENAME TABLE alembic_version_machines TO alembic_version_equipment"
|
||||
)
|
||||
|
||||
if 'settings' in tables:
|
||||
_rename_setting_keys(bind, old_marker='_machine_',
|
||||
new_marker='_equipment_')
|
||||
if 'permissions' in tables:
|
||||
_rename_permissions(bind, old_prefix='machines.',
|
||||
new_prefix='equipment.',
|
||||
old_category='machines', new_category='equipment')
|
||||
if 'auditlogs' in tables:
|
||||
bind.exec_driver_sql(
|
||||
"UPDATE auditlogs SET entitytype='Equipment' "
|
||||
"WHERE entitytype='Machine'"
|
||||
)
|
||||
if 'assettypes' in tables:
|
||||
bind.exec_driver_sql(
|
||||
"UPDATE assettypes SET assettype='equipment', "
|
||||
"pluginname='equipment', tablename='equipment' "
|
||||
"WHERE assettype='machine'"
|
||||
)
|
||||
|
||||
if 'modeltypes' in tables and 'machinetypes' not in tables:
|
||||
bind.exec_driver_sql("SET FOREIGN_KEY_CHECKS=0")
|
||||
for name in _fk_names(insp, 'models', 'modeltypes'):
|
||||
bind.exec_driver_sql(f"ALTER TABLE models DROP FOREIGN KEY {name}")
|
||||
model_indexes = {ix['name'] for ix in insp.get_indexes('models')}
|
||||
if 'modeltypeid' in model_indexes:
|
||||
bind.exec_driver_sql("ALTER TABLE models DROP KEY modeltypeid")
|
||||
bind.exec_driver_sql("RENAME TABLE modeltypes TO machinetypes")
|
||||
bind.exec_driver_sql(
|
||||
"ALTER TABLE machinetypes "
|
||||
"CHANGE modeltypeid machinetypeid INT NOT NULL AUTO_INCREMENT, "
|
||||
"CHANGE modeltype machinetype VARCHAR(100) NOT NULL, "
|
||||
"DROP KEY modeltype, "
|
||||
"ADD UNIQUE KEY machinetype (machinetype)"
|
||||
)
|
||||
bind.exec_driver_sql(
|
||||
"ALTER TABLE models "
|
||||
"CHANGE modeltypeid machinetypeid INT NULL, "
|
||||
"ADD KEY machinetypeid (machinetypeid), "
|
||||
"ADD CONSTRAINT models_ibfk_1 "
|
||||
"FOREIGN KEY (machinetypeid) REFERENCES machinetypes (machinetypeid)"
|
||||
)
|
||||
bind.exec_driver_sql("SET FOREIGN_KEY_CHECKS=1")
|
||||
Reference in New Issue
Block a user