Files
TODO_list_system/backend/routes/admin.py
beabigegg b0c86302ff 1ST
2025-08-29 16:25:46 +08:00

191 lines
6.8 KiB
Python

from flask import Blueprint, request, jsonify
from flask_jwt_extended import jwt_required, get_jwt_identity
from datetime import datetime, timedelta
from sqlalchemy import func
from models import db, TodoItem, TodoAuditLog, TodoMailLog, TodoImportJob
from utils.logger import get_logger
admin_bp = Blueprint('admin', __name__)
logger = get_logger(__name__)
# Admin users (in production, this should be in database or config)
ADMIN_USERS = ['admin', 'administrator']
def is_admin(identity):
"""Check if user is admin"""
return identity.lower() in ADMIN_USERS
@admin_bp.route('/stats', methods=['GET'])
@jwt_required()
def get_stats():
"""Get system statistics"""
try:
identity = get_jwt_identity()
if not is_admin(identity):
return jsonify({'error': 'Admin access required'}), 403
# Get date range
days = request.args.get('days', 30, type=int)
start_date = datetime.utcnow() - timedelta(days=days)
# Todo statistics
todo_stats = db.session.query(
func.count(TodoItem.id).label('total'),
func.sum(func.if_(TodoItem.status == 'NEW', 1, 0)).label('new'),
func.sum(func.if_(TodoItem.status == 'DOING', 1, 0)).label('doing'),
func.sum(func.if_(TodoItem.status == 'BLOCKED', 1, 0)).label('blocked'),
func.sum(func.if_(TodoItem.status == 'DONE', 1, 0)).label('done')
).filter(TodoItem.created_at >= start_date).first()
# User activity
active_users = db.session.query(
func.count(func.distinct(TodoAuditLog.actor_ad))
).filter(TodoAuditLog.created_at >= start_date).scalar()
# Email statistics
email_stats = db.session.query(
func.count(TodoMailLog.id).label('total'),
func.sum(func.if_(TodoMailLog.status == 'SENT', 1, 0)).label('sent'),
func.sum(func.if_(TodoMailLog.status == 'FAILED', 1, 0)).label('failed')
).filter(TodoMailLog.created_at >= start_date).first()
# Import statistics
import_stats = db.session.query(
func.count(TodoImportJob.id).label('total'),
func.sum(func.if_(TodoImportJob.status == 'COMPLETED', 1, 0)).label('completed'),
func.sum(func.if_(TodoImportJob.status == 'FAILED', 1, 0)).label('failed')
).filter(TodoImportJob.created_at >= start_date).first()
return jsonify({
'period_days': days,
'todos': {
'total': todo_stats.total or 0,
'new': todo_stats.new or 0,
'doing': todo_stats.doing or 0,
'blocked': todo_stats.blocked or 0,
'done': todo_stats.done or 0
},
'users': {
'active': active_users or 0
},
'emails': {
'total': email_stats.total or 0,
'sent': email_stats.sent or 0,
'failed': email_stats.failed or 0
},
'imports': {
'total': import_stats.total or 0,
'completed': import_stats.completed or 0,
'failed': import_stats.failed or 0
}
}), 200
except Exception as e:
logger.error(f"Error fetching stats: {str(e)}")
return jsonify({'error': 'Failed to fetch statistics'}), 500
@admin_bp.route('/audit-logs', methods=['GET'])
@jwt_required()
def get_audit_logs():
"""Get audit logs"""
try:
identity = get_jwt_identity()
if not is_admin(identity):
return jsonify({'error': 'Admin access required'}), 403
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 50, type=int)
actor = request.args.get('actor')
action = request.args.get('action')
todo_id = request.args.get('todo_id')
query = TodoAuditLog.query
if actor:
query = query.filter(TodoAuditLog.actor_ad == actor)
if action:
query = query.filter(TodoAuditLog.action == action)
if todo_id:
query = query.filter(TodoAuditLog.todo_id == todo_id)
query = query.order_by(TodoAuditLog.created_at.desc())
pagination = query.paginate(page=page, per_page=per_page, error_out=False)
logs = []
for log in pagination.items:
logs.append({
'id': log.id,
'actor_ad': log.actor_ad,
'todo_id': log.todo_id,
'action': log.action,
'detail': log.detail,
'created_at': log.created_at.isoformat()
})
return jsonify({
'logs': logs,
'total': pagination.total,
'page': page,
'per_page': per_page,
'pages': pagination.pages
}), 200
except Exception as e:
logger.error(f"Error fetching audit logs: {str(e)}")
return jsonify({'error': 'Failed to fetch audit logs'}), 500
@admin_bp.route('/mail-logs', methods=['GET'])
@jwt_required()
def get_mail_logs():
"""Get mail logs"""
try:
identity = get_jwt_identity()
if not is_admin(identity):
return jsonify({'error': 'Admin access required'}), 403
page = request.args.get('page', 1, type=int)
per_page = request.args.get('per_page', 50, type=int)
status = request.args.get('status')
type_ = request.args.get('type')
query = TodoMailLog.query
if status:
query = query.filter(TodoMailLog.status == status)
if type_:
query = query.filter(TodoMailLog.type == type_)
query = query.order_by(TodoMailLog.created_at.desc())
pagination = query.paginate(page=page, per_page=per_page, error_out=False)
logs = []
for log in pagination.items:
logs.append({
'id': log.id,
'todo_id': log.todo_id,
'type': log.type,
'triggered_by_ad': log.triggered_by_ad,
'recipients': log.recipients,
'subject': log.subject,
'status': log.status,
'error_text': log.error_text,
'created_at': log.created_at.isoformat(),
'sent_at': log.sent_at.isoformat() if log.sent_at else None
})
return jsonify({
'logs': logs,
'total': pagination.total,
'page': page,
'per_page': per_page,
'pages': pagination.pages
}), 200
except Exception as e:
logger.error(f"Error fetching mail logs: {str(e)}")
return jsonify({'error': 'Failed to fetch mail logs'}), 500