django-cfg 1.2.17__py3-none-any.whl → 1.2.18__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.
Files changed (81) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/models/__init__.py +68 -0
  3. django_cfg/apps/accounts/models/activity.py +34 -0
  4. django_cfg/apps/accounts/models/auth.py +50 -0
  5. django_cfg/apps/accounts/models/base.py +8 -0
  6. django_cfg/apps/accounts/models/choices.py +32 -0
  7. django_cfg/apps/accounts/models/integrations.py +75 -0
  8. django_cfg/apps/accounts/models/registration.py +52 -0
  9. django_cfg/apps/accounts/models/user.py +80 -0
  10. django_cfg/apps/maintenance/__init__.py +53 -24
  11. django_cfg/apps/maintenance/admin/__init__.py +7 -18
  12. django_cfg/apps/maintenance/admin/api_key_admin.py +185 -0
  13. django_cfg/apps/maintenance/admin/log_admin.py +156 -0
  14. django_cfg/apps/maintenance/admin/scheduled_admin.py +390 -0
  15. django_cfg/apps/maintenance/admin/site_admin.py +448 -0
  16. django_cfg/apps/maintenance/apps.py +9 -96
  17. django_cfg/apps/maintenance/management/commands/maintenance.py +193 -307
  18. django_cfg/apps/maintenance/management/commands/process_scheduled_maintenance.py +241 -0
  19. django_cfg/apps/maintenance/management/commands/sync_cloudflare.py +152 -111
  20. django_cfg/apps/maintenance/managers/__init__.py +7 -12
  21. django_cfg/apps/maintenance/managers/cloudflare_site_manager.py +192 -0
  22. django_cfg/apps/maintenance/managers/maintenance_log_manager.py +151 -0
  23. django_cfg/apps/maintenance/migrations/0001_initial.py +145 -705
  24. django_cfg/apps/maintenance/migrations/0002_cloudflaresite_maintenance_url.py +21 -0
  25. django_cfg/apps/maintenance/models/__init__.py +23 -21
  26. django_cfg/apps/maintenance/models/cloudflare_api_key.py +109 -0
  27. django_cfg/apps/maintenance/models/cloudflare_site.py +125 -0
  28. django_cfg/apps/maintenance/models/maintenance_log.py +131 -0
  29. django_cfg/apps/maintenance/models/scheduled_maintenance.py +307 -0
  30. django_cfg/apps/maintenance/services/__init__.py +37 -16
  31. django_cfg/apps/maintenance/services/bulk_operations_service.py +400 -0
  32. django_cfg/apps/maintenance/services/maintenance_service.py +230 -0
  33. django_cfg/apps/maintenance/services/scheduled_maintenance_service.py +381 -0
  34. django_cfg/apps/maintenance/services/site_sync_service.py +390 -0
  35. django_cfg/apps/maintenance/utils/__init__.py +12 -0
  36. django_cfg/apps/maintenance/utils/retry_utils.py +109 -0
  37. django_cfg/config.py +3 -0
  38. django_cfg/core/config.py +4 -6
  39. django_cfg/modules/django_unfold/dashboard.py +4 -5
  40. {django_cfg-1.2.17.dist-info → django_cfg-1.2.18.dist-info}/METADATA +52 -1
  41. {django_cfg-1.2.17.dist-info → django_cfg-1.2.18.dist-info}/RECORD +45 -55
  42. django_cfg/apps/maintenance/README.md +0 -305
  43. django_cfg/apps/maintenance/admin/deployments_admin.py +0 -251
  44. django_cfg/apps/maintenance/admin/events_admin.py +0 -374
  45. django_cfg/apps/maintenance/admin/monitoring_admin.py +0 -215
  46. django_cfg/apps/maintenance/admin/sites_admin.py +0 -464
  47. django_cfg/apps/maintenance/managers/deployments.py +0 -287
  48. django_cfg/apps/maintenance/managers/events.py +0 -374
  49. django_cfg/apps/maintenance/managers/monitoring.py +0 -301
  50. django_cfg/apps/maintenance/managers/sites.py +0 -335
  51. django_cfg/apps/maintenance/models/cloudflare.py +0 -316
  52. django_cfg/apps/maintenance/models/maintenance.py +0 -334
  53. django_cfg/apps/maintenance/models/monitoring.py +0 -393
  54. django_cfg/apps/maintenance/models/sites.py +0 -419
  55. django_cfg/apps/maintenance/serializers/__init__.py +0 -60
  56. django_cfg/apps/maintenance/serializers/actions.py +0 -310
  57. django_cfg/apps/maintenance/serializers/base.py +0 -44
  58. django_cfg/apps/maintenance/serializers/deployments.py +0 -209
  59. django_cfg/apps/maintenance/serializers/events.py +0 -210
  60. django_cfg/apps/maintenance/serializers/monitoring.py +0 -278
  61. django_cfg/apps/maintenance/serializers/sites.py +0 -213
  62. django_cfg/apps/maintenance/services/README.md +0 -168
  63. django_cfg/apps/maintenance/services/cloudflare_client.py +0 -441
  64. django_cfg/apps/maintenance/services/dns_manager.py +0 -497
  65. django_cfg/apps/maintenance/services/maintenance_manager.py +0 -504
  66. django_cfg/apps/maintenance/services/site_sync.py +0 -448
  67. django_cfg/apps/maintenance/services/sync_command_service.py +0 -330
  68. django_cfg/apps/maintenance/services/worker_manager.py +0 -264
  69. django_cfg/apps/maintenance/signals.py +0 -38
  70. django_cfg/apps/maintenance/urls.py +0 -36
  71. django_cfg/apps/maintenance/views/__init__.py +0 -18
  72. django_cfg/apps/maintenance/views/base.py +0 -61
  73. django_cfg/apps/maintenance/views/deployments.py +0 -175
  74. django_cfg/apps/maintenance/views/events.py +0 -204
  75. django_cfg/apps/maintenance/views/monitoring.py +0 -213
  76. django_cfg/apps/maintenance/views/sites.py +0 -338
  77. django_cfg/models/cloudflare.py +0 -316
  78. /django_cfg/apps/accounts/{models.py → __models.py} +0 -0
  79. {django_cfg-1.2.17.dist-info → django_cfg-1.2.18.dist-info}/WHEEL +0 -0
  80. {django_cfg-1.2.17.dist-info → django_cfg-1.2.18.dist-info}/entry_points.txt +0 -0
  81. {django_cfg-1.2.17.dist-info → django_cfg-1.2.18.dist-info}/licenses/LICENSE +0 -0
@@ -1,22 +1,18 @@
1
- # Generated by Django 5.2.6 on 2025-09-22 17:18
1
+ # Generated by Django 5.2.6 on 2025-09-23 07:44
2
2
 
3
+ import datetime
3
4
  import django.db.models.deletion
4
- import django.utils.timezone
5
- from django.conf import settings
6
5
  from django.db import migrations, models
7
6
 
8
7
 
9
8
  class Migration(migrations.Migration):
10
-
11
9
  initial = True
12
10
 
13
- dependencies = [
14
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15
- ]
11
+ dependencies = []
16
12
 
17
13
  operations = [
18
14
  migrations.CreateModel(
19
- name="CloudflareSite",
15
+ name="CloudflareApiKey",
20
16
  fields=[
21
17
  (
22
18
  "id",
@@ -27,157 +23,56 @@ class Migration(migrations.Migration):
27
23
  (
28
24
  "name",
29
25
  models.CharField(
30
- help_text="Friendly site name for identification", max_length=100
31
- ),
32
- ),
33
- (
34
- "domain",
35
- models.CharField(
36
- help_text="Domain name (e.g., example.com)", max_length=253, unique=True
26
+ help_text="Friendly name for this API key (e.g., 'Production', 'Staging')",
27
+ max_length=100,
37
28
  ),
38
29
  ),
39
30
  (
40
31
  "description",
41
- models.TextField(blank=True, help_text="Site description or notes"),
42
- ),
43
- (
44
- "zone_id",
45
- models.CharField(help_text="Cloudflare Zone ID", max_length=32, unique=True),
46
- ),
47
- ("account_id", models.CharField(help_text="Cloudflare Account ID", max_length=32)),
48
- (
49
- "api_token",
50
- models.CharField(
51
- help_text="Site-specific or account API token", max_length=200
52
- ),
53
- ),
54
- (
55
- "environment",
56
- models.CharField(
57
- choices=[
58
- ("production", "Production"),
59
- ("staging", "Staging"),
60
- ("development", "Development"),
61
- ("testing", "Testing"),
62
- ],
63
- default="production",
64
- help_text="Site environment type",
65
- max_length=20,
32
+ models.TextField(
33
+ blank=True, help_text="Optional description of what this key is used for"
66
34
  ),
67
35
  ),
36
+ ("api_token", models.CharField(help_text="Cloudflare API token", max_length=255)),
68
37
  (
69
- "project",
38
+ "account_id",
70
39
  models.CharField(
71
- blank=True, help_text="Project or client name", max_length=100
72
- ),
73
- ),
74
- (
75
- "tags",
76
- models.JSONField(
77
40
  blank=True,
78
- default=list,
79
- help_text="Custom tags for filtering and organization",
80
- ),
81
- ),
82
- (
83
- "current_status",
84
- models.CharField(
85
- choices=[
86
- ("active", "Active"),
87
- ("maintenance", "Under Maintenance"),
88
- ("offline", "Offline"),
89
- ("unknown", "Unknown"),
90
- ],
91
- default="unknown",
92
- help_text="Current operational status",
93
- max_length=20,
94
- ),
95
- ),
96
- (
97
- "maintenance_active",
98
- models.BooleanField(
99
- default=False, help_text="Whether maintenance mode is currently active"
100
- ),
101
- ),
102
- (
103
- "last_status_check",
104
- models.DateTimeField(
105
- blank=True, help_text="When status was last checked", null=True
106
- ),
107
- ),
108
- (
109
- "worker_name",
110
- models.CharField(
111
- default="maintenance-mode",
112
- help_text="Cloudflare Worker name for maintenance mode",
113
- max_length=100,
114
- ),
115
- ),
116
- (
117
- "maintenance_template",
118
- models.CharField(
119
- default="modern", help_text="Maintenance page template", max_length=50
41
+ help_text="Cloudflare Account ID (auto-discovered if empty)",
42
+ max_length=32,
120
43
  ),
121
44
  ),
122
45
  (
123
- "custom_maintenance_message",
124
- models.TextField(
125
- blank=True, help_text="Custom maintenance message for this site"
126
- ),
46
+ "is_active",
47
+ models.BooleanField(default=True, help_text="Whether this API key is active"),
127
48
  ),
128
49
  (
129
- "monitoring_enabled",
50
+ "is_default",
130
51
  models.BooleanField(
131
- default=True, help_text="Enable health monitoring for this site"
132
- ),
133
- ),
134
- (
135
- "health_check_url",
136
- models.URLField(
137
- blank=True, help_text="Custom health check URL (defaults to domain/health/)"
138
- ),
139
- ),
140
- (
141
- "check_interval",
142
- models.PositiveIntegerField(
143
- default=300, help_text="Health check interval in seconds"
52
+ default=False, help_text="Whether this is the default API key to use"
144
53
  ),
145
54
  ),
146
55
  ("created_at", models.DateTimeField(auto_now_add=True)),
147
56
  ("updated_at", models.DateTimeField(auto_now=True)),
148
57
  (
149
- "last_maintenance_at",
58
+ "last_used_at",
150
59
  models.DateTimeField(
151
- blank=True, help_text="When maintenance was last activated", null=True
152
- ),
153
- ),
154
- (
155
- "allowed_users",
156
- models.ManyToManyField(
157
- blank=True,
158
- help_text="Users with access to manage this site",
159
- related_name="accessible_sites",
160
- to=settings.AUTH_USER_MODEL,
161
- ),
162
- ),
163
- (
164
- "owner",
165
- models.ForeignKey(
166
- help_text="Site owner",
167
- on_delete=django.db.models.deletion.CASCADE,
168
- related_name="owned_sites",
169
- to=settings.AUTH_USER_MODEL,
60
+ blank=True, help_text="When this API key was last used", null=True
170
61
  ),
171
62
  ),
172
63
  ],
173
64
  options={
174
- "verbose_name": "Cloudflare Site",
175
- "verbose_name_plural": "Cloudflare Sites",
176
- "ordering": ["name"],
65
+ "verbose_name": "Cloudflare API Key",
66
+ "verbose_name_plural": "Cloudflare API Keys",
67
+ "ordering": ["-is_default", "name"],
68
+ "indexes": [
69
+ models.Index(fields=["is_active"], name="maintenance_is_acti_a3fc7a_idx"),
70
+ models.Index(fields=["is_default"], name="maintenance_is_defa_10fec0_idx"),
71
+ ],
177
72
  },
178
73
  ),
179
74
  migrations.CreateModel(
180
- name="MaintenanceEvent",
75
+ name="CloudflareSite",
181
76
  fields=[
182
77
  (
183
78
  "id",
@@ -186,146 +81,59 @@ class Migration(migrations.Migration):
186
81
  ),
187
82
  ),
188
83
  (
189
- "title",
190
- models.CharField(
191
- help_text="Human-readable maintenance event title", max_length=200
192
- ),
193
- ),
194
- (
195
- "description",
196
- models.TextField(
197
- blank=True, help_text="Detailed description of maintenance work"
198
- ),
199
- ),
200
- (
201
- "reason",
84
+ "name",
202
85
  models.CharField(
203
- choices=[
204
- ("manual", "Manual Activation"),
205
- ("server_down", "Server Unreachable"),
206
- ("high_error_rate", "High Error Rate"),
207
- ("database_issues", "Database Issues"),
208
- ("deployment", "Deployment"),
209
- ("security_update", "Security Update"),
210
- ("scheduled", "Scheduled Maintenance"),
211
- ("emergency", "Emergency Maintenance"),
212
- ],
213
- default="manual",
214
- help_text="Reason for maintenance activation",
215
- max_length=50,
86
+ help_text="Friendly site name for identification", max_length=100
216
87
  ),
217
88
  ),
218
89
  (
219
- "status",
90
+ "domain",
220
91
  models.CharField(
221
- choices=[
222
- ("scheduled", "Scheduled"),
223
- ("active", "Active"),
224
- ("completed", "Completed"),
225
- ("failed", "Failed"),
226
- ("cancelled", "Cancelled"),
227
- ],
228
- default="active",
229
- help_text="Current maintenance status",
230
- max_length=20,
231
- ),
232
- ),
233
- (
234
- "started_at",
235
- models.DateTimeField(
236
- default=django.utils.timezone.now, help_text="When maintenance was started"
92
+ help_text="Domain name (e.g., vamcar.com)", max_length=255, unique=True
237
93
  ),
238
94
  ),
239
95
  (
240
- "ended_at",
241
- models.DateTimeField(
242
- blank=True, help_text="When maintenance was completed", null=True
243
- ),
244
- ),
245
- (
246
- "estimated_duration",
247
- models.DurationField(
248
- blank=True, help_text="Estimated maintenance duration", null=True
249
- ),
96
+ "zone_id",
97
+ models.CharField(help_text="Cloudflare Zone ID", max_length=32, unique=True),
250
98
  ),
99
+ ("account_id", models.CharField(help_text="Cloudflare Account ID", max_length=32)),
251
100
  (
252
- "cloudflare_worker_deployed",
101
+ "maintenance_active",
253
102
  models.BooleanField(
254
- default=False, help_text="Whether Cloudflare Worker was deployed"
255
- ),
256
- ),
257
- (
258
- "cloudflare_deployment_id",
259
- models.CharField(
260
- blank=True, help_text="Cloudflare deployment identifier", max_length=100
103
+ default=False, help_text="Whether maintenance mode is currently active"
261
104
  ),
262
105
  ),
263
106
  (
264
- "worker_deployment_success",
107
+ "is_active",
265
108
  models.BooleanField(
266
- default=False, help_text="Whether Worker deployment was successful"
267
- ),
268
- ),
269
- (
270
- "affected_requests",
271
- models.PositiveIntegerField(
272
- default=0, help_text="Number of requests affected during maintenance"
273
- ),
274
- ),
275
- (
276
- "error_count_before",
277
- models.PositiveIntegerField(
278
- default=0, help_text="Error count before maintenance"
279
- ),
280
- ),
281
- (
282
- "error_count_during",
283
- models.PositiveIntegerField(
284
- default=0, help_text="Error count during maintenance"
109
+ default=True, help_text="Whether this site is active in our system"
285
110
  ),
286
111
  ),
287
112
  ("created_at", models.DateTimeField(auto_now_add=True)),
288
113
  ("updated_at", models.DateTimeField(auto_now=True)),
289
114
  (
290
- "completed_by",
291
- models.ForeignKey(
292
- blank=True,
293
- help_text="User who completed maintenance",
294
- null=True,
295
- on_delete=django.db.models.deletion.SET_NULL,
296
- related_name="completed_maintenance_events",
297
- to=settings.AUTH_USER_MODEL,
115
+ "last_maintenance_at",
116
+ models.DateTimeField(
117
+ blank=True, help_text="When maintenance was last activated", null=True
298
118
  ),
299
119
  ),
300
120
  (
301
- "initiated_by",
121
+ "api_key",
302
122
  models.ForeignKey(
303
- blank=True,
304
- help_text="User who initiated maintenance",
305
- null=True,
306
- on_delete=django.db.models.deletion.SET_NULL,
307
- related_name="initiated_maintenance_events",
308
- to=settings.AUTH_USER_MODEL,
309
- ),
310
- ),
311
- (
312
- "sites",
313
- models.ManyToManyField(
314
- blank=True,
315
- help_text="Sites affected by this maintenance event",
316
- related_name="maintenance_events",
317
- to="django_cfg_maintenance.cloudflaresite",
123
+ help_text="API key to use for this site",
124
+ on_delete=django.db.models.deletion.PROTECT,
125
+ to="maintenance.cloudflareapikey",
318
126
  ),
319
127
  ),
320
128
  ],
321
129
  options={
322
- "verbose_name": "Maintenance Event",
323
- "verbose_name_plural": "Maintenance Events",
324
- "ordering": ["-started_at"],
130
+ "verbose_name": "Cloudflare Site",
131
+ "verbose_name_plural": "Cloudflare Sites",
132
+ "ordering": ["name"],
325
133
  },
326
134
  ),
327
135
  migrations.CreateModel(
328
- name="CloudflareDeployment",
136
+ name="MaintenanceLog",
329
137
  fields=[
330
138
  (
331
139
  "id",
@@ -334,211 +142,71 @@ class Migration(migrations.Migration):
334
142
  ),
335
143
  ),
336
144
  (
337
- "deployment_type",
145
+ "action",
338
146
  models.CharField(
339
147
  choices=[
340
- ("worker", "Cloudflare Worker"),
341
- ("page_rule", "Page Rule"),
342
- ("dns_record", "DNS Record"),
343
- ("ssl_setting", "SSL Setting"),
344
- ("custom_error_page", "Custom Error Page"),
148
+ ("enable", "Enable Maintenance"),
149
+ ("disable", "Disable Maintenance"),
150
+ ("error", "Error"),
151
+ ("sync", "Sync from Cloudflare"),
345
152
  ],
346
- default="worker",
347
- help_text="Type of Cloudflare resource being deployed",
348
- max_length=50,
349
- ),
350
- ),
351
- (
352
- "resource_name",
353
- models.CharField(
354
- help_text="Name of the deployed resource (Worker name, Page Rule, etc.)",
355
- max_length=200,
356
- ),
357
- ),
358
- (
359
- "resource_id",
360
- models.CharField(
361
- blank=True,
362
- help_text="Cloudflare resource ID after deployment",
363
- max_length=100,
153
+ help_text="What action was performed",
154
+ max_length=20,
364
155
  ),
365
156
  ),
366
157
  (
367
158
  "status",
368
159
  models.CharField(
369
160
  choices=[
370
- ("pending", "Pending"),
371
- ("deploying", "Deploying"),
372
- ("deployed", "Deployed"),
161
+ ("success", "Success"),
373
162
  ("failed", "Failed"),
374
- ("rolled_back", "Rolled Back"),
163
+ ("pending", "Pending"),
375
164
  ],
376
- default="pending",
377
- help_text="Current deployment status",
165
+ help_text="Result of the operation",
378
166
  max_length=20,
379
167
  ),
380
168
  ),
381
169
  (
382
- "created_at",
383
- models.DateTimeField(
384
- auto_now_add=True, help_text="When deployment was initiated"
385
- ),
386
- ),
387
- (
388
- "deployed_at",
389
- models.DateTimeField(
390
- blank=True, help_text="When deployment completed successfully", null=True
391
- ),
392
- ),
393
- (
394
- "failed_at",
395
- models.DateTimeField(blank=True, help_text="When deployment failed", null=True),
396
- ),
397
- (
398
- "configuration",
399
- models.JSONField(
400
- default=dict,
401
- help_text="Deployment configuration (Worker script, Page Rule settings, etc.)",
402
- ),
403
- ),
404
- (
405
- "cloudflare_response",
406
- models.JSONField(
407
- blank=True, default=dict, help_text="Full response from Cloudflare API"
408
- ),
170
+ "reason",
171
+ models.TextField(blank=True, help_text="Why maintenance was enabled/disabled"),
409
172
  ),
410
173
  (
411
174
  "error_message",
412
- models.TextField(blank=True, help_text="Error message if deployment failed"),
175
+ models.TextField(blank=True, help_text="Error details if operation failed"),
413
176
  ),
414
177
  (
415
- "rollback_data",
178
+ "cloudflare_response",
416
179
  models.JSONField(
417
180
  blank=True,
418
- default=dict,
419
- help_text="Data needed for rollback (previous configuration, etc.)",
420
- ),
421
- ),
422
- (
423
- "previous_deployment",
424
- models.ForeignKey(
425
- blank=True,
426
- help_text="Previous deployment for rollback",
181
+ help_text="Full Cloudflare API response for debugging",
427
182
  null=True,
428
- on_delete=django.db.models.deletion.SET_NULL,
429
- related_name="rollback_deployments",
430
- to="django_cfg_maintenance.cloudflaredeployment",
431
- ),
432
- ),
433
- (
434
- "site",
435
- models.ForeignKey(
436
- help_text="Site this deployment belongs to",
437
- on_delete=django.db.models.deletion.CASCADE,
438
- related_name="deployments",
439
- to="django_cfg_maintenance.cloudflaresite",
440
- ),
441
- ),
442
- (
443
- "maintenance_event",
444
- models.ForeignKey(
445
- blank=True,
446
- help_text="Related maintenance event",
447
- null=True,
448
- on_delete=django.db.models.deletion.SET_NULL,
449
- related_name="cloudflare_deployments",
450
- to="django_cfg_maintenance.maintenanceevent",
451
- ),
452
- ),
453
- ],
454
- options={
455
- "verbose_name": "Cloudflare Deployment",
456
- "verbose_name_plural": "Cloudflare Deployments",
457
- "ordering": ["-created_at"],
458
- },
459
- ),
460
- migrations.CreateModel(
461
- name="MaintenanceLog",
462
- fields=[
463
- (
464
- "id",
465
- models.BigAutoField(
466
- auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
467
- ),
468
- ),
469
- (
470
- "level",
471
- models.CharField(
472
- choices=[
473
- ("debug", "Debug"),
474
- ("info", "Info"),
475
- ("warning", "Warning"),
476
- ("error", "Error"),
477
- ("critical", "Critical"),
478
- ],
479
- default="info",
480
- help_text="Log level",
481
- max_length=20,
482
- ),
483
- ),
484
- ("message", models.TextField(help_text="Log message")),
485
- (
486
- "details",
487
- models.JSONField(
488
- blank=True, default=dict, help_text="Additional log details (JSON)"
489
- ),
490
- ),
491
- (
492
- "component",
493
- models.CharField(
494
- blank=True,
495
- help_text="Component that generated the log (e.g., 'cloudflare', 'monitoring')",
496
- max_length=100,
497
- ),
498
- ),
499
- (
500
- "operation",
501
- models.CharField(
502
- blank=True,
503
- help_text="Operation being performed (e.g., 'deploy_worker', 'health_check')",
504
- max_length=100,
505
183
  ),
506
184
  ),
185
+ ("created_at", models.DateTimeField(auto_now_add=True)),
507
186
  (
508
- "timestamp",
509
- models.DateTimeField(
510
- default=django.utils.timezone.now,
511
- help_text="When the log entry was created",
187
+ "duration_seconds",
188
+ models.IntegerField(
189
+ blank=True, help_text="How long the operation took", null=True
512
190
  ),
513
191
  ),
514
192
  (
515
- "event",
193
+ "site",
516
194
  models.ForeignKey(
517
- help_text="Related maintenance event",
195
+ help_text="Site this log entry belongs to",
518
196
  on_delete=django.db.models.deletion.CASCADE,
519
197
  related_name="logs",
520
- to="django_cfg_maintenance.maintenanceevent",
521
- ),
522
- ),
523
- (
524
- "user",
525
- models.ForeignKey(
526
- blank=True,
527
- help_text="User associated with this log entry",
528
- null=True,
529
- on_delete=django.db.models.deletion.SET_NULL,
530
- to=settings.AUTH_USER_MODEL,
198
+ to="maintenance.cloudflaresite",
531
199
  ),
532
200
  ),
533
201
  ],
534
202
  options={
535
203
  "verbose_name": "Maintenance Log",
536
204
  "verbose_name_plural": "Maintenance Logs",
537
- "ordering": ["-timestamp"],
205
+ "ordering": ["-created_at"],
538
206
  },
539
207
  ),
540
208
  migrations.CreateModel(
541
- name="MonitoringTarget",
209
+ name="ScheduledMaintenance",
542
210
  fields=[
543
211
  (
544
212
  "id",
@@ -546,394 +214,166 @@ class Migration(migrations.Migration):
546
214
  auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
547
215
  ),
548
216
  ),
549
- ("check_url", models.URLField(help_text="URL to check for health status")),
550
- (
551
- "check_interval",
552
- models.PositiveIntegerField(default=60, help_text="Check interval in seconds"),
553
- ),
554
- (
555
- "timeout",
556
- models.PositiveIntegerField(default=10, help_text="Request timeout in seconds"),
557
- ),
217
+ ("title", models.CharField(help_text="Maintenance event title", max_length=200)),
558
218
  (
559
- "expected_status_codes",
560
- models.JSONField(
561
- default=list, help_text="Expected HTTP status codes (e.g., [200, 201])"
562
- ),
563
- ),
564
- (
565
- "expected_response_time_ms",
566
- models.PositiveIntegerField(
567
- blank=True,
568
- help_text="Maximum expected response time in milliseconds",
569
- null=True,
570
- ),
219
+ "description",
220
+ models.TextField(blank=True, help_text="Detailed description of maintenance"),
571
221
  ),
572
222
  (
573
- "expected_content",
574
- models.TextField(
575
- blank=True, help_text="Expected content in response body (substring match)"
576
- ),
223
+ "scheduled_start",
224
+ models.DateTimeField(help_text="When maintenance should start"),
577
225
  ),
578
226
  (
579
- "failure_threshold",
580
- models.PositiveIntegerField(
581
- default=3, help_text="Consecutive failures before triggering maintenance"
582
- ),
227
+ "estimated_duration",
228
+ models.DurationField(help_text="Expected duration of maintenance"),
583
229
  ),
584
230
  (
585
- "recovery_threshold",
586
- models.PositiveIntegerField(
587
- default=2, help_text="Consecutive successes before disabling maintenance"
588
- ),
231
+ "scheduled_end",
232
+ models.DateTimeField(editable=False, help_text="Auto-calculated end time"),
589
233
  ),
590
234
  (
591
235
  "status",
592
236
  models.CharField(
593
237
  choices=[
238
+ ("scheduled", "Scheduled"),
594
239
  ("active", "Active"),
595
- ("paused", "Paused"),
596
- ("disabled", "Disabled"),
597
- ("error", "Error"),
240
+ ("completed", "Completed"),
241
+ ("cancelled", "Cancelled"),
242
+ ("failed", "Failed"),
598
243
  ],
599
- default="active",
600
- help_text="Current monitoring status",
244
+ default="scheduled",
601
245
  max_length=20,
602
246
  ),
603
247
  ),
604
248
  (
605
- "consecutive_failures",
606
- models.PositiveIntegerField(
607
- default=0, help_text="Current consecutive failure count"
608
- ),
609
- ),
610
- (
611
- "consecutive_successes",
612
- models.PositiveIntegerField(
613
- default=0, help_text="Current consecutive success count"
614
- ),
615
- ),
616
- (
617
- "last_check_at",
618
- models.DateTimeField(
619
- blank=True, help_text="When last health check was performed", null=True
620
- ),
621
- ),
622
- (
623
- "last_check_success",
624
- models.BooleanField(
625
- default=True, help_text="Whether last check was successful"
249
+ "priority",
250
+ models.CharField(
251
+ choices=[
252
+ ("low", "Low"),
253
+ ("normal", "Normal"),
254
+ ("high", "High"),
255
+ ("critical", "Critical"),
256
+ ],
257
+ default="normal",
258
+ max_length=20,
626
259
  ),
627
260
  ),
261
+ ("actual_start", models.DateTimeField(blank=True, null=True)),
262
+ ("actual_end", models.DateTimeField(blank=True, null=True)),
628
263
  (
629
- "last_response_time_ms",
630
- models.PositiveIntegerField(
631
- blank=True,
632
- help_text="Response time of last check in milliseconds",
633
- null=True,
264
+ "maintenance_message",
265
+ models.TextField(
266
+ blank=True, help_text="Custom message to display during maintenance"
634
267
  ),
635
268
  ),
636
269
  (
637
- "auto_enable_maintenance",
638
- models.BooleanField(
639
- default=True,
640
- help_text="Automatically enable maintenance on failure threshold",
270
+ "template",
271
+ models.CharField(
272
+ choices=[
273
+ ("modern", "Modern"),
274
+ ("simple", "Simple"),
275
+ ("premium", "Premium"),
276
+ ("minimal", "Minimal"),
277
+ ],
278
+ default="modern",
279
+ help_text="Maintenance page template",
280
+ max_length=50,
641
281
  ),
642
282
  ),
643
283
  (
644
- "auto_disable_maintenance",
284
+ "auto_enable",
645
285
  models.BooleanField(
646
- default=True,
647
- help_text="Automatically disable maintenance on recovery threshold",
648
- ),
649
- ),
650
- (
651
- "maintenance_triggered_at",
652
- models.DateTimeField(
653
- blank=True, help_text="When maintenance was last auto-triggered", null=True
654
- ),
655
- ),
656
- (
657
- "user_agent",
658
- models.CharField(
659
- default="Django-CFG-Monitor/1.0",
660
- help_text="User agent for health checks",
661
- max_length=200,
286
+ default=True, help_text="Automatically enable maintenance at scheduled time"
662
287
  ),
663
288
  ),
664
289
  (
665
- "follow_redirects",
290
+ "auto_disable",
666
291
  models.BooleanField(
667
- default=True, help_text="Follow HTTP redirects during checks"
292
+ default=True, help_text="Automatically disable maintenance after duration"
668
293
  ),
669
294
  ),
670
295
  (
671
- "verify_ssl",
672
- models.BooleanField(default=True, help_text="Verify SSL certificates"),
673
- ),
674
- (
675
- "custom_headers",
676
- models.JSONField(
677
- blank=True,
678
- default=dict,
679
- help_text="Custom headers for health check requests",
296
+ "notify_before",
297
+ models.DurationField(
298
+ default=datetime.timedelta(seconds=3600),
299
+ help_text="Send notification before maintenance starts",
680
300
  ),
681
301
  ),
302
+ ("notify_on_start", models.BooleanField(default=True)),
303
+ ("notify_on_complete", models.BooleanField(default=True)),
682
304
  ("created_at", models.DateTimeField(auto_now_add=True)),
683
305
  ("updated_at", models.DateTimeField(auto_now=True)),
684
306
  (
685
- "site",
686
- models.OneToOneField(
687
- help_text="Site being monitored",
688
- on_delete=django.db.models.deletion.CASCADE,
689
- related_name="monitoring_target",
690
- to="django_cfg_maintenance.cloudflaresite",
691
- ),
692
- ),
693
- ],
694
- options={
695
- "verbose_name": "Monitoring Target",
696
- "verbose_name_plural": "Monitoring Targets",
697
- },
698
- ),
699
- migrations.CreateModel(
700
- name="HealthCheckResult",
701
- fields=[
702
- (
703
- "id",
704
- models.BigAutoField(
705
- auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
706
- ),
707
- ),
708
- (
709
- "timestamp",
710
- models.DateTimeField(
711
- default=django.utils.timezone.now, help_text="When the check was performed"
712
- ),
713
- ),
714
- ("success", models.BooleanField(help_text="Whether the check was successful")),
715
- (
716
- "status_code",
717
- models.PositiveIntegerField(
718
- blank=True, help_text="HTTP response status code", null=True
719
- ),
720
- ),
721
- (
722
- "response_time_ms",
723
- models.PositiveIntegerField(
724
- blank=True, help_text="Response time in milliseconds", null=True
725
- ),
726
- ),
727
- (
728
- "response_size_bytes",
729
- models.PositiveIntegerField(
730
- blank=True, help_text="Response size in bytes", null=True
731
- ),
732
- ),
733
- (
734
- "error_message",
735
- models.TextField(blank=True, help_text="Error message if check failed"),
736
- ),
737
- (
738
- "error_type",
307
+ "created_by",
739
308
  models.CharField(
740
- blank=True,
741
- help_text="Type of error (timeout, connection, etc.)",
742
- max_length=100,
743
- ),
744
- ),
745
- (
746
- "details",
747
- models.JSONField(
748
- blank=True,
749
- default=dict,
750
- help_text="Additional check details (headers, content, etc.)",
309
+ blank=True, help_text="Who created this maintenance", max_length=100
751
310
  ),
752
311
  ),
753
312
  (
754
- "target",
755
- models.ForeignKey(
756
- help_text="Monitoring target this result belongs to",
757
- on_delete=django.db.models.deletion.CASCADE,
758
- related_name="results",
759
- to="django_cfg_maintenance.monitoringtarget",
760
- ),
761
- ),
762
- ],
763
- options={
764
- "verbose_name": "Health Check Result",
765
- "verbose_name_plural": "Health Check Results",
766
- "ordering": ["-timestamp"],
767
- },
768
- ),
769
- migrations.CreateModel(
770
- name="SiteGroup",
771
- fields=[
772
- (
773
- "id",
774
- models.BigAutoField(
775
- auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
776
- ),
777
- ),
778
- ("name", models.CharField(help_text="Group name", max_length=100)),
779
- ("description", models.TextField(blank=True, help_text="Group description")),
780
- (
781
- "auto_maintenance_rules",
313
+ "execution_log",
782
314
  models.JSONField(
783
- blank=True,
784
- default=dict,
785
- help_text="Automatic maintenance rules for this group",
786
- ),
787
- ),
788
- (
789
- "notification_settings",
790
- models.JSONField(
791
- blank=True,
792
- default=dict,
793
- help_text="Notification preferences for group events",
794
- ),
795
- ),
796
- ("created_at", models.DateTimeField(auto_now_add=True)),
797
- ("updated_at", models.DateTimeField(auto_now=True)),
798
- (
799
- "owner",
800
- models.ForeignKey(
801
- help_text="Group owner",
802
- on_delete=django.db.models.deletion.CASCADE,
803
- to=settings.AUTH_USER_MODEL,
315
+ blank=True, default=dict, help_text="Log of execution steps and results"
804
316
  ),
805
317
  ),
806
318
  (
807
319
  "sites",
808
320
  models.ManyToManyField(
809
- help_text="Sites in this group",
810
- related_name="groups",
811
- to="django_cfg_maintenance.cloudflaresite",
321
+ help_text="Sites affected by this maintenance",
322
+ related_name="scheduled_maintenances",
323
+ to="maintenance.cloudflaresite",
812
324
  ),
813
325
  ),
814
326
  ],
815
327
  options={
816
- "verbose_name": "Site Group",
817
- "verbose_name_plural": "Site Groups",
818
- "ordering": ["name"],
328
+ "verbose_name": "Scheduled Maintenance",
329
+ "verbose_name_plural": "Scheduled Maintenances",
330
+ "ordering": ["scheduled_start"],
819
331
  },
820
332
  ),
821
333
  migrations.AddIndex(
822
334
  model_name="cloudflaresite",
823
- index=models.Index(
824
- fields=["owner", "environment"], name="django_cfg__owner_i_5d4060_idx"
825
- ),
335
+ index=models.Index(fields=["domain"], name="maintenance_domain_b9a739_idx"),
826
336
  ),
827
337
  migrations.AddIndex(
828
338
  model_name="cloudflaresite",
829
339
  index=models.Index(
830
- fields=["project", "environment"], name="django_cfg__project_9a07f1_idx"
340
+ fields=["maintenance_active"], name="maintenance_mainten_26f0c1_idx"
831
341
  ),
832
342
  ),
833
343
  migrations.AddIndex(
834
344
  model_name="cloudflaresite",
835
- index=models.Index(fields=["current_status"], name="django_cfg__current_fcca20_idx"),
836
- ),
837
- migrations.AddIndex(
838
- model_name="cloudflaresite",
839
- index=models.Index(
840
- fields=["maintenance_active"], name="django_cfg__mainten_0c725d_idx"
841
- ),
842
- ),
843
- migrations.AddIndex(
844
- model_name="cloudflaresite",
845
- index=models.Index(fields=["domain"], name="django_cfg__domain_179845_idx"),
846
- ),
847
- migrations.AddIndex(
848
- model_name="maintenanceevent",
849
- index=models.Index(
850
- fields=["status", "-started_at"], name="django_cfg__status_a7d5f3_idx"
851
- ),
852
- ),
853
- migrations.AddIndex(
854
- model_name="maintenanceevent",
855
- index=models.Index(
856
- fields=["reason", "-started_at"], name="django_cfg__reason_214648_idx"
857
- ),
858
- ),
859
- migrations.AddIndex(
860
- model_name="maintenanceevent",
861
- index=models.Index(
862
- fields=["initiated_by", "-started_at"], name="django_cfg__initiat_7ad0ad_idx"
863
- ),
864
- ),
865
- migrations.AddIndex(
866
- model_name="cloudflaredeployment",
867
- index=models.Index(
868
- fields=["site", "-created_at"], name="django_cfg__site_id_7414e8_idx"
869
- ),
870
- ),
871
- migrations.AddIndex(
872
- model_name="cloudflaredeployment",
873
- index=models.Index(
874
- fields=["status", "-created_at"], name="django_cfg__status_ee1f80_idx"
875
- ),
876
- ),
877
- migrations.AddIndex(
878
- model_name="cloudflaredeployment",
879
- index=models.Index(
880
- fields=["deployment_type", "-created_at"], name="django_cfg__deploym_bc24ff_idx"
881
- ),
882
- ),
883
- migrations.AddIndex(
884
- model_name="cloudflaredeployment",
885
- index=models.Index(fields=["resource_id"], name="django_cfg__resourc_fab8ca_idx"),
345
+ index=models.Index(fields=["is_active"], name="maintenance_is_acti_335998_idx"),
886
346
  ),
887
347
  migrations.AddIndex(
888
348
  model_name="maintenancelog",
889
349
  index=models.Index(
890
- fields=["event", "-timestamp"], name="django_cfg__event_i_b03d81_idx"
350
+ fields=["site", "-created_at"], name="maintenance_site_id_c57d8c_idx"
891
351
  ),
892
352
  ),
893
353
  migrations.AddIndex(
894
354
  model_name="maintenancelog",
895
- index=models.Index(fields=["level", "-timestamp"], name="django_cfg__level_b66e18_idx"),
896
- ),
897
- migrations.AddIndex(
898
- model_name="maintenancelog",
899
- index=models.Index(
900
- fields=["component", "-timestamp"], name="django_cfg__compone_35dbe4_idx"
901
- ),
902
- ),
903
- migrations.AddIndex(
904
- model_name="monitoringtarget",
905
355
  index=models.Index(
906
- fields=["status", "last_check_at"], name="django_cfg__status_e57085_idx"
356
+ fields=["action", "-created_at"], name="maintenance_action_1676f8_idx"
907
357
  ),
908
358
  ),
909
359
  migrations.AddIndex(
910
- model_name="monitoringtarget",
911
- index=models.Index(
912
- fields=["site", "-last_check_at"], name="django_cfg__site_id_37651c_idx"
913
- ),
914
- ),
915
- migrations.AddIndex(
916
- model_name="healthcheckresult",
360
+ model_name="maintenancelog",
917
361
  index=models.Index(
918
- fields=["target", "-timestamp"], name="django_cfg__target__1a3262_idx"
362
+ fields=["status", "-created_at"], name="maintenance_status_47eaad_idx"
919
363
  ),
920
364
  ),
921
365
  migrations.AddIndex(
922
- model_name="healthcheckresult",
366
+ model_name="scheduledmaintenance",
923
367
  index=models.Index(
924
- fields=["success", "-timestamp"], name="django_cfg__success_6181d8_idx"
368
+ fields=["status", "scheduled_start"], name="maintenance_status_77021b_idx"
925
369
  ),
926
370
  ),
927
371
  migrations.AddIndex(
928
- model_name="healthcheckresult",
929
- index=models.Index(fields=["-timestamp"], name="django_cfg__timesta_ba6784_idx"),
372
+ model_name="scheduledmaintenance",
373
+ index=models.Index(fields=["scheduled_start"], name="maintenance_schedul_7c49c4_idx"),
930
374
  ),
931
375
  migrations.AddIndex(
932
- model_name="sitegroup",
933
- index=models.Index(fields=["owner", "name"], name="django_cfg__owner_i_6ba808_idx"),
934
- ),
935
- migrations.AlterUniqueTogether(
936
- name="sitegroup",
937
- unique_together={("name", "owner")},
376
+ model_name="scheduledmaintenance",
377
+ index=models.Index(fields=["status"], name="maintenance_status_92c0e9_idx"),
938
378
  ),
939
379
  ]