diff --git a/routes/__pycache__/main.cpython-313.pyc b/routes/__pycache__/main.cpython-313.pyc index 9c60ea4..337a0b7 100644 Binary files a/routes/__pycache__/main.cpython-313.pyc and b/routes/__pycache__/main.cpython-313.pyc differ diff --git a/routes/main.py b/routes/main.py index bf8534d..779e903 100644 --- a/routes/main.py +++ b/routes/main.py @@ -1,6 +1,6 @@ from flask import render_template, Blueprint, redirect, url_for, request, flash, Response, jsonify, session from flask_login import current_user, login_required -from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings, Event, Conversation, Message, MessageAttachment, Notif, EmailTemplate +from models import User, db, Room, RoomFile, RoomMemberPermission, SiteSettings, Event, Conversation, Message, MessageAttachment, Notif, EmailTemplate, Mail from routes.auth import require_password_change import os from werkzeug.utils import secure_filename @@ -11,6 +11,8 @@ import sys import time from forms import CompanySettingsForm from utils import log_event, create_notification, get_unread_count +from io import StringIO +import csv # Set up logging to show in console logging.basicConfig( @@ -1119,4 +1121,166 @@ def init_routes(main_bp): }) except Exception as e: db.session.rollback() - return jsonify({'error': str(e)}), 500 \ No newline at end of file + return jsonify({'error': str(e)}), 500 + + @main_bp.route('/settings/mails') + @login_required + def mails(): + if not current_user.is_admin: + flash('Only administrators can access mail logs.', 'error') + return redirect(url_for('main.dashboard')) + + # Get filter parameters + status = request.args.get('status') + date_range = request.args.get('date_range', '7d') + user_id = request.args.get('user_id') + page = request.args.get('page', 1, type=int) + per_page = 10 + + # Calculate date range + end_date = datetime.utcnow() + if date_range == '24h': + start_date = end_date - timedelta(days=1) + elif date_range == '7d': + start_date = end_date - timedelta(days=7) + elif date_range == '30d': + start_date = end_date - timedelta(days=30) + else: + start_date = None + + # Build query + query = Mail.query + + if status: + query = query.filter_by(status=status) + if start_date: + query = query.filter(Mail.created_at >= start_date) + if user_id: + query = query.filter(Mail.recipient == User.query.get(user_id).email) + + # Get total count for pagination + total_mails = query.count() + total_pages = (total_mails + per_page - 1) // per_page + + # Get paginated mails + mails = query.order_by(Mail.created_at.desc()).paginate(page=page, per_page=per_page) + + # Get all users for filter dropdown + users = User.query.order_by(User.username).all() + + # Check if this is an AJAX request + if request.headers.get('X-Requested-With') == 'XMLHttpRequest': + return render_template('settings/tabs/mails.html', + mails=mails.items, + total_pages=total_pages, + current_page=page, + status=status, + date_range=date_range, + user_id=user_id, + users=users, + csrf_token=session.get('csrf_token')) + + # For full page requests, render the full settings page + site_settings = SiteSettings.get_settings() + return render_template('settings/settings.html', + primary_color=site_settings.primary_color, + secondary_color=site_settings.secondary_color, + active_tab='mails', + site_settings=site_settings, + mails=mails.items, + total_pages=total_pages, + current_page=page, + users=users, + csrf_token=session.get('csrf_token')) + + @main_bp.route('/settings/mails/') + @login_required + def get_mail_details(mail_id): + if not current_user.is_admin: + return jsonify({'error': 'Unauthorized'}), 403 + + mail = Mail.query.get_or_404(mail_id) + return jsonify({ + 'id': mail.id, + 'recipient': mail.recipient, + 'subject': mail.subject, + 'body': mail.body, + 'status': mail.status, + 'created_at': mail.created_at.isoformat(), + 'sent_at': mail.sent_at.isoformat() if mail.sent_at else None, + 'template': { + 'id': mail.template.id, + 'name': mail.template.name + } if mail.template else None + }) + + @main_bp.route('/settings/mails/download') + @login_required + def download_mails(): + if not current_user.is_admin: + flash('Only administrators can download mail logs.', 'error') + return redirect(url_for('main.dashboard')) + + # Get filter parameters + status = request.args.get('status') + date_range = request.args.get('date_range', '7d') + user_id = request.args.get('user_id') + + # Calculate date range + end_date = datetime.utcnow() + if date_range == '24h': + start_date = end_date - timedelta(days=1) + elif date_range == '7d': + start_date = end_date - timedelta(days=7) + elif date_range == '30d': + start_date = end_date - timedelta(days=30) + else: + start_date = None + + # Build query + query = Mail.query + + if status: + query = query.filter_by(status=status) + if start_date: + query = query.filter(Mail.created_at >= start_date) + if user_id: + query = query.filter(Mail.recipient == User.query.get(user_id).email) + + # Get all mails + mails = query.order_by(Mail.created_at.desc()).all() + + # Create CSV + output = StringIO() + writer = csv.writer(output) + + # Write header + writer.writerow([ + 'Created At', + 'Recipient', + 'Subject', + 'Status', + 'Template', + 'Sent At' + ]) + + # Write data + for mail in mails: + writer.writerow([ + mail.created_at.strftime('%Y-%m-%d %H:%M:%S'), + mail.recipient, + mail.subject, + mail.status, + mail.template.name if mail.template else '-', + mail.sent_at.strftime('%Y-%m-%d %H:%M:%S') if mail.sent_at else '-' + ]) + + output.seek(0) + + return Response( + output, + mimetype='text/csv', + headers={ + 'Content-Disposition': f'attachment; filename=mail_log_{datetime.utcnow().strftime("%Y%m%d_%H%M%S")}.csv' + } + ) \ No newline at end of file diff --git a/templates/settings/settings.html b/templates/settings/settings.html index 2d75fb3..b2c0f09 100644 --- a/templates/settings/settings.html +++ b/templates/settings/settings.html @@ -6,6 +6,7 @@ {% from "settings/tabs/debugging.html" import debugging_tab %} {% from "settings/tabs/events.html" import events_tab %} {% from "settings/tabs/email_templates.html" import email_templates_tab %} +{% from "settings/tabs/mails.html" import mails_tab %} {% from "settings/components/reset_colors_modal.html" import reset_colors_modal %} {% block title %}Settings - DocuPulse{% endblock %} @@ -43,6 +44,11 @@ Email Templates +