mirror of
https://github.com/house-of-vanity/OutFleet.git
synced 2025-08-22 06:57:17 +00:00
This commit is contained in:
17
vpn/admin.py
17
vpn/admin.py
@@ -1347,20 +1347,29 @@ class ACLLinkAdmin(admin.ModelAdmin):
|
|||||||
if not stats.daily_usage:
|
if not stats.daily_usage:
|
||||||
return mark_safe('<span style="color: #9ca3af; font-size: 11px;">No data</span>')
|
return mark_safe('<span style="color: #9ca3af; font-size: 11px;">No data</span>')
|
||||||
|
|
||||||
# Create mini chart
|
# Create wider mini chart for better visibility
|
||||||
max_val = max(stats.daily_usage) if stats.daily_usage else 1
|
max_val = max(stats.daily_usage) if stats.daily_usage else 1
|
||||||
chart_html = '<div style="display: flex; align-items: end; gap: 1px; height: 20px; width: 60px;">'
|
chart_html = '<div style="display: flex; align-items: end; gap: 1px; height: 35px; width: 180px;">'
|
||||||
|
|
||||||
for day_count in stats.daily_usage[-14:]: # Last 14 days for compact view
|
# Show last 30 days with wider bars for better visibility
|
||||||
|
for day_count in stats.daily_usage[-30:]: # Last 30 days
|
||||||
if max_val > 0:
|
if max_val > 0:
|
||||||
height_percent = (day_count / max_val) * 100
|
height_percent = (day_count / max_val) * 100
|
||||||
else:
|
else:
|
||||||
height_percent = 0
|
height_percent = 0
|
||||||
|
|
||||||
color = '#4ade80' if day_count > 0 else '#e5e7eb'
|
color = '#4ade80' if day_count > 0 else '#e5e7eb'
|
||||||
chart_html += f'<div style="background: {color}; width: 2px; height: {height_percent}%; min-height: 1px;" title="{day_count} connections"></div>'
|
chart_html += f'<div style="background: {color}; width: 5px; height: {height_percent}%; min-height: 1px; border-radius: 1px;" title="{day_count} connections"></div>'
|
||||||
|
|
||||||
chart_html += '</div>'
|
chart_html += '</div>'
|
||||||
|
|
||||||
|
# Add summary info below chart
|
||||||
|
total_last_30 = sum(stats.daily_usage[-30:]) if stats.daily_usage else 0
|
||||||
|
avg_daily = total_last_30 / 30 if total_last_30 > 0 else 0
|
||||||
|
chart_html += f'<div style="font-size: 10px; color: #6b7280; margin-top: 2px;">'
|
||||||
|
chart_html += f'Max: {max_val} | Avg: {avg_daily:.1f}'
|
||||||
|
chart_html += f'</div>'
|
||||||
|
|
||||||
return mark_safe(chart_html)
|
return mark_safe(chart_html)
|
||||||
except:
|
except:
|
||||||
return mark_safe('<span style="color: #dc2626; font-size: 11px;">-</span>')
|
return mark_safe('<span style="color: #dc2626; font-size: 11px;">-</span>')
|
||||||
|
@@ -165,6 +165,7 @@ class OutlineServer(Server):
|
|||||||
raise OutlineServerErrorException(f"Error searching for key: {e}")
|
raise OutlineServerErrorException(f"Error searching for key: {e}")
|
||||||
|
|
||||||
def get_user(self, user, raw=False):
|
def get_user(self, user, raw=False):
|
||||||
|
try:
|
||||||
user_info = self._get_key(user)
|
user_info = self._get_key(user)
|
||||||
if raw:
|
if raw:
|
||||||
return user_info
|
return user_info
|
||||||
@@ -177,6 +178,28 @@ class OutlineServer(Server):
|
|||||||
if not key.startswith('_') and key not in [] # fields to mask
|
if not key.startswith('_') and key not in [] # fields to mask
|
||||||
}
|
}
|
||||||
return outline_key_dict
|
return outline_key_dict
|
||||||
|
except OutlineServerErrorException as e:
|
||||||
|
# If user key not found, try to create it automatically
|
||||||
|
if "Key not found" in str(e):
|
||||||
|
self.logger.warning(f"[{self.name}] Key not found for user {user.username}, attempting to create")
|
||||||
|
try:
|
||||||
|
self.add_user(user)
|
||||||
|
# Try to get the key again after creation
|
||||||
|
user_info = self._get_key(user)
|
||||||
|
if raw:
|
||||||
|
return user_info
|
||||||
|
else:
|
||||||
|
outline_key_dict = {
|
||||||
|
key: value
|
||||||
|
for key, value in user_info.__dict__.items()
|
||||||
|
if not key.startswith('_') and key not in []
|
||||||
|
}
|
||||||
|
return outline_key_dict
|
||||||
|
except Exception as create_error:
|
||||||
|
self.logger.error(f"[{self.name}] Failed to create missing key for user {user.username}: {create_error}")
|
||||||
|
raise OutlineServerErrorException(f"Failed to get credentials: {e}")
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
def add_user(self, user):
|
def add_user(self, user):
|
||||||
@@ -195,9 +218,9 @@ class OutlineServer(Server):
|
|||||||
# Check if user needs update - but don't delete immediately
|
# Check if user needs update - but don't delete immediately
|
||||||
needs_update = (
|
needs_update = (
|
||||||
server_user.method != "chacha20-ietf-poly1305" or
|
server_user.method != "chacha20-ietf-poly1305" or
|
||||||
server_user.port != int(self.client_port) or
|
|
||||||
server_user.name != user.username or
|
server_user.name != user.username or
|
||||||
server_user.password != user.hash
|
server_user.password != user.hash
|
||||||
|
# Don't check port as Outline can assign different ports automatically
|
||||||
)
|
)
|
||||||
|
|
||||||
if needs_update:
|
if needs_update:
|
||||||
@@ -215,8 +238,8 @@ class OutlineServer(Server):
|
|||||||
name=user.username,
|
name=user.username,
|
||||||
method="chacha20-ietf-poly1305",
|
method="chacha20-ietf-poly1305",
|
||||||
password=user.hash,
|
password=user.hash,
|
||||||
data_limit=None,
|
data_limit=None
|
||||||
port=int(self.client_port)
|
# Don't specify port - let server assign automatically
|
||||||
)
|
)
|
||||||
logger.info(f"[{self.name}] User {user.username} updated")
|
logger.info(f"[{self.name}] User {user.username} updated")
|
||||||
except OutlineServerErrorException as e:
|
except OutlineServerErrorException as e:
|
||||||
@@ -233,8 +256,8 @@ class OutlineServer(Server):
|
|||||||
name=user.username,
|
name=user.username,
|
||||||
method="chacha20-ietf-poly1305",
|
method="chacha20-ietf-poly1305",
|
||||||
password=user.hash,
|
password=user.hash,
|
||||||
data_limit=None,
|
data_limit=None
|
||||||
port=int(self.client_port)
|
# Don't specify port - let server assign automatically
|
||||||
)
|
)
|
||||||
logger.info(f"[{self.name}] User {user.username} created")
|
logger.info(f"[{self.name}] User {user.username} created")
|
||||||
except OutlineServerErrorException as e:
|
except OutlineServerErrorException as e:
|
||||||
|
@@ -119,8 +119,8 @@ def sync_users(self, server_id):
|
|||||||
server = Server.objects.get(id=server_id)
|
server = Server.objects.get(id=server_id)
|
||||||
except Server.DoesNotExist:
|
except Server.DoesNotExist:
|
||||||
error_message = f"Server with id {server_id} not found - may have been deleted"
|
error_message = f"Server with id {server_id} not found - may have been deleted"
|
||||||
logger.error(error_message)
|
logger.warning(error_message)
|
||||||
create_task_log(task_id, "sync_all_users_on_server", "Server not found", 'FAILURE', message=error_message, execution_time=time.time() - start_time)
|
create_task_log(task_id, "sync_all_users_on_server", "Server not found", 'SUCCESS', message=error_message, execution_time=time.time() - start_time)
|
||||||
return error_message # Don't raise exception for deleted servers
|
return error_message # Don't raise exception for deleted servers
|
||||||
|
|
||||||
# Test server connectivity before proceeding
|
# Test server connectivity before proceeding
|
||||||
|
Reference in New Issue
Block a user