05/06 Phase 2: updated and added new files
This commit is contained in:
@@ -1,7 +1,122 @@
|
||||
"""
|
||||
app/admin/settings_override/routes.py
|
||||
Phase 2 implementation.
|
||||
Superadmin tenant settings overrides: set, list active, lift.
|
||||
Overrides take precedence over tenant_settings at the application layer.
|
||||
All actions logged with before/after values.
|
||||
"""
|
||||
from flask import Blueprint
|
||||
|
||||
import logging
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from flask import Blueprint, render_template, redirect, url_for, flash, request
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
from app.extensions import db
|
||||
from app.models.platform import Tenant, TenantSettingOverride
|
||||
from app.admin.utils import superadmin_required, log_admin_action
|
||||
from app.security import validate_setting_key
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
settings_override_bp = Blueprint("settings_override", __name__, url_prefix="/settings-override")
|
||||
|
||||
|
||||
@settings_override_bp.route("/tenant/<int:tenant_id>")
|
||||
@login_required
|
||||
@superadmin_required
|
||||
def tenant_overrides(tenant_id):
|
||||
tenant = Tenant.query.get_or_404(tenant_id)
|
||||
active = (
|
||||
TenantSettingOverride.query
|
||||
.filter_by(tenant_id=tenant_id)
|
||||
.filter(TenantSettingOverride.lifted_at.is_(None))
|
||||
.order_by(TenantSettingOverride.overridden_at.desc())
|
||||
.all()
|
||||
)
|
||||
history = (
|
||||
TenantSettingOverride.query
|
||||
.filter_by(tenant_id=tenant_id)
|
||||
.filter(TenantSettingOverride.lifted_at.isnot(None))
|
||||
.order_by(TenantSettingOverride.lifted_at.desc())
|
||||
.limit(50)
|
||||
.all()
|
||||
)
|
||||
return render_template("admin/settings_override/list.html",
|
||||
tenant=tenant, active=active, history=history)
|
||||
|
||||
|
||||
@settings_override_bp.route("/tenant/<int:tenant_id>/set", methods=["GET", "POST"])
|
||||
@login_required
|
||||
@superadmin_required
|
||||
def set_override(tenant_id):
|
||||
tenant = Tenant.query.get_or_404(tenant_id)
|
||||
|
||||
if request.method == "POST":
|
||||
setting_key = request.form.get("setting_key", "").strip()
|
||||
setting_value = request.form.get("setting_value", "").strip()
|
||||
note = request.form.get("note", "").strip() or None
|
||||
|
||||
if not validate_setting_key(setting_key):
|
||||
return render_template("admin/settings_override/form.html", tenant=tenant,
|
||||
error="Invalid setting key (alphanumeric, underscores, dots only).")
|
||||
if not setting_value:
|
||||
return render_template("admin/settings_override/form.html", tenant=tenant,
|
||||
error="Setting value is required.")
|
||||
|
||||
# Lift any existing active override for the same key
|
||||
existing = (
|
||||
TenantSettingOverride.query
|
||||
.filter_by(tenant_id=tenant_id, setting_key=setting_key)
|
||||
.filter(TenantSettingOverride.lifted_at.is_(None))
|
||||
.first()
|
||||
)
|
||||
old_value = None
|
||||
if existing:
|
||||
old_value = existing.setting_value
|
||||
existing.lifted_at = datetime.now(timezone.utc)
|
||||
|
||||
override = TenantSettingOverride(
|
||||
tenant_id=tenant_id,
|
||||
setting_key=setting_key,
|
||||
setting_value=setting_value,
|
||||
overridden_by=current_user.id,
|
||||
note=note,
|
||||
)
|
||||
db.session.add(override)
|
||||
db.session.flush()
|
||||
log_admin_action(
|
||||
"settings_override.set", "tenant", tenant_id,
|
||||
before={"setting_key": setting_key, "setting_value": old_value},
|
||||
after={"setting_key": setting_key, "setting_value": setting_value, "note": note},
|
||||
)
|
||||
db.session.commit()
|
||||
logger.info("Settings override set: tenant=%s key=%s by=%s",
|
||||
tenant_id, setting_key, current_user.id)
|
||||
flash(f"Override for \'{setting_key}\' set on tenant \'{tenant.name}\'.", "success")
|
||||
return redirect(url_for("settings_override.tenant_overrides", tenant_id=tenant_id))
|
||||
|
||||
return render_template("admin/settings_override/form.html", tenant=tenant)
|
||||
|
||||
|
||||
@settings_override_bp.route("/<int:override_id>/lift", methods=["POST"])
|
||||
@login_required
|
||||
@superadmin_required
|
||||
def lift_override(override_id):
|
||||
override = TenantSettingOverride.query.get_or_404(override_id)
|
||||
if override.lifted_at is not None:
|
||||
flash("This override has already been lifted.", "warning")
|
||||
return redirect(url_for("settings_override.tenant_overrides",
|
||||
tenant_id=override.tenant_id))
|
||||
|
||||
override.lifted_at = datetime.now(timezone.utc)
|
||||
log_admin_action(
|
||||
"settings_override.lift", "tenant", override.tenant_id,
|
||||
before={"setting_key": override.setting_key, "setting_value": override.setting_value},
|
||||
after={"setting_key": override.setting_key, "lifted_at": str(override.lifted_at)},
|
||||
)
|
||||
db.session.commit()
|
||||
logger.info("Override lifted: id=%s tenant=%s key=%s by=%s",
|
||||
override_id, override.tenant_id, override.setting_key, current_user.id)
|
||||
flash(f"Override for \'{override.setting_key}\' lifted.", "success")
|
||||
return redirect(url_for("settings_override.tenant_overrides",
|
||||
tenant_id=override.tenant_id))
|
||||
|
||||
Reference in New Issue
Block a user