1ST
This commit is contained in:
191
backend/routes/admin.py
Normal file
191
backend/routes/admin.py
Normal file
@@ -0,0 +1,191 @@
|
||||
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
|
Reference in New Issue
Block a user