django-cfg 1.2.15__py3-none-any.whl → 1.2.16__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/maintenance/README.md +305 -0
- django_cfg/apps/maintenance/__init__.py +27 -0
- django_cfg/apps/maintenance/admin/__init__.py +28 -0
- django_cfg/apps/maintenance/admin/deployments_admin.py +251 -0
- django_cfg/apps/maintenance/admin/events_admin.py +374 -0
- django_cfg/apps/maintenance/admin/monitoring_admin.py +215 -0
- django_cfg/apps/maintenance/admin/sites_admin.py +464 -0
- django_cfg/apps/maintenance/apps.py +105 -0
- django_cfg/apps/maintenance/management/__init__.py +0 -0
- django_cfg/apps/maintenance/management/commands/__init__.py +0 -0
- django_cfg/apps/maintenance/management/commands/maintenance.py +375 -0
- django_cfg/apps/maintenance/management/commands/sync_cloudflare.py +168 -0
- django_cfg/apps/maintenance/managers/__init__.py +20 -0
- django_cfg/apps/maintenance/managers/deployments.py +287 -0
- django_cfg/apps/maintenance/managers/events.py +374 -0
- django_cfg/apps/maintenance/managers/monitoring.py +301 -0
- django_cfg/apps/maintenance/managers/sites.py +335 -0
- django_cfg/apps/maintenance/migrations/0001_initial.py +939 -0
- django_cfg/apps/maintenance/migrations/__init__.py +0 -0
- django_cfg/apps/maintenance/models/__init__.py +27 -0
- django_cfg/apps/maintenance/models/cloudflare.py +316 -0
- django_cfg/apps/maintenance/models/maintenance.py +334 -0
- django_cfg/apps/maintenance/models/monitoring.py +393 -0
- django_cfg/apps/maintenance/models/sites.py +419 -0
- django_cfg/apps/maintenance/serializers/__init__.py +60 -0
- django_cfg/apps/maintenance/serializers/actions.py +310 -0
- django_cfg/apps/maintenance/serializers/base.py +44 -0
- django_cfg/apps/maintenance/serializers/deployments.py +209 -0
- django_cfg/apps/maintenance/serializers/events.py +210 -0
- django_cfg/apps/maintenance/serializers/monitoring.py +278 -0
- django_cfg/apps/maintenance/serializers/sites.py +213 -0
- django_cfg/apps/maintenance/services/README.md +168 -0
- django_cfg/apps/maintenance/services/__init__.py +21 -0
- django_cfg/apps/maintenance/services/cloudflare_client.py +441 -0
- django_cfg/apps/maintenance/services/dns_manager.py +497 -0
- django_cfg/apps/maintenance/services/maintenance_manager.py +504 -0
- django_cfg/apps/maintenance/services/site_sync.py +448 -0
- django_cfg/apps/maintenance/services/sync_command_service.py +330 -0
- django_cfg/apps/maintenance/services/worker_manager.py +264 -0
- django_cfg/apps/maintenance/signals.py +38 -0
- django_cfg/apps/maintenance/urls.py +36 -0
- django_cfg/apps/maintenance/views/__init__.py +18 -0
- django_cfg/apps/maintenance/views/base.py +61 -0
- django_cfg/apps/maintenance/views/deployments.py +175 -0
- django_cfg/apps/maintenance/views/events.py +204 -0
- django_cfg/apps/maintenance/views/monitoring.py +213 -0
- django_cfg/apps/maintenance/views/sites.py +338 -0
- django_cfg/apps/urls.py +5 -1
- django_cfg/core/config.py +34 -3
- django_cfg/core/generation.py +15 -10
- django_cfg/models/cloudflare.py +316 -0
- django_cfg/models/revolution.py +1 -1
- django_cfg/models/tasks.py +1 -1
- django_cfg/modules/base.py +12 -5
- django_cfg/modules/django_unfold/dashboard.py +16 -1
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/METADATA +2 -1
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/RECORD +61 -13
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/WHEEL +0 -0
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.2.15.dist-info → django_cfg-1.2.16.dist-info}/licenses/LICENSE +0 -0
django_cfg/__init__.py
CHANGED
@@ -0,0 +1,305 @@
|
|
1
|
+
# 🔧 Django-CFG Maintenance Application
|
2
|
+
|
3
|
+
**Multi-site maintenance mode management with Cloudflare integration**
|
4
|
+
|
5
|
+
## 🎯 Overview
|
6
|
+
|
7
|
+
The Django-CFG Maintenance application provides a comprehensive solution for managing maintenance mode across multiple Cloudflare sites with an ORM-like interface and zero-configuration setup.
|
8
|
+
|
9
|
+
### Key Features
|
10
|
+
|
11
|
+
- ✅ **Zero-Configuration Setup** - Just provide API token and domain
|
12
|
+
- ✅ **Multi-Site Management** - Manage hundreds of sites with ORM-like queries
|
13
|
+
- ✅ **Bulk Operations** - Enable/disable maintenance for multiple sites at once
|
14
|
+
- ✅ **External Monitoring** - Automatic maintenance triggers on health check failures
|
15
|
+
- ✅ **Rich Admin Interface** - Full Django admin integration with bulk actions
|
16
|
+
- ✅ **CLI Management** - Powerful management commands for automation
|
17
|
+
- ✅ **Audit Trail** - Complete logging and event tracking
|
18
|
+
|
19
|
+
## 🚀 Quick Start
|
20
|
+
|
21
|
+
### 1. Enable in Configuration
|
22
|
+
|
23
|
+
```python
|
24
|
+
# settings.py or your DjangoConfig
|
25
|
+
class MyProjectConfig(DjangoConfig):
|
26
|
+
project_name = "My Project"
|
27
|
+
enable_maintenance = True # Enable maintenance app
|
28
|
+
|
29
|
+
# Optional: Zero-config Cloudflare setup
|
30
|
+
# Set these environment variables:
|
31
|
+
# CLOUDFLARE_API_TOKEN=your_token
|
32
|
+
# CLOUDFLARE_DOMAIN=example.com
|
33
|
+
```
|
34
|
+
|
35
|
+
### 2. Run Migrations
|
36
|
+
|
37
|
+
```bash
|
38
|
+
python manage.py migrate
|
39
|
+
```
|
40
|
+
|
41
|
+
### 3. Basic Usage
|
42
|
+
|
43
|
+
#### ORM-like Interface
|
44
|
+
|
45
|
+
```python
|
46
|
+
from django_cfg.apps.maintenance.services import multi_site_manager
|
47
|
+
|
48
|
+
# Get sites for user
|
49
|
+
sites = multi_site_manager.sites(user)
|
50
|
+
|
51
|
+
# Enable maintenance for all production sites
|
52
|
+
await sites.production().enable_maintenance(
|
53
|
+
reason="Database migration",
|
54
|
+
message="We're upgrading our database. Back in 30 minutes!"
|
55
|
+
)
|
56
|
+
|
57
|
+
# Disable maintenance for specific project
|
58
|
+
await sites.filter(project='ecommerce').disable_maintenance()
|
59
|
+
|
60
|
+
# Complex filtering
|
61
|
+
critical_sites = sites.filter(
|
62
|
+
environment='production',
|
63
|
+
tags__contains='critical'
|
64
|
+
).exclude(project='legacy')
|
65
|
+
|
66
|
+
await critical_sites.enable_maintenance(reason="Security patch")
|
67
|
+
```
|
68
|
+
|
69
|
+
#### CLI Management
|
70
|
+
|
71
|
+
```bash
|
72
|
+
# Enable maintenance for all production sites
|
73
|
+
python manage.py maintenance enable --environment production --reason "Database upgrade"
|
74
|
+
|
75
|
+
# Disable maintenance for specific project
|
76
|
+
python manage.py maintenance disable --project myproject
|
77
|
+
|
78
|
+
# Check status of all sites
|
79
|
+
python manage.py maintenance status
|
80
|
+
|
81
|
+
# Discover new sites from Cloudflare
|
82
|
+
python manage.py maintenance discover --api-token your_token
|
83
|
+
```
|
84
|
+
|
85
|
+
#### Django Admin
|
86
|
+
|
87
|
+
- Navigate to `/admin/maintenance/`
|
88
|
+
- Use bulk actions to manage multiple sites
|
89
|
+
- View comprehensive dashboard with statistics
|
90
|
+
- Monitor maintenance events and logs
|
91
|
+
|
92
|
+
## 📊 Models
|
93
|
+
|
94
|
+
### CloudflareSite
|
95
|
+
Individual Cloudflare site configuration with maintenance capabilities.
|
96
|
+
|
97
|
+
### SiteGroup
|
98
|
+
Logical grouping of sites for bulk operations.
|
99
|
+
|
100
|
+
### MaintenanceEvent
|
101
|
+
Tracks maintenance events with full audit trail.
|
102
|
+
|
103
|
+
### MaintenanceLog
|
104
|
+
Detailed logging for maintenance operations.
|
105
|
+
|
106
|
+
### MonitoringTarget
|
107
|
+
External monitoring configuration for automatic triggers.
|
108
|
+
|
109
|
+
### CloudflareDeployment
|
110
|
+
Tracks Cloudflare Worker deployments with rollback support.
|
111
|
+
|
112
|
+
## 🔧 Services
|
113
|
+
|
114
|
+
### CloudflareService
|
115
|
+
Core Cloudflare API v4 integration with proper error handling and retries.
|
116
|
+
|
117
|
+
### CloudflareAutoSetup
|
118
|
+
Zero-configuration setup service that automatically discovers and configures Cloudflare resources.
|
119
|
+
|
120
|
+
### MultiSiteManager
|
121
|
+
ORM-like interface for multi-site management with bulk operations.
|
122
|
+
|
123
|
+
### MonitoringService
|
124
|
+
External health check monitoring with automatic maintenance triggers.
|
125
|
+
|
126
|
+
## 🎛️ Admin Interface
|
127
|
+
|
128
|
+
Rich Django admin interface with:
|
129
|
+
|
130
|
+
- **Site Dashboard** - Overview of all sites with statistics
|
131
|
+
- **Bulk Operations** - Enable/disable maintenance for multiple sites
|
132
|
+
- **Status Monitoring** - Real-time site status checks
|
133
|
+
- **Event Tracking** - Complete audit trail of maintenance events
|
134
|
+
- **Log Viewing** - Detailed operation logs with filtering
|
135
|
+
|
136
|
+
## 📱 Management Commands
|
137
|
+
|
138
|
+
### `maintenance`
|
139
|
+
|
140
|
+
Comprehensive CLI for maintenance management:
|
141
|
+
|
142
|
+
```bash
|
143
|
+
# Actions
|
144
|
+
python manage.py maintenance enable|disable|status|list|discover
|
145
|
+
|
146
|
+
# Filters
|
147
|
+
--domain example.com
|
148
|
+
--environment production|staging|development|testing
|
149
|
+
--project myproject
|
150
|
+
--tag critical
|
151
|
+
--owner username
|
152
|
+
|
153
|
+
# Options
|
154
|
+
--reason "Custom reason"
|
155
|
+
--message "Custom maintenance message"
|
156
|
+
--dry-run # Preview without executing
|
157
|
+
--force # Skip confirmation
|
158
|
+
--verbose # Detailed output
|
159
|
+
```
|
160
|
+
|
161
|
+
## 🔍 Monitoring
|
162
|
+
|
163
|
+
### External Health Checks
|
164
|
+
|
165
|
+
The monitoring system performs external health checks and automatically triggers maintenance mode when sites become unavailable:
|
166
|
+
|
167
|
+
```python
|
168
|
+
# Configure monitoring target
|
169
|
+
target = MonitoringTarget.objects.create(
|
170
|
+
site=site,
|
171
|
+
check_url=f"https://{site.domain}/health/",
|
172
|
+
check_interval=60, # seconds
|
173
|
+
failure_threshold=3,
|
174
|
+
recovery_threshold=2,
|
175
|
+
auto_enable_maintenance=True,
|
176
|
+
auto_disable_maintenance=True
|
177
|
+
)
|
178
|
+
```
|
179
|
+
|
180
|
+
### Health Check Results
|
181
|
+
|
182
|
+
All health check results are stored with detailed information:
|
183
|
+
- Response time
|
184
|
+
- Status code
|
185
|
+
- Error messages
|
186
|
+
- Success/failure tracking
|
187
|
+
|
188
|
+
## 🌐 Zero-Configuration Setup
|
189
|
+
|
190
|
+
The auto-setup service automatically configures:
|
191
|
+
|
192
|
+
1. **Zone Discovery** - Finds Zone ID from domain name
|
193
|
+
2. **Account Discovery** - Extracts Account ID from zone data
|
194
|
+
3. **SSL Configuration** - Sets appropriate SSL/TLS mode
|
195
|
+
4. **DNS Records** - Creates missing DNS records if needed
|
196
|
+
5. **Worker Deployment** - Deploys maintenance mode Worker
|
197
|
+
6. **Monitoring Setup** - Configures health checks
|
198
|
+
|
199
|
+
```python
|
200
|
+
from django_cfg.models.cloudflare import CloudflareConfig
|
201
|
+
from django_cfg.apps.maintenance.services import CloudflareAutoSetup
|
202
|
+
|
203
|
+
config = CloudflareConfig(
|
204
|
+
api_token="your_token",
|
205
|
+
domain="example.com"
|
206
|
+
)
|
207
|
+
|
208
|
+
setup = CloudflareAutoSetup(config)
|
209
|
+
result = await setup.setup_complete_infrastructure()
|
210
|
+
|
211
|
+
if result.success:
|
212
|
+
print(f"✅ Setup completed in {result.get_duration_seconds():.2f}s")
|
213
|
+
else:
|
214
|
+
print(f"❌ Setup failed: {result.error_message}")
|
215
|
+
```
|
216
|
+
|
217
|
+
## 🔐 Security
|
218
|
+
|
219
|
+
- **API Token Security** - Tokens stored securely with proper field types
|
220
|
+
- **User Permissions** - Site-level access control with owner/shared model
|
221
|
+
- **Audit Trail** - Complete logging of all maintenance operations
|
222
|
+
- **Input Validation** - Comprehensive validation using Pydantic v2
|
223
|
+
|
224
|
+
## 📈 Scalability
|
225
|
+
|
226
|
+
- **Bulk Operations** - Handle hundreds of sites simultaneously
|
227
|
+
- **Async Processing** - Non-blocking operations with proper error handling
|
228
|
+
- **Rate Limiting** - Respects Cloudflare API rate limits
|
229
|
+
- **Retry Logic** - Exponential backoff for failed operations
|
230
|
+
- **Connection Pooling** - Efficient HTTP connection management
|
231
|
+
|
232
|
+
## 🧪 Testing
|
233
|
+
|
234
|
+
```bash
|
235
|
+
# Run maintenance app tests
|
236
|
+
python manage.py test django_cfg.apps.maintenance
|
237
|
+
|
238
|
+
# Test with coverage
|
239
|
+
coverage run --source='.' manage.py test django_cfg.apps.maintenance
|
240
|
+
coverage report
|
241
|
+
```
|
242
|
+
|
243
|
+
## 📚 API Reference
|
244
|
+
|
245
|
+
### Multi-Site Manager
|
246
|
+
|
247
|
+
```python
|
248
|
+
from django_cfg.apps.maintenance.services import multi_site_manager
|
249
|
+
|
250
|
+
# Get sites queryset
|
251
|
+
sites = multi_site_manager.sites(user)
|
252
|
+
|
253
|
+
# Filtering methods
|
254
|
+
sites.production() # Production sites
|
255
|
+
sites.staging() # Staging sites
|
256
|
+
sites.active() # Active sites
|
257
|
+
sites.in_maintenance() # Sites in maintenance
|
258
|
+
sites.by_project('name') # Filter by project
|
259
|
+
sites.with_tag('tag') # Filter by tag
|
260
|
+
|
261
|
+
# Bulk operations
|
262
|
+
await sites.enable_maintenance(reason, message, user, dry_run)
|
263
|
+
await sites.disable_maintenance(user, dry_run)
|
264
|
+
await sites.check_status()
|
265
|
+
|
266
|
+
# Analysis
|
267
|
+
sites.get_environment_summary() # Count by environment
|
268
|
+
sites.get_status_summary() # Count by status
|
269
|
+
sites.get_project_summary() # Count by project
|
270
|
+
```
|
271
|
+
|
272
|
+
### Cloudflare Service
|
273
|
+
|
274
|
+
```python
|
275
|
+
from django_cfg.apps.maintenance.services import CloudflareService
|
276
|
+
|
277
|
+
async with CloudflareService(api_token) as cf:
|
278
|
+
# Zone management
|
279
|
+
zones = await cf.get_zones()
|
280
|
+
zone = await cf.get_zone_by_name('example.com')
|
281
|
+
|
282
|
+
# Worker management
|
283
|
+
result = await cf.deploy_worker(zone_id, worker_name, script_content)
|
284
|
+
success = await cf.delete_worker(zone_id, worker_name)
|
285
|
+
|
286
|
+
# DNS management
|
287
|
+
record_id = await cf.create_dns_record(zone_id, 'A', 'www', '192.0.2.1')
|
288
|
+
records = await cf.list_dns_records(zone_id)
|
289
|
+
|
290
|
+
# SSL management
|
291
|
+
settings = await cf.get_ssl_settings(zone_id)
|
292
|
+
success = await cf.update_ssl_setting(zone_id, 'flexible')
|
293
|
+
```
|
294
|
+
|
295
|
+
## 🤝 Contributing
|
296
|
+
|
297
|
+
1. Follow CRITICAL_REQUIREMENTS.md for code standards
|
298
|
+
2. Use proper type hints and Pydantic models
|
299
|
+
3. Add comprehensive tests for new features
|
300
|
+
4. Update documentation for API changes
|
301
|
+
5. Follow django-cfg patterns and conventions
|
302
|
+
|
303
|
+
## 📄 License
|
304
|
+
|
305
|
+
Part of django-cfg package. See main package license.
|
@@ -0,0 +1,27 @@
|
|
1
|
+
"""
|
2
|
+
Django-CFG Maintenance Application
|
3
|
+
|
4
|
+
Multi-site maintenance mode management with Cloudflare integration.
|
5
|
+
Provides zero-configuration setup and ORM-like interface for managing
|
6
|
+
maintenance mode across multiple sites.
|
7
|
+
|
8
|
+
Key Features:
|
9
|
+
- Zero-configuration Cloudflare setup
|
10
|
+
- Multi-site management with ORM-like queries
|
11
|
+
- External monitoring for automatic maintenance mode
|
12
|
+
- Rich Django admin interface
|
13
|
+
- Scheduled maintenance support
|
14
|
+
- Full audit trail and logging
|
15
|
+
|
16
|
+
Example Usage:
|
17
|
+
# Zero-config setup
|
18
|
+
CLOUDFLARE_API_TOKEN = "your_token"
|
19
|
+
CLOUDFLARE_DOMAIN = "example.com"
|
20
|
+
|
21
|
+
# Multi-site management
|
22
|
+
sites = multi_site_manager.sites(user)
|
23
|
+
await sites.production().enable_maintenance()
|
24
|
+
await sites.filter(project='client-a').disable_maintenance()
|
25
|
+
"""
|
26
|
+
|
27
|
+
default_app_config = 'django_cfg.apps.maintenance.apps.MaintenanceConfig'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
"""
|
2
|
+
Maintenance admin interfaces.
|
3
|
+
|
4
|
+
Rich Django admin interfaces for multi-site maintenance management.
|
5
|
+
Following django-cfg patterns with Unfold optimization.
|
6
|
+
"""
|
7
|
+
|
8
|
+
# Import all admin classes to register them
|
9
|
+
from .sites_admin import CloudflareSiteAdmin, SiteGroupAdmin
|
10
|
+
from .events_admin import MaintenanceEventAdmin, MaintenanceLogAdmin
|
11
|
+
from .monitoring_admin import MonitoringTargetAdmin
|
12
|
+
from .deployments_admin import CloudflareDeploymentAdmin
|
13
|
+
|
14
|
+
__all__ = [
|
15
|
+
# Site management
|
16
|
+
'CloudflareSiteAdmin',
|
17
|
+
'SiteGroupAdmin',
|
18
|
+
|
19
|
+
# Maintenance tracking
|
20
|
+
'MaintenanceEventAdmin',
|
21
|
+
'MaintenanceLogAdmin',
|
22
|
+
|
23
|
+
# Monitoring
|
24
|
+
'MonitoringTargetAdmin',
|
25
|
+
|
26
|
+
# Cloudflare integration
|
27
|
+
'CloudflareDeploymentAdmin',
|
28
|
+
]
|
@@ -0,0 +1,251 @@
|
|
1
|
+
"""
|
2
|
+
Deployments admin interfaces with Unfold optimization.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from django.contrib import admin
|
6
|
+
from django.utils.html import format_html
|
7
|
+
from django.urls import reverse
|
8
|
+
from django.utils.safestring import mark_safe
|
9
|
+
from django.db import models
|
10
|
+
from django.db.models import Count, Q
|
11
|
+
from django.contrib import messages
|
12
|
+
from django.shortcuts import redirect
|
13
|
+
from unfold.admin import ModelAdmin, TabularInline
|
14
|
+
from unfold.decorators import display, action
|
15
|
+
from unfold.enums import ActionVariant
|
16
|
+
from unfold.contrib.filters.admin import AutocompleteSelectFilter
|
17
|
+
from django_cfg import ImportExportModelAdmin, ExportMixin
|
18
|
+
|
19
|
+
from ..models import CloudflareDeployment
|
20
|
+
|
21
|
+
|
22
|
+
@admin.register(CloudflareDeployment)
|
23
|
+
class CloudflareDeploymentAdmin(ModelAdmin, ImportExportModelAdmin):
|
24
|
+
"""Admin for CloudflareDeployment with Unfold styling."""
|
25
|
+
|
26
|
+
list_display = [
|
27
|
+
"deployment_with_icon",
|
28
|
+
"site_link",
|
29
|
+
"deployment_type_badge",
|
30
|
+
"status_badge",
|
31
|
+
"worker_name_display",
|
32
|
+
"created_at_display",
|
33
|
+
"deployed_at_display"
|
34
|
+
]
|
35
|
+
list_display_links = ["deployment_with_icon"]
|
36
|
+
search_fields = ["site__name", "site__domain", "worker_name", "script_name"]
|
37
|
+
list_filter = [
|
38
|
+
"deployment_type",
|
39
|
+
"status",
|
40
|
+
"created_at",
|
41
|
+
"deployed_at",
|
42
|
+
("site", AutocompleteSelectFilter),
|
43
|
+
("maintenance_event", AutocompleteSelectFilter),
|
44
|
+
]
|
45
|
+
ordering = ["-created_at"]
|
46
|
+
readonly_fields = [
|
47
|
+
"deployed_at", "created_at"
|
48
|
+
]
|
49
|
+
|
50
|
+
fieldsets = (
|
51
|
+
("Deployment Information", {
|
52
|
+
"fields": ("site", "deployment_type", "maintenance_event")
|
53
|
+
}),
|
54
|
+
("Worker Configuration", {
|
55
|
+
"fields": ("worker_name", "script_name", "script_content"),
|
56
|
+
"classes": ("collapse",)
|
57
|
+
}),
|
58
|
+
("Cloudflare Details", {
|
59
|
+
"fields": ("worker_id", "script_id", "deployment_config"),
|
60
|
+
"classes": ("collapse",)
|
61
|
+
}),
|
62
|
+
("Status & Logs", {
|
63
|
+
"fields": ("status", "deployed_at", "deployment_logs"),
|
64
|
+
"classes": ("collapse",)
|
65
|
+
}),
|
66
|
+
("Timestamps", {
|
67
|
+
"fields": ("created_at", "updated_at"),
|
68
|
+
"classes": ("collapse",)
|
69
|
+
})
|
70
|
+
)
|
71
|
+
|
72
|
+
# Unfold actions
|
73
|
+
actions_detail = ["deploy_worker", "undeploy_worker", "view_logs"]
|
74
|
+
|
75
|
+
@display(description="Deployment", ordering="worker_name")
|
76
|
+
def deployment_with_icon(self, obj):
|
77
|
+
"""Display deployment with status icon."""
|
78
|
+
icons = {
|
79
|
+
'pending': '⏳',
|
80
|
+
'deploying': '🚀',
|
81
|
+
'deployed': '✅',
|
82
|
+
'failed': '❌',
|
83
|
+
'undeployed': '🗑️'
|
84
|
+
}
|
85
|
+
icon = icons.get(obj.status, '📦')
|
86
|
+
name = obj.worker_name or obj.script_name or f"Deployment #{obj.id}"
|
87
|
+
return format_html('{} {}', icon, name)
|
88
|
+
|
89
|
+
@display(description="Site")
|
90
|
+
def site_link(self, obj):
|
91
|
+
"""Display site with link."""
|
92
|
+
return format_html(
|
93
|
+
'<a href="{}" class="text-decoration-none">🌐 {}</a>',
|
94
|
+
reverse('admin:django_cfg_maintenance_cloudflaresite_change',
|
95
|
+
args=[obj.site.id]),
|
96
|
+
obj.site.name
|
97
|
+
)
|
98
|
+
|
99
|
+
@display(description="Type", ordering="deployment_type")
|
100
|
+
def deployment_type_badge(self, obj):
|
101
|
+
"""Display deployment type with colored badge."""
|
102
|
+
colors = {
|
103
|
+
'maintenance_page': 'warning',
|
104
|
+
'redirect': 'info',
|
105
|
+
'custom_worker': 'primary',
|
106
|
+
'error_page': 'danger'
|
107
|
+
}
|
108
|
+
color = colors.get(obj.deployment_type, 'secondary')
|
109
|
+
return format_html(
|
110
|
+
'<span class="badge badge-{}">{}</span>',
|
111
|
+
color, obj.get_deployment_type_display()
|
112
|
+
)
|
113
|
+
|
114
|
+
@display(description="Status", ordering="status")
|
115
|
+
def status_badge(self, obj):
|
116
|
+
"""Display status with colored badge."""
|
117
|
+
colors = {
|
118
|
+
'pending': 'secondary',
|
119
|
+
'deploying': 'info',
|
120
|
+
'deployed': 'success',
|
121
|
+
'failed': 'danger',
|
122
|
+
'undeployed': 'warning'
|
123
|
+
}
|
124
|
+
color = colors.get(obj.status, 'secondary')
|
125
|
+
return format_html(
|
126
|
+
'<span class="badge badge-{}">{}</span>',
|
127
|
+
color, obj.get_status_display()
|
128
|
+
)
|
129
|
+
|
130
|
+
@display(description="Worker")
|
131
|
+
def worker_name_display(self, obj):
|
132
|
+
"""Display worker name or script name."""
|
133
|
+
if obj.worker_name:
|
134
|
+
return obj.worker_name
|
135
|
+
elif obj.script_name:
|
136
|
+
return format_html('<em>{}</em>', obj.script_name)
|
137
|
+
else:
|
138
|
+
return format_html('<span class="text-muted">Auto-generated</span>')
|
139
|
+
|
140
|
+
@display(description="Created", ordering="created_at")
|
141
|
+
def created_at_display(self, obj):
|
142
|
+
"""Display creation time."""
|
143
|
+
return obj.created_at.strftime("%Y-%m-%d %H:%M")
|
144
|
+
|
145
|
+
@display(description="Deployed", ordering="deployed_at")
|
146
|
+
def deployed_at_display(self, obj):
|
147
|
+
"""Display deployment time."""
|
148
|
+
if not obj.deployed_at:
|
149
|
+
return format_html('<span class="text-muted">Not deployed</span>')
|
150
|
+
|
151
|
+
from django.utils import timezone
|
152
|
+
from datetime import timedelta
|
153
|
+
|
154
|
+
now = timezone.now()
|
155
|
+
diff = now - obj.deployed_at
|
156
|
+
|
157
|
+
if diff < timedelta(hours=1):
|
158
|
+
color = "success"
|
159
|
+
elif diff < timedelta(days=1):
|
160
|
+
color = "info"
|
161
|
+
else:
|
162
|
+
color = "secondary"
|
163
|
+
|
164
|
+
return format_html(
|
165
|
+
'<span class="text-{}">{}</span>',
|
166
|
+
color, obj.deployed_at.strftime("%Y-%m-%d %H:%M")
|
167
|
+
)
|
168
|
+
|
169
|
+
def get_queryset(self, request):
|
170
|
+
"""Optimize queryset."""
|
171
|
+
return super().get_queryset(request).select_related(
|
172
|
+
'site', 'maintenance_event'
|
173
|
+
)
|
174
|
+
|
175
|
+
@action(
|
176
|
+
description="🚀 Deploy Worker",
|
177
|
+
icon="rocket_launch",
|
178
|
+
variant=ActionVariant.SUCCESS
|
179
|
+
)
|
180
|
+
def deploy_worker(self, request, object_id):
|
181
|
+
"""Deploy Cloudflare Worker."""
|
182
|
+
try:
|
183
|
+
deployment = CloudflareDeployment.objects.get(id=object_id)
|
184
|
+
|
185
|
+
if deployment.status == 'deployed':
|
186
|
+
messages.warning(request, "Worker is already deployed")
|
187
|
+
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
188
|
+
|
189
|
+
# Deploy worker logic here (placeholder)
|
190
|
+
deployment.status = 'deploying'
|
191
|
+
deployment.save()
|
192
|
+
|
193
|
+
messages.success(
|
194
|
+
request,
|
195
|
+
f"Deployment started for {deployment.site.name}"
|
196
|
+
)
|
197
|
+
|
198
|
+
except Exception as e:
|
199
|
+
messages.error(request, f"Deployment failed: {str(e)}")
|
200
|
+
|
201
|
+
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
202
|
+
|
203
|
+
@action(
|
204
|
+
description="🗑️ Undeploy Worker",
|
205
|
+
icon="delete",
|
206
|
+
variant=ActionVariant.DANGER
|
207
|
+
)
|
208
|
+
def undeploy_worker(self, request, object_id):
|
209
|
+
"""Undeploy Cloudflare Worker."""
|
210
|
+
try:
|
211
|
+
deployment = CloudflareDeployment.objects.get(id=object_id)
|
212
|
+
|
213
|
+
if deployment.status != 'deployed':
|
214
|
+
messages.warning(request, "Worker is not currently deployed")
|
215
|
+
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
216
|
+
|
217
|
+
# Undeploy worker logic here (placeholder)
|
218
|
+
deployment.status = 'undeployed'
|
219
|
+
deployment.save()
|
220
|
+
|
221
|
+
messages.success(
|
222
|
+
request,
|
223
|
+
f"Worker undeployed for {deployment.site.name}"
|
224
|
+
)
|
225
|
+
|
226
|
+
except Exception as e:
|
227
|
+
messages.error(request, f"Undeployment failed: {str(e)}")
|
228
|
+
|
229
|
+
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|
230
|
+
|
231
|
+
@action(
|
232
|
+
description="📋 View Logs",
|
233
|
+
icon="description",
|
234
|
+
variant=ActionVariant.INFO
|
235
|
+
)
|
236
|
+
def view_logs(self, request, object_id):
|
237
|
+
"""View deployment logs."""
|
238
|
+
try:
|
239
|
+
deployment = CloudflareDeployment.objects.get(id=object_id)
|
240
|
+
|
241
|
+
# This would typically redirect to a logs view
|
242
|
+
# For now, just show a message
|
243
|
+
messages.info(
|
244
|
+
request,
|
245
|
+
f"Logs for deployment {deployment.id} would be displayed here"
|
246
|
+
)
|
247
|
+
|
248
|
+
except Exception as e:
|
249
|
+
messages.error(request, f"Failed to retrieve logs: {str(e)}")
|
250
|
+
|
251
|
+
return redirect(request.META.get('HTTP_REFERER', '/admin/'))
|