85 lines
2.6 KiB
Python
85 lines
2.6 KiB
Python
"""
|
|
Admin REST API: user management, chat audit, system stats (RBAC-protected).
|
|
"""
|
|
from flask import Blueprint, request, jsonify
|
|
from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
|
|
from app import db
|
|
from app.models.user import User, Role
|
|
from app.models.chat import Conversation, Message
|
|
|
|
admin_api_bp = Blueprint("admin_api", __name__)
|
|
|
|
|
|
def admin_required(fn):
|
|
"""Require admin role (role name 'admin')."""
|
|
from functools import wraps
|
|
@wraps(fn)
|
|
def wrapper(*args, **kwargs):
|
|
identity = get_jwt_identity()
|
|
user = User.query.get(identity)
|
|
if not user or not user.role_id:
|
|
return jsonify({"error": "Forbidden"}), 403
|
|
role = Role.query.get(user.role_id)
|
|
if not role or role.name != "admin":
|
|
return jsonify({"error": "Admin required"}), 403
|
|
return fn(*args, **kwargs)
|
|
return wrapper
|
|
|
|
|
|
@admin_api_bp.route("/users", methods=["GET"])
|
|
@jwt_required()
|
|
@admin_required
|
|
def list_users():
|
|
skip = request.args.get("skip", 0, type=int)
|
|
limit = min(request.args.get("limit", 20, type=int), 100)
|
|
users = User.query.order_by(User.created_at.desc()).offset(skip).limit(limit).all()
|
|
return jsonify({"items": [u.to_dict() for u in users]})
|
|
|
|
|
|
@admin_api_bp.route("/users/<user_id>", methods=["PATCH"])
|
|
@jwt_required()
|
|
@admin_required
|
|
def update_user(user_id):
|
|
user = User.query.get(user_id)
|
|
if not user:
|
|
return jsonify({"error": "User not found"}), 404
|
|
data = request.get_json() or {}
|
|
if "is_active" in data:
|
|
user.is_active = bool(data["is_active"])
|
|
db.session.commit()
|
|
return jsonify(user.to_dict())
|
|
|
|
|
|
@admin_api_bp.route("/conversations", methods=["GET"])
|
|
@jwt_required()
|
|
@admin_required
|
|
def list_all_conversations():
|
|
skip = request.args.get("skip", 0, type=int)
|
|
limit = min(request.args.get("limit", 20, type=int), 100)
|
|
convs = Conversation.query.order_by(Conversation.last_message_at.desc()).offset(skip).limit(limit).all()
|
|
return jsonify({
|
|
"items": [
|
|
{
|
|
"id": c.id,
|
|
"user_id": c.user_id,
|
|
"title": c.title,
|
|
"last_message_at": c.last_message_at.isoformat() if c.last_message_at else None,
|
|
}
|
|
for c in convs
|
|
]
|
|
})
|
|
|
|
|
|
@admin_api_bp.route("/stats", methods=["GET"])
|
|
@jwt_required()
|
|
@admin_required
|
|
def system_stats():
|
|
user_count = User.query.count()
|
|
conv_count = Conversation.query.count()
|
|
msg_count = Message.query.count()
|
|
return jsonify({
|
|
"users": user_count,
|
|
"conversations": conv_count,
|
|
"messages": msg_count,
|
|
})
|