mirror of
https://github.com/house-of-vanity/OutFleet.git
synced 2025-08-21 14:37:16 +00:00
Force sync and purge
This commit is contained in:
50
vpn/admin.py
50
vpn/admin.py
@@ -53,24 +53,6 @@ class TaskExecutionLogAdmin(admin.ModelAdmin):
|
|||||||
# This action doesn't require selected items
|
# This action doesn't require selected items
|
||||||
try:
|
try:
|
||||||
from vpn.tasks import sync_all_users
|
from vpn.tasks import sync_all_users
|
||||||
from datetime import timedelta
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
# Check if sync is already running (last 10 minutes)
|
|
||||||
recent_cutoff = timezone.now() - timedelta(minutes=10)
|
|
||||||
running_syncs = TaskExecutionLog.objects.filter(
|
|
||||||
created_at__gte=recent_cutoff,
|
|
||||||
task_name='sync_all_servers',
|
|
||||||
status='STARTED'
|
|
||||||
)
|
|
||||||
|
|
||||||
if running_syncs.exists():
|
|
||||||
self.message_user(
|
|
||||||
request,
|
|
||||||
'Synchronization is already running. Please wait for completion.',
|
|
||||||
level=messages.WARNING
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
# Start the sync task
|
# Start the sync task
|
||||||
task = sync_all_users.delay()
|
task = sync_all_users.delay()
|
||||||
@@ -140,7 +122,7 @@ class TaskExecutionLogAdmin(admin.ModelAdmin):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def changelist_view(self, request, extra_context=None):
|
def changelist_view(self, request, extra_context=None):
|
||||||
"""Override to handle actions that don't require item selection and add sync status"""
|
"""Override to handle actions that don't require item selection"""
|
||||||
# Handle actions that don't require selection
|
# Handle actions that don't require selection
|
||||||
if 'action' in request.POST:
|
if 'action' in request.POST:
|
||||||
action = request.POST['action']
|
action = request.POST['action']
|
||||||
@@ -150,36 +132,6 @@ class TaskExecutionLogAdmin(admin.ModelAdmin):
|
|||||||
# Return redirect to prevent AttributeError
|
# Return redirect to prevent AttributeError
|
||||||
return redirect(request.get_full_path())
|
return redirect(request.get_full_path())
|
||||||
|
|
||||||
# Add sync status and controls to the changelist
|
|
||||||
extra_context = extra_context or {}
|
|
||||||
|
|
||||||
# Add sync statistics
|
|
||||||
from datetime import timedelta
|
|
||||||
from django.utils import timezone
|
|
||||||
|
|
||||||
# Get recent sync tasks (last 24 hours)
|
|
||||||
recent_cutoff = timezone.now() - timedelta(hours=24)
|
|
||||||
recent_syncs = TaskExecutionLog.objects.filter(
|
|
||||||
created_at__gte=recent_cutoff,
|
|
||||||
task_name='sync_all_servers'
|
|
||||||
)
|
|
||||||
|
|
||||||
total_recent = recent_syncs.count()
|
|
||||||
successful_recent = recent_syncs.filter(status='SUCCESS').count()
|
|
||||||
failed_recent = recent_syncs.filter(status='FAILURE').count()
|
|
||||||
running_recent = recent_syncs.filter(status='STARTED').count()
|
|
||||||
|
|
||||||
# Check if sync is currently running
|
|
||||||
currently_running = recent_syncs.filter(status='STARTED').exists()
|
|
||||||
|
|
||||||
extra_context.update({
|
|
||||||
'total_recent_syncs': total_recent,
|
|
||||||
'successful_recent_syncs': successful_recent,
|
|
||||||
'failed_recent_syncs': failed_recent,
|
|
||||||
'running_recent_syncs': running_recent,
|
|
||||||
'sync_currently_running': currently_running,
|
|
||||||
})
|
|
||||||
|
|
||||||
return super().changelist_view(request, extra_context)
|
return super().changelist_view(request, extra_context)
|
||||||
|
|
||||||
|
|
||||||
|
51
vpn/migrations/0002_taskexecutionlog.py
Normal file
51
vpn/migrations/0002_taskexecutionlog.py
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Generated manually to fix migration issue
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('vpn', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunSQL(
|
||||||
|
"DROP TABLE IF EXISTS vpn_taskexecutionlog CASCADE;",
|
||||||
|
reverse_sql="-- No reverse operation"
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TaskExecutionLog',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('task_id', models.CharField(help_text='Celery task ID', max_length=255)),
|
||||||
|
('task_name', models.CharField(help_text='Task name', max_length=100)),
|
||||||
|
('action', models.CharField(help_text='Action performed', max_length=100)),
|
||||||
|
('status', models.CharField(choices=[('STARTED', 'Started'), ('SUCCESS', 'Success'), ('FAILURE', 'Failure'), ('RETRY', 'Retry')], default='STARTED', max_length=20)),
|
||||||
|
('message', models.TextField(help_text='Detailed execution message')),
|
||||||
|
('execution_time', models.FloatField(blank=True, help_text='Execution time in seconds', null=True)),
|
||||||
|
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('server', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='vpn.server')),
|
||||||
|
('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='vpn.user')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Task Execution Log',
|
||||||
|
'verbose_name_plural': 'Task Execution Logs',
|
||||||
|
'ordering': ['-created_at'],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
# Create indexes with safe SQL to avoid conflicts
|
||||||
|
migrations.RunSQL(
|
||||||
|
"CREATE INDEX IF NOT EXISTS vpn_taskexec_task_id_idx ON vpn_taskexecutionlog (task_id);",
|
||||||
|
reverse_sql="DROP INDEX IF EXISTS vpn_taskexec_task_id_idx;"
|
||||||
|
),
|
||||||
|
migrations.RunSQL(
|
||||||
|
"CREATE INDEX IF NOT EXISTS vpn_taskexec_created_idx ON vpn_taskexecutionlog (created_at);",
|
||||||
|
reverse_sql="DROP INDEX IF EXISTS vpn_taskexec_created_idx;"
|
||||||
|
),
|
||||||
|
migrations.RunSQL(
|
||||||
|
"CREATE INDEX IF NOT EXISTS vpn_taskexec_status_idx ON vpn_taskexecutionlog (status);",
|
||||||
|
reverse_sql="DROP INDEX IF EXISTS vpn_taskexec_status_idx;"
|
||||||
|
),
|
||||||
|
]
|
@@ -3,49 +3,14 @@
|
|||||||
{% block content_title %}
|
{% block content_title %}
|
||||||
<h1>Task Execution Logs</h1>
|
<h1>Task Execution Logs</h1>
|
||||||
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; margin: 16px 0;">
|
<div style="background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 16px; margin: 16px 0;">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
<h3 style="margin: 0; color: #374151;">Sync Status (Last 24 hours)</h3>
|
<h3 style="margin: 0; color: #374151;">Manual Sync Control</h3>
|
||||||
{% if sync_currently_running %}
|
|
||||||
<span style="background: #fbbf24; color: #000; padding: 6px 12px; border-radius: 20px; font-size: 12px; font-weight: bold;">
|
|
||||||
⏳ Sync Running
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
<span style="background: #10b981; color: #fff; padding: 6px 12px; border-radius: 20px; font-size: 12px; font-weight: bold;">
|
|
||||||
✅ Sync Available
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: flex; gap: 20px; flex-wrap: wrap; margin-bottom: 16px;">
|
<div style="border-top: 1px solid #e5e7eb; padding-top: 16px; margin-top: 16px;">
|
||||||
<div style="display: flex; align-items: center; gap: 8px;">
|
<p style="margin: 0; color: #6b7280; font-size: 14px;">
|
||||||
<span style="background: #3b82f6; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;">📊</span>
|
💡 Use the "Trigger full sync" action to manually synchronize all servers with current ACL settings.
|
||||||
<span><strong>Total Syncs:</strong> {{ total_recent_syncs|default:0 }}</span>
|
</p>
|
||||||
</div>
|
|
||||||
<div style="display: flex; align-items: center; gap: 8px;">
|
|
||||||
<span style="background: #16a34a; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;">✅</span>
|
|
||||||
<span><strong>Successful:</strong> {{ successful_recent_syncs|default:0 }}</span>
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; align-items: center; gap: 8px;">
|
|
||||||
<span style="background: #dc2626; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;">❌</span>
|
|
||||||
<span><strong>Failed:</strong> {{ failed_recent_syncs|default:0 }}</span>
|
|
||||||
</div>
|
|
||||||
<div style="display: flex; align-items: center; gap: 8px;">
|
|
||||||
<span style="background: #f59e0b; color: white; padding: 4px 8px; border-radius: 4px; font-weight: bold;">⏳</span>
|
|
||||||
<span><strong>Running:</strong> {{ running_recent_syncs|default:0 }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="border-top: 1px solid #e5e7eb; padding-top: 16px;">
|
|
||||||
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px;">
|
|
||||||
<p style="margin: 0; color: #6b7280; font-size: 14px;">
|
|
||||||
💡 Use the "Trigger full sync" action to manually synchronize all servers with current ACL settings.
|
|
||||||
</p>
|
|
||||||
{% if sync_currently_running %}
|
|
||||||
<span style="color: #f59e0b; font-size: 14px; font-weight: bold;">
|
|
||||||
⚠️ Sync already running - wait for completion
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
Reference in New Issue
Block a user