- Added monitoring metrics for project creation success and error handling in `ProjectRepository`. - Implemented similar monitoring for scenario creation in `ScenarioRepository`. - Refactored `run_monte_carlo` function in `simulation.py` to include timing and success/error metrics. - Introduced new CSS styles for headers, alerts, and navigation buttons in `main.css` and `projects.css`. - Created a new JavaScript file for navigation logic to handle chevron buttons. - Updated HTML templates to include new navigation buttons and improved styling for buttons. - Added tests for reporting service and routes to ensure proper functionality and access control. - Removed unused imports and optimized existing test files for better clarity and performance.
135 lines
3.3 KiB
Python
135 lines
3.3 KiB
Python
"""Add metadata columns to roles table"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sqlalchemy as sa
|
|
from alembic import op
|
|
|
|
# revision identifiers, used by Alembic.
|
|
revision = "20251112_00_add_roles_metadata_columns"
|
|
down_revision = "20251111_01"
|
|
branch_labels = None
|
|
depends_on = None
|
|
|
|
|
|
ROLE_BACKFILL = (
|
|
("admin", "Administrator", "Full platform access with user management rights."),
|
|
(
|
|
"project_manager",
|
|
"Project Manager",
|
|
"Manage projects, scenarios, and associated data.",
|
|
),
|
|
("analyst", "Analyst", "Review dashboards and scenario outputs."),
|
|
(
|
|
"viewer",
|
|
"Viewer",
|
|
"Read-only access to assigned projects and reports.",
|
|
),
|
|
)
|
|
|
|
|
|
def upgrade() -> None:
|
|
op.add_column(
|
|
"roles",
|
|
sa.Column("display_name", sa.String(length=128), nullable=True),
|
|
)
|
|
op.add_column(
|
|
"roles",
|
|
sa.Column("description", sa.Text(), nullable=True),
|
|
)
|
|
op.add_column(
|
|
"roles",
|
|
sa.Column(
|
|
"created_at",
|
|
sa.DateTime(timezone=True),
|
|
nullable=True,
|
|
server_default=sa.text("timezone('UTC', now())"),
|
|
),
|
|
)
|
|
op.add_column(
|
|
"roles",
|
|
sa.Column(
|
|
"updated_at",
|
|
sa.DateTime(timezone=True),
|
|
nullable=True,
|
|
server_default=sa.text("timezone('UTC', now())"),
|
|
),
|
|
)
|
|
|
|
connection = op.get_bind()
|
|
|
|
for name, display_name, description in ROLE_BACKFILL:
|
|
connection.execute(
|
|
sa.text(
|
|
"""
|
|
UPDATE roles
|
|
SET display_name = :display_name,
|
|
description = COALESCE(description, :description)
|
|
WHERE name = :name
|
|
AND display_name IS NULL
|
|
"""
|
|
),
|
|
{
|
|
"name": name,
|
|
"display_name": display_name,
|
|
"description": description,
|
|
},
|
|
)
|
|
|
|
connection.execute(
|
|
sa.text(
|
|
"""
|
|
UPDATE roles
|
|
SET display_name = INITCAP(REPLACE(name, '_', ' '))
|
|
WHERE display_name IS NULL
|
|
"""
|
|
)
|
|
)
|
|
|
|
connection.execute(
|
|
sa.text(
|
|
"""
|
|
UPDATE roles
|
|
SET created_at = timezone('UTC', now())
|
|
WHERE created_at IS NULL
|
|
"""
|
|
)
|
|
)
|
|
connection.execute(
|
|
sa.text(
|
|
"""
|
|
UPDATE roles
|
|
SET updated_at = timezone('UTC', now())
|
|
WHERE updated_at IS NULL
|
|
"""
|
|
)
|
|
)
|
|
|
|
op.alter_column(
|
|
"roles",
|
|
"display_name",
|
|
existing_type=sa.String(length=128),
|
|
nullable=False,
|
|
)
|
|
op.alter_column(
|
|
"roles",
|
|
"created_at",
|
|
existing_type=sa.DateTime(timezone=True),
|
|
nullable=False,
|
|
server_default=sa.text("timezone('UTC', now())"),
|
|
)
|
|
op.alter_column(
|
|
"roles",
|
|
"updated_at",
|
|
existing_type=sa.DateTime(timezone=True),
|
|
nullable=False,
|
|
server_default=sa.text("timezone('UTC', now())"),
|
|
)
|
|
|
|
|
|
def downgrade() -> None:
|
|
op.drop_column("roles", "updated_at")
|
|
op.drop_column("roles", "created_at")
|
|
op.drop_column("roles", "description")
|
|
op.drop_column("roles", "display_name")
|