72 lines
2.0 KiB
Python
72 lines
2.0 KiB
Python
"""
|
|
app/admin/utils.py
|
|
Shared helpers used across all admin portal blueprints.
|
|
"""
|
|
|
|
import logging
|
|
from functools import wraps
|
|
|
|
from flask import abort, request
|
|
from flask_login import current_user
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def superadmin_required(f):
|
|
"""
|
|
Decorator: ensures the current user is an authenticated superadmin.
|
|
Aborts 401 if unauthenticated, 403 if wrong role.
|
|
Use on every admin blueprint route.
|
|
"""
|
|
@wraps(f)
|
|
def decorated(*args, **kwargs):
|
|
if not current_user.is_authenticated:
|
|
abort(401)
|
|
if current_user.role != "superadmin":
|
|
logger.warning(
|
|
"superadmin_required: denied user id=%s role=%s endpoint=%s",
|
|
current_user.id, current_user.role, request.endpoint,
|
|
)
|
|
abort(403)
|
|
return f(*args, **kwargs)
|
|
return decorated
|
|
|
|
|
|
def log_admin_action(action, target_type=None, target_id=None, before=None, after=None):
|
|
"""
|
|
Convenience wrapper — creates an AuditLog entry and adds it to the
|
|
current db session. Caller must commit.
|
|
"""
|
|
from app.models.platform import AuditLog
|
|
AuditLog.log(
|
|
actor_id=current_user.id,
|
|
actor_type="system_user",
|
|
action=action,
|
|
target_type=target_type,
|
|
target_id=target_id,
|
|
before=before,
|
|
after=after,
|
|
ip_address=request.remote_addr,
|
|
)
|
|
|
|
|
|
def model_to_dict(obj, fields):
|
|
"""
|
|
Return a plain JSON-serialisable dict of the named fields from an ORM object.
|
|
Converts datetime -> ISO-8601 string, Decimal -> float, all others pass through.
|
|
Safe to use directly as AuditLog before_json / after_json values.
|
|
"""
|
|
import datetime
|
|
from decimal import Decimal
|
|
|
|
result = {}
|
|
for f in fields:
|
|
val = getattr(obj, f, None)
|
|
if isinstance(val, (datetime.datetime, datetime.date)):
|
|
result[f] = val.isoformat()
|
|
elif isinstance(val, Decimal):
|
|
result[f] = float(val)
|
|
else:
|
|
result[f] = val
|
|
return result
|