From 243a6734fd3edd5d71343c1a2357123ca9f4e0d9 Mon Sep 17 00:00:00 2001 From: Ultradesu Date: Mon, 21 Jul 2025 12:47:47 +0300 Subject: [PATCH] Improve acl model --- vpn/views.py | 105 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 98 insertions(+), 7 deletions(-) diff --git a/vpn/views.py b/vpn/views.py index 775672d..484b8f7 100644 --- a/vpn/views.py +++ b/vpn/views.py @@ -1,6 +1,8 @@ def userPortal(request, user_hash): """HTML portal for user to view their VPN access links and server information""" - from .models import User, ACLLink + from .models import User, ACLLink, AccessLog + from django.utils import timezone + from datetime import datetime, timedelta import logging logger = logging.getLogger(__name__) @@ -18,15 +20,36 @@ def userPortal(request, user_hash): try: # Get all ACL links for the user with server information acl_links = ACLLink.objects.filter(acl__user=user).select_related('acl__server', 'acl') + logger.info(f"Found {acl_links.count()} ACL links for user {user.username}") + + # Calculate date ranges for statistics + now = timezone.now() + thirty_days_ago = now - timedelta(days=30) + logger.debug(f"Calculating stats from {thirty_days_ago} to {now}") + + # Calculate total connection statistics + total_connections = AccessLog.objects.filter( + user=user.username, + action='Success' + ).count() + + recent_connections = AccessLog.objects.filter( + user=user.username, + action='Success', + timestamp__gte=thirty_days_ago + ).count() + + logger.info(f"User {user.username} stats: total_connections={total_connections}, recent_connections={recent_connections}") # Group links by server servers_data = {} total_links = 0 - total_connections = 0 # Can be calculated from AccessLog if needed for link in acl_links: server = link.acl.server server_name = server.name + logger.debug(f"Processing link {link.link} for server {server_name}") + logger.debug(f"Link last_access_time: {link.last_access_time}") if server_name not in servers_data: # Get server status and info @@ -34,12 +57,20 @@ def userPortal(request, user_hash): server_status = server.get_server_status() server_accessible = True server_error = None + logger.debug(f"Server {server_name} status retrieved successfully") except Exception as e: logger.warning(f"Could not get status for server {server_name}: {e}") server_status = {} server_accessible = False server_error = str(e) + # Calculate server-specific connection stats + server_total_connections = AccessLog.objects.filter( + user=user.username, + server=server_name, + action='Success' + ).count() + servers_data[server_name] = { 'server': server, 'status': server_status, @@ -47,32 +78,92 @@ def userPortal(request, user_hash): 'error': server_error, 'links': [], 'server_type': server.server_type, - 'total_connections': 0, + 'total_connections': server_total_connections, } + logger.debug(f"Created server data for {server_name} with {server_total_connections} connections") - # Add link information with simple last access from denormalized field + # Calculate link-specific statistics + # Note: AccessLog doesn't have link-specific tracking, so we'll use server-based stats + link_connections = AccessLog.objects.filter( + user=user.username, + server=server_name, + action='Success' + ).count() + + link_recent_connections = AccessLog.objects.filter( + user=user.username, + server=server_name, + action='Success', + timestamp__gte=thirty_days_ago + ).count() + + # Generate daily usage data for the last 30 days + daily_usage = [] + max_daily = 0 + + for i in range(30): + day_start = (now - timedelta(days=29-i)).replace(hour=0, minute=0, second=0, microsecond=0) + day_end = day_start + timedelta(days=1) + + day_connections = AccessLog.objects.filter( + user=user.username, + server=server_name, + action='Success', + timestamp__gte=day_start, + timestamp__lt=day_end + ).count() + + daily_usage.append(day_connections) + max_daily = max(max_daily, day_connections) + + logger.debug(f"Link {link.link} stats: connections={link_connections}, recent={link_recent_connections}, max_daily={max_daily}") + + # Add link information with comprehensive statistics link_url = f"{EXTERNAL_ADDRESS}/ss/{link.link}#{server_name}" - servers_data[server_name]['links'].append({ + link_data = { 'link': link, 'url': link_url, 'comment': link.comment or 'Default', 'last_access': link.last_access_time, - }) + 'connections': link_connections, + 'recent_connections': link_recent_connections, + 'daily_usage': daily_usage, + 'max_daily': max_daily, + } + + servers_data[server_name]['links'].append(link_data) total_links += 1 + + logger.debug(f"Added comprehensive link data for {link.link}") + + logger.info(f"Prepared data for {len(servers_data)} servers and {total_links} total links") + logger.info(f"Portal statistics: total_connections={total_connections}, recent_connections={recent_connections}") context = { 'user': user, 'servers_data': servers_data, 'total_servers': len(servers_data), 'total_links': total_links, + 'total_connections': total_connections, + 'recent_connections': recent_connections, 'external_address': EXTERNAL_ADDRESS, } + logger.debug(f"Context prepared with keys: {list(context.keys())}") + logger.debug(f"Servers in context: {list(servers_data.keys())}") + logger.debug(f"Final context values: total_connections={context['total_connections']}, recent_connections={context['recent_connections']}") + + # Log sample server data for debugging + for server_name, server_data in servers_data.items(): + logger.debug(f"Server {server_name}: total_connections={server_data['total_connections']}, links_count={len(server_data['links'])}") + for i, link_data in enumerate(server_data['links']): + logger.debug(f" Link {i}: connections={link_data['connections']}, recent={link_data['recent_connections']}, daily_usage_len={len(link_data['daily_usage'])}") + return render(request, 'vpn/user_portal.html', context) except Exception as e: - logger.error(f"Error loading user portal for {user.username}: {e}") + logger.error(f"Error loading user portal for {user.username}: {e}", exc_info=True) return render(request, 'vpn/user_portal_error.html', { 'error_title': 'Server Error', 'error_message': 'Unable to load your VPN information. Please try again later or contact support.'