django-cfg 1.4.113__py3-none-any.whl → 1.4.114__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.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/dashboard/serializers/__init__.py +10 -8
- django_cfg/apps/dashboard/serializers/django_q2.py +50 -0
- django_cfg/apps/dashboard/services/__init__.py +2 -2
- django_cfg/apps/dashboard/services/django_q2_service.py +159 -0
- django_cfg/apps/dashboard/services/system_health_service.py +39 -26
- django_cfg/apps/dashboard/urls.py +2 -2
- django_cfg/apps/dashboard/views/__init__.py +2 -2
- django_cfg/apps/dashboard/views/django_q2_views.py +79 -0
- django_cfg/apps/tasks/migrations/0002_delete_tasklog.py +16 -0
- django_cfg/core/base/config_model.py +15 -5
- django_cfg/core/builders/apps_builder.py +3 -3
- django_cfg/core/generation/data_generators/cache.py +28 -2
- django_cfg/core/generation/integration_generators/__init__.py +4 -3
- django_cfg/core/generation/integration_generators/django_q2.py +133 -0
- django_cfg/core/generation/orchestrator.py +7 -7
- django_cfg/models/__init__.py +3 -3
- django_cfg/models/django/__init__.py +3 -3
- django_cfg/models/django/django_q2.py +491 -0
- django_cfg/pyproject.toml +2 -2
- django_cfg/registry/core.py +3 -3
- django_cfg/static/frontend/admin.zip +0 -0
- {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/METADATA +3 -2
- {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/RECORD +27 -26
- django_cfg/apps/dashboard/serializers/crontab.py +0 -84
- django_cfg/apps/dashboard/services/crontab_service.py +0 -210
- django_cfg/apps/dashboard/views/crontab_views.py +0 -72
- django_cfg/core/generation/integration_generators/crontab.py +0 -64
- django_cfg/models/django/crontab.py +0 -303
- {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.113.dist-info → django_cfg-1.4.114.dist-info}/licenses/LICENSE +0 -0
django_cfg/pyproject.toml
CHANGED
|
@@ -4,13 +4,13 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "django-cfg"
|
|
7
|
-
version = "1.4.
|
|
7
|
+
version = "1.4.114"
|
|
8
8
|
description = "Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
keywords = [ "django", "configuration", "pydantic", "settings", "type-safety", "pydantic-settings", "django-environ", "startup-validation", "ide-autocomplete", "nextjs-admin", "react-admin", "websocket", "centrifugo", "real-time", "typescript-generation", "ai-agents", "enterprise-django", "django-settings", "type-safe-config", "modern-django",]
|
|
11
11
|
classifiers = [ "Development Status :: 4 - Beta", "Framework :: Django", "Framework :: Django :: 5.2", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Topic :: Internet :: WWW/HTTP", "Topic :: Internet :: WWW/HTTP :: Dynamic Content", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: System :: Systems Administration", "Typing :: Typed",]
|
|
12
12
|
requires-python = ">=3.12,<3.14"
|
|
13
|
-
dependencies = [ "pydantic>=2.11.0,<3.0", "pydantic[email]>=2.11.0,<3.0", "PyYAML>=6.0,<7.0", "click>=8.2.0,<9.0", "questionary>=2.1.0,<3.0", "rich>=14.0.0,<15.0", "cloudflare>=4.3.0,<5.0", "loguru>=0.7.0,<1.0", "colorlog>=6.9.0,<7.0", "cachetools>=5.3.0,<7.0", "toml>=0.10.2,<0.11.0", "ngrok>=1.5.1; python_version>='3.12'", "psycopg[binary,pool]>=3.2.0,<4.0", "dj-database-url>=3.0.0,<4.0", "whitenoise>=6.8.0,<7.0", "django-cors-headers>=4.7.0,<5.0", "django-
|
|
13
|
+
dependencies = [ "pydantic>=2.11.0,<3.0", "pydantic[email]>=2.11.0,<3.0", "PyYAML>=6.0,<7.0", "click>=8.2.0,<9.0", "questionary>=2.1.0,<3.0", "rich>=14.0.0,<15.0", "cloudflare>=4.3.0,<5.0", "loguru>=0.7.0,<1.0", "colorlog>=6.9.0,<7.0", "cachetools>=5.3.0,<7.0", "toml>=0.10.2,<0.11.0", "ngrok>=1.5.1; python_version>='3.12'", "psycopg[binary,pool]>=3.2.0,<4.0", "dj-database-url>=3.0.0,<4.0", "whitenoise>=6.8.0,<7.0", "django-cors-headers>=4.7.0,<5.0", "django-q2==1.8.0", "croniter>=6.0.0,<7.0", "djangorestframework>=3.16.0,<4.0", "djangorestframework-simplejwt>=5.5.0,<6.0", "djangorestframework-simplejwt[token-blacklist]>=5.5.0,<6.0", "drf-nested-routers>=0.94.0,<1.0", "django-filter>=25.0,<26.0", "django-ratelimit>=4.1.0,<5.0.0", "drf-spectacular>=0.28.0,<1.0", "drf-spectacular-sidecar>=2025.8.0,<2026.0", "django-json-widget>=2.0.0,<3.0", "django-import-export>=4.3.0,<5.0", "django-extensions>=4.1.0,<5.0", "django-constance>=4.3.0,<5.0", "django-unfold>=0.64.0,<1.0", "django-redis>=6.0.0,<7.0", "redis>=6.4.0,<7.0", "hiredis>=2.0.0,<4.0", "rearq>=0.2.0,<1.0", "setuptools>=75.0.0; python_version>='3.13'", "pyTelegramBotAPI>=4.28.0,<5.0", "coolname>=2.2.0,<3.0", "django-admin-rangefilter>=0.13.0,<1.0", "python-json-logger>=3.3.0,<4.0", "requests>=2.32.0,<3.0", "tiktoken>=0.11.0,<1.0", "openai>=1.107.0,<2.0", "twilio>=9.8.0,<10.0", "sendgrid>=6.12.0,<7.0", "beautifulsoup4>=4.13.0,<5.0", "lxml>=6.0.0,<7.0", "pgvector>=0.4.0,<1.0", "tenacity>=9.1.2,<10.0.0", "mypy (>=1.18.2,<2.0.0)", "django-tailwind[reload] (>=4.2.0,<5.0.0)", "jinja2 (>=3.1.6,<4.0.0)", "django-axes[ipware] (>=8.0.0,<9.0.0)", "pydantic-settings (>=2.11.0,<3.0.0)", "pytz>=2025.1", "httpx>=0.28.1,<1.0", "mistune>=3.1.4,<4.0",]
|
|
14
14
|
[[project.authors]]
|
|
15
15
|
name = "Django-CFG Team"
|
|
16
16
|
email = "info@djangocfg.com"
|
django_cfg/registry/core.py
CHANGED
|
@@ -38,9 +38,9 @@ CORE_REGISTRY = {
|
|
|
38
38
|
# Security - Django Crypto Fields
|
|
39
39
|
"CryptoFieldsConfig": ("django_cfg.models.django.crypto_fields", "CryptoFieldsConfig"),
|
|
40
40
|
|
|
41
|
-
# Scheduling - Django
|
|
42
|
-
"
|
|
43
|
-
"
|
|
41
|
+
# Scheduling - Django-Q2
|
|
42
|
+
"DjangoQ2Config": ("django_cfg.models.django.django_q2", "DjangoQ2Config"),
|
|
43
|
+
"DjangoQ2ScheduleConfig": ("django_cfg.models.django.django_q2", "DjangoQ2ScheduleConfig"),
|
|
44
44
|
|
|
45
45
|
# Limits models
|
|
46
46
|
"LimitsConfig": ("django_cfg.models.api.limits", "LimitsConfig"),
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: django-cfg
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.114
|
|
4
4
|
Summary: Modern Django framework with type-safe Pydantic v2 configuration, Next.js admin integration, real-time WebSockets, and 8 enterprise apps. Replace settings.py with validated models, 90% less code. Production-ready with AI agents, auto-generated TypeScript clients, and zero-config features.
|
|
5
5
|
Project-URL: Homepage, https://djangocfg.com
|
|
6
6
|
Project-URL: Documentation, https://djangocfg.com
|
|
@@ -34,16 +34,17 @@ Requires-Dist: click<9.0,>=8.2.0
|
|
|
34
34
|
Requires-Dist: cloudflare<5.0,>=4.3.0
|
|
35
35
|
Requires-Dist: colorlog<7.0,>=6.9.0
|
|
36
36
|
Requires-Dist: coolname<3.0,>=2.2.0
|
|
37
|
+
Requires-Dist: croniter<7.0,>=6.0.0
|
|
37
38
|
Requires-Dist: dj-database-url<4.0,>=3.0.0
|
|
38
39
|
Requires-Dist: django-admin-rangefilter<1.0,>=0.13.0
|
|
39
40
|
Requires-Dist: django-axes[ipware]<9.0.0,>=8.0.0
|
|
40
41
|
Requires-Dist: django-constance<5.0,>=4.3.0
|
|
41
42
|
Requires-Dist: django-cors-headers<5.0,>=4.7.0
|
|
42
|
-
Requires-Dist: django-crontab<1.0,>=0.7.1
|
|
43
43
|
Requires-Dist: django-extensions<5.0,>=4.1.0
|
|
44
44
|
Requires-Dist: django-filter<26.0,>=25.0
|
|
45
45
|
Requires-Dist: django-import-export<5.0,>=4.3.0
|
|
46
46
|
Requires-Dist: django-json-widget<3.0,>=2.0.0
|
|
47
|
+
Requires-Dist: django-q2==1.8.0
|
|
47
48
|
Requires-Dist: django-ratelimit<5.0.0,>=4.1.0
|
|
48
49
|
Requires-Dist: django-redis<7.0,>=6.0.0
|
|
49
50
|
Requires-Dist: django-tailwind[reload]<5.0.0,>=4.2.0
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
django_cfg/README.md,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
django_cfg/__init__.py,sha256=
|
|
2
|
+
django_cfg/__init__.py,sha256=MWuXwRHUZtVt1_3qryh_271FF5bBx2dxkXP91uVtiok,1621
|
|
3
3
|
django_cfg/apps.py,sha256=72m3uuvyqGiLx6gOfE-BD3P61jddCCERuBOYpxTX518,1605
|
|
4
4
|
django_cfg/config.py,sha256=xdwFE8bocOEnMjqDOwr1_M02oUgdaMG_2M6F_IuB9GQ,1351
|
|
5
5
|
django_cfg/apps/__init__.py,sha256=JtDmEYt1OcleWM2ZaeX0LKDnRQzPOavfaXBWG4ECB5Q,26
|
|
@@ -196,32 +196,32 @@ django_cfg/apps/centrifugo/views/testing_api.py,sha256=sNBmYoRD7VBXZmoHEw9BmPbDa
|
|
|
196
196
|
django_cfg/apps/dashboard/__init__.py,sha256=TirqQji7p39fA15jGBswWSt6ML2K1SP96Iq-7Sw7NFI,236
|
|
197
197
|
django_cfg/apps/dashboard/apps.py,sha256=OvB_C5qTq-QcLvvrRpbBxJPL-DCtA-pGVK8ir2y-hKk,508
|
|
198
198
|
django_cfg/apps/dashboard/permissions.py,sha256=LJGza0pjVfoR2rQjKYZWnkgGcyzSHr43RMYiCibrokQ,1360
|
|
199
|
-
django_cfg/apps/dashboard/urls.py,sha256=
|
|
200
|
-
django_cfg/apps/dashboard/serializers/__init__.py,sha256=
|
|
199
|
+
django_cfg/apps/dashboard/urls.py,sha256=4LYRy8AOVHD4e-E8K_KW4-nFpH21g-yEjYdL13Evr_E,1351
|
|
200
|
+
django_cfg/apps/dashboard/serializers/__init__.py,sha256=QB31m7FxYlm1TEMp1zMvm6QgXaMGbI7PwlPgfcZzlrs,1837
|
|
201
201
|
django_cfg/apps/dashboard/serializers/activity.py,sha256=eaimk1eI1-WPFa_b8oqF-xM5V6uoSBlS0mRR7TfMtrQ,1410
|
|
202
202
|
django_cfg/apps/dashboard/serializers/apizones.py,sha256=eeluzYPtrSXskpfFY2ykw3yM71BCr5_XoAomcU-zNqE,773
|
|
203
203
|
django_cfg/apps/dashboard/serializers/base.py,sha256=-PRmxV3eApf-JfFVjgiL8ka0b07m69crkIECX-EK4IY,526
|
|
204
204
|
django_cfg/apps/dashboard/serializers/charts.py,sha256=EPgIcQ2jPLp2-5IbVWyhP86p_puPU0TMxitFR3yPfDE,1425
|
|
205
205
|
django_cfg/apps/dashboard/serializers/commands.py,sha256=qiRcSMNz7J72TcSVZLYD-oZxEAN3hmt_MZx9kkxlp7o,1925
|
|
206
|
-
django_cfg/apps/dashboard/serializers/
|
|
206
|
+
django_cfg/apps/dashboard/serializers/django_q2.py,sha256=sSCxaP_xwwNlY58lI6LooJ6JwHeaUwltXZkX2wtvloM,1735
|
|
207
207
|
django_cfg/apps/dashboard/serializers/overview.py,sha256=ejFZV2l2GOTHLA8XQty8SayyXM-cL3VM2veY7YoMeWE,1373
|
|
208
208
|
django_cfg/apps/dashboard/serializers/statistics.py,sha256=DrT3eDdsqSaeCE3GJ_7_o5Tl_WVc2NwNJ43fm-kPu2A,1664
|
|
209
209
|
django_cfg/apps/dashboard/serializers/system.py,sha256=mDwqPVS2iBfyCcs4BcnT2_kZWRnbWCtLvoTievc7qkU,2093
|
|
210
|
-
django_cfg/apps/dashboard/services/__init__.py,sha256=
|
|
210
|
+
django_cfg/apps/dashboard/services/__init__.py,sha256=nDMZcwG036iLta9LsAGQ39W8NfvDC8vt6j8xlBLaQ2A,687
|
|
211
211
|
django_cfg/apps/dashboard/services/apizones_service.py,sha256=FVpdMgBzjTzK3G5zZb2ADKL8ZrjEmdclCRNOr4AdIGI,3955
|
|
212
212
|
django_cfg/apps/dashboard/services/charts_service.py,sha256=QP4nWghSvkqTX-9ndQmmzdEDIsxVewGZj8Oy27kLoOA,8848
|
|
213
213
|
django_cfg/apps/dashboard/services/commands_security.py,sha256=kFADVoYNbqb2DwzFfFBZ3Th2TdfL-1z2V-dnNXHU5Fw,7893
|
|
214
214
|
django_cfg/apps/dashboard/services/commands_service.py,sha256=OnvZBUv2GDUWq3JA3UVrHu-gMc2eJm0-MT_WTdM27uk,11644
|
|
215
|
-
django_cfg/apps/dashboard/services/
|
|
215
|
+
django_cfg/apps/dashboard/services/django_q2_service.py,sha256=BalFPJhEDWPYv1fugYe123GQOSh0Gpdt6imJkNyQA1w,5113
|
|
216
216
|
django_cfg/apps/dashboard/services/overview_service.py,sha256=Dl_y89_waG9onDC9PHGWx0ci7m3NOdrMoEKSdv3Fves,6382
|
|
217
217
|
django_cfg/apps/dashboard/services/statistics_service.py,sha256=cX20DB0VrjDLaaLCp8YQUcBw_N34VzZKqY4Ly2Qal0M,14023
|
|
218
|
-
django_cfg/apps/dashboard/services/system_health_service.py,sha256=
|
|
219
|
-
django_cfg/apps/dashboard/views/__init__.py,sha256=
|
|
218
|
+
django_cfg/apps/dashboard/services/system_health_service.py,sha256=oekgJva1T-WTMqrNnlKRvaVbJvPI2PtSfUAe4coGNlg,12695
|
|
219
|
+
django_cfg/apps/dashboard/views/__init__.py,sha256=caP9Gt_4e_1kORhRLmWd2TJbIMbf86peKSXnf6ltFwE,629
|
|
220
220
|
django_cfg/apps/dashboard/views/activity_views.py,sha256=UsGTnFABCJdZZID8kmG2J6grVRx18G9xSKfl7nKVz3w,2797
|
|
221
221
|
django_cfg/apps/dashboard/views/apizones_views.py,sha256=FtEEeNQD7aFBejmuTfdtjvRCLwCJyjD7AWDR1ouBo2k,2329
|
|
222
222
|
django_cfg/apps/dashboard/views/charts_views.py,sha256=XDV3lTfoP65UuW_HIgNnp_80k35DVcicXXPLzIB6neU,5514
|
|
223
223
|
django_cfg/apps/dashboard/views/commands_views.py,sha256=eJw3U4CtLUMZn2YdENr3HwhzHcqygo8HW92vjRg1sYQ,6099
|
|
224
|
-
django_cfg/apps/dashboard/views/
|
|
224
|
+
django_cfg/apps/dashboard/views/django_q2_views.py,sha256=oQcMNDffZc0zB0Er-s2vUIRW_49yqKeEbxsyo9r32_U,2222
|
|
225
225
|
django_cfg/apps/dashboard/views/overview_views.py,sha256=UZsGOUuZxYymziB0bPxBEfDaIHwFMGz6pCxNMLBRtsI,3680
|
|
226
226
|
django_cfg/apps/dashboard/views/statistics_views.py,sha256=CISWM8A5lkIqTK2dWifTBJD4RdFI9Hu-_RCFl3kMoiA,3511
|
|
227
227
|
django_cfg/apps/dashboard/views/system_views.py,sha256=PSEGZuHhexgBiKVOlrNlDV9_t2kEwS2arBT8h2KFxds,2459
|
|
@@ -509,6 +509,7 @@ django_cfg/apps/tasks/admin/task_log.py,sha256=H7gv8k7J_1rd31jmbMU6TKuDkzH_mx2be
|
|
|
509
509
|
django_cfg/apps/tasks/filters/__init__.py,sha256=9H6dh9ryI_zJ0_tPENjsSS2V3Mx8MMcWze8hyHokfhc,151
|
|
510
510
|
django_cfg/apps/tasks/filters/task_log.py,sha256=BY67R3jyzHR6XdhNty8gjGmLTC5VDTx2_tGeGODOJXE,4929
|
|
511
511
|
django_cfg/apps/tasks/migrations/0001_initial.py,sha256=dVbEPP7umgjsJsubxaTYsrDq7dvwv2xf6_K8hfju-lE,7367
|
|
512
|
+
django_cfg/apps/tasks/migrations/0002_delete_tasklog.py,sha256=HW1ovU2mwvUXPhrVFaRorJW-rC-SlBNT0qUg6hG6vPY,283
|
|
512
513
|
django_cfg/apps/tasks/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
513
514
|
django_cfg/apps/tasks/models/__init__.py,sha256=4tvTev7IYkcjBrll3eLUFLJCDNlyG9c_863qoe_Fzu0,72
|
|
514
515
|
django_cfg/apps/tasks/models/task_log.py,sha256=PxcQ7D3LNwQPy9IYLaBYL08buMHeakbmmXyr4Vgaqa0,7967
|
|
@@ -541,27 +542,27 @@ django_cfg/core/validation.py,sha256=QmwGlNDa0MFG2OUmgykIUAaEotT55YNh-wAWSVxOAos
|
|
|
541
542
|
django_cfg/core/backends/__init__.py,sha256=5Qfza7oKQ8_UIHOs4ibhYvwtgAjngUqLrlwjKl_q124,38
|
|
542
543
|
django_cfg/core/backends/smtp.py,sha256=kWkNMG7UwLsHcFYSKRgrk1HbP9mU1fxzWYnalHXqoL8,2308
|
|
543
544
|
django_cfg/core/base/__init__.py,sha256=Z3bZvxejxk4vvWqmqTBLUi9XJpo6A_5Bq4R0J8q81Y4,116
|
|
544
|
-
django_cfg/core/base/config_model.py,sha256=
|
|
545
|
+
django_cfg/core/base/config_model.py,sha256=fnmvjOs2fHTb8ifjFv0EsbVPFScG87ExikIqVAqpDZc,21810
|
|
545
546
|
django_cfg/core/builders/__init__.py,sha256=jkInI7_jbxcjitapohw6QmbJPpacnnID6V1JovqtOFM,282
|
|
546
|
-
django_cfg/core/builders/apps_builder.py,sha256=
|
|
547
|
+
django_cfg/core/builders/apps_builder.py,sha256=96o35vB7-eIzAv32bZ505H6lGmcxjqZmhUDsxbOQ4Ug,6675
|
|
547
548
|
django_cfg/core/builders/middleware_builder.py,sha256=OwqQRoJKYWlXsQNPFBfUvVMYdppUHCPw-UDczV_esYg,3101
|
|
548
549
|
django_cfg/core/builders/security_builder.py,sha256=W8Lk9eTMi3PuNK5qH-BIHegeE0cbvmuHKTumLcwOAh8,23961
|
|
549
550
|
django_cfg/core/environment/__init__.py,sha256=sMOIe9z1i51j8B1VGjpLHJMaeDsBfsgn1TmL03FIeNo,141
|
|
550
551
|
django_cfg/core/environment/detector.py,sha256=bI9k4fdK8Nbfl61ZcQ3yNbm3WlmK-L0xB-g-aXKUdhA,8923
|
|
551
552
|
django_cfg/core/generation/__init__.py,sha256=0cYgeQ5EDN6sscQuFnXsFCy6m1BKgv_izNz0a1TlYSc,1355
|
|
552
553
|
django_cfg/core/generation/generation.py,sha256=uLLJnJ_9kq8zV_auySK05dXwZB-BJx920mID0Pm4RCo,2524
|
|
553
|
-
django_cfg/core/generation/orchestrator.py,sha256=
|
|
554
|
+
django_cfg/core/generation/orchestrator.py,sha256=GdR5HBjuDE4Rxzj8q6_mm24XbIJd7cORncHGYgCCwkI,12046
|
|
554
555
|
django_cfg/core/generation/protocols.py,sha256=9pqGsZD_Y5v3jdYp4YdkL-i--8feuvX_iKXxV-Cc4Bg,676
|
|
555
556
|
django_cfg/core/generation/core_generators/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
556
557
|
django_cfg/core/generation/core_generators/settings.py,sha256=Rto9qjqQC-MeQJMNyoflS91RrNDS_lBNH4d4ZtgER-8,2632
|
|
557
558
|
django_cfg/core/generation/core_generators/static.py,sha256=7xo7F9DSbz5Gk2Di-SbBo0petNMX4ZKfS8wuQCe9lz8,2747
|
|
558
559
|
django_cfg/core/generation/core_generators/templates.py,sha256=XeGKzF790_zKwFdRw3FN-VHCEgw6Q1dWPX7C1tNas1s,4885
|
|
559
560
|
django_cfg/core/generation/data_generators/__init__.py,sha256=O7cmt_k34hWRgrdaAzCRPudcaowaOwMgaoXmZY8HG54,298
|
|
560
|
-
django_cfg/core/generation/data_generators/cache.py,sha256=
|
|
561
|
+
django_cfg/core/generation/data_generators/cache.py,sha256=UvBmkmiUMPTaA5PDuOdMH1RgpvUz7xvX7jlWe4GUCsg,4920
|
|
561
562
|
django_cfg/core/generation/data_generators/database.py,sha256=mYR2mBvqWU93YP9XUUVlcZaQJtSNeAQ7Dk4Vj6Tu95k,3481
|
|
562
|
-
django_cfg/core/generation/integration_generators/__init__.py,sha256=
|
|
563
|
+
django_cfg/core/generation/integration_generators/__init__.py,sha256=wPPiVQnmCEXKigp-d_jKznU2i1M6aP4P2YOVYipuMDk,737
|
|
563
564
|
django_cfg/core/generation/integration_generators/api.py,sha256=Xsyu3mYyq9mje8QGNSU0Yp4tLbtF0ckq4lEf_Rj5pLc,11062
|
|
564
|
-
django_cfg/core/generation/integration_generators/
|
|
565
|
+
django_cfg/core/generation/integration_generators/django_q2.py,sha256=ZRIApW0lQWHOizd9jvFBSckk_O-bhrgr7rCnKg7M8U0,4155
|
|
565
566
|
django_cfg/core/generation/integration_generators/sessions.py,sha256=GbRC72Gny4dzj7oTIrbuhYyvhCQBoWI-0GxB8ZHTrEU,1644
|
|
566
567
|
django_cfg/core/generation/integration_generators/tailwind.py,sha256=YgiV5c-l0DDJnMKx6mWcUtH5zyMdewAJXjLDwmHrSuc,1208
|
|
567
568
|
django_cfg/core/generation/integration_generators/tasks.py,sha256=fMbuIdjRenuZQ6rfco7imLzDbCdX4WEO1aLslBpxjTQ,2253
|
|
@@ -624,7 +625,7 @@ django_cfg/middleware/user_activity.py,sha256=bgftHXXeGBS-jCa8mLzTx4Gcz2fHTaQz_n
|
|
|
624
625
|
django_cfg/mixins/__init__.py,sha256=1IErIlF4QWqt9VLFD8yoTiGWHobsDjLL6rqcEqMLbw4,211
|
|
625
626
|
django_cfg/mixins/admin_api.py,sha256=3GRfAty6YXGbZp4ZFsNFt1Gs_e5T4xBOLnRPoc5vaq0,1116
|
|
626
627
|
django_cfg/mixins/client_api.py,sha256=KeGK_f2xR08l0ckGpMmXHHpVLDQ7SnSbZn4WP5bSsvI,1200
|
|
627
|
-
django_cfg/models/__init__.py,sha256=
|
|
628
|
+
django_cfg/models/__init__.py,sha256=H11Jdcv5CaKMq6ylk8o3s7Orc6Yr8wQJ6lL1n7EMiZI,2883
|
|
628
629
|
django_cfg/models/api/__init__.py,sha256=VWkiYs38A7Tx5ZWePeBxL1lMiXKsonb5TQfoVRRCBac,605
|
|
629
630
|
django_cfg/models/api/config.py,sha256=KzaDn2Ubc7SpZ_8xt6-Q-XxnZbf9Glu1xJhJWbAI--o,4455
|
|
630
631
|
django_cfg/models/api/cors.py,sha256=kRDGD-HcCK39QhoyvKnn2yGcwzGFp2QIw50G7TNx78I,3467
|
|
@@ -639,11 +640,11 @@ django_cfg/models/api/drf/swagger.py,sha256=ku_eE7bWgHxjXD6Z2sEKSYE-bIzmZfAR0vQW
|
|
|
639
640
|
django_cfg/models/base/__init__.py,sha256=f6sMVyd-YEFdLebmIKOOPviu1Ovn4BHGp7j7ZVNqFDo,271
|
|
640
641
|
django_cfg/models/base/config.py,sha256=hfpf35yMR8oOE1J0SBPNNSBwXckK3F2-Iv0Vw6cNX4E,10114
|
|
641
642
|
django_cfg/models/base/module.py,sha256=nxN1Y9J4l94kOfSXLQJ2eGgIGWTq8kyh7hUGvCQNyIs,2674
|
|
642
|
-
django_cfg/models/django/__init__.py,sha256=
|
|
643
|
+
django_cfg/models/django/__init__.py,sha256=J4VRl77vgXzfKcdUcX-sPxpBSOJ4qA-8RstPgJ5ChmA,511
|
|
643
644
|
django_cfg/models/django/axes.py,sha256=-4nk2gSfpj7lNY5vnm_2jHVLz8VAKoEd9yF2TuCR8O8,5624
|
|
644
645
|
django_cfg/models/django/constance.py,sha256=6x57bi40mDX0fKcKeQKgV2BO3WIVYPQllAchWsj4KvM,8847
|
|
645
|
-
django_cfg/models/django/crontab.py,sha256=HoD3CRhE3Lfo_pnKdm32pgeEz7J4MiJqI6WuOpR03G0,8816
|
|
646
646
|
django_cfg/models/django/crypto_fields.py,sha256=OguITidM4Mp564p_gbsokeNCZxjL9hrK1Vw0McuA3yo,4700
|
|
647
|
+
django_cfg/models/django/django_q2.py,sha256=9i-ogZJ24YZJ9Xf0CoLs_tvg9FkYhrZoOd4KurDwYnY,14378
|
|
647
648
|
django_cfg/models/django/environment.py,sha256=lBCHBs1lphv9tlu1BCTfLZeH_kUame0p66A_BIjBY7M,9440
|
|
648
649
|
django_cfg/models/django/openapi.py,sha256=avE3iapaCj8eyOqVUum_v2EExR3V-hwHrexqtXMHtTQ,3739
|
|
649
650
|
django_cfg/models/django/revolution_legacy.py,sha256=Z4SPUS7QSv62EuPAeFFoXGEgqLmdXnVEr7Ofk1IDtVc,8918
|
|
@@ -1001,7 +1002,7 @@ django_cfg/modules/nextjs_admin/models/config.py,sha256=75iM81aaTlDQdhfvdlCzj6o9
|
|
|
1001
1002
|
django_cfg/modules/nextjs_admin/templatetags/__init__.py,sha256=ChVBnJggCIY8rMhfyJFoA8k0qKo-8FtJknrk54Vx4wM,51
|
|
1002
1003
|
django_cfg/modules/nextjs_admin/templatetags/nextjs_admin.py,sha256=aAekrlu3pvvx3I4uJGT3S2ie8QfF94umDBjgAF71EII,4483
|
|
1003
1004
|
django_cfg/registry/__init__.py,sha256=CaiL9KwqPzXlIe5-4Qr7PQu5ZxAW1HtuDIXZ7-ktRQg,538
|
|
1004
|
-
django_cfg/registry/core.py,sha256=
|
|
1005
|
+
django_cfg/registry/core.py,sha256=LqqmWwaOo-0KivPD61yolBwxxigvKARZflOv6rLAcHM,3546
|
|
1005
1006
|
django_cfg/registry/exceptions.py,sha256=b4pIakeRxhT1-ST3lbAnmAQaASRBARCoah_w6vb3VF0,399
|
|
1006
1007
|
django_cfg/registry/modules.py,sha256=DC9veh6DdnqOa_KPNwDhnxvvNKRNF0Um2isHn1XGoxU,1915
|
|
1007
1008
|
django_cfg/registry/services.py,sha256=l0V2twGpF9BwVlo-TTfFu8dV7GVBS7XKCsScIZXWWbc,2457
|
|
@@ -1024,7 +1025,7 @@ django_cfg/static/admin/js/alpine/commands-section.js,sha256=8z2MQNwZF9Tx_2EK1AY
|
|
|
1024
1025
|
django_cfg/static/admin/js/alpine/dashboard-tabs.js,sha256=ob8Q_I9lFLDv_hFERXgTyvqMDBspAGfzCxI_7slRur4,1354
|
|
1025
1026
|
django_cfg/static/admin/js/alpine/system-metrics.js,sha256=m-Fg55K_vpHXToD46PXL9twl4OBF_V9MONvbSWbQqDw,440
|
|
1026
1027
|
django_cfg/static/admin/js/alpine/toggle-section.js,sha256=T141NFmy0fRJyGGuuaCJRjJXwPam-xxtQNW1hi8BJbc,672
|
|
1027
|
-
django_cfg/static/frontend/admin.zip,sha256=
|
|
1028
|
+
django_cfg/static/frontend/admin.zip,sha256=3ezv0j07V1jtVJA3wjxwr1T6Z4XoA3xRhRIFOAZCOm8,7647333
|
|
1028
1029
|
django_cfg/static/js/api-loader.mjs,sha256=boGqqRGnFR-Mzo_RQOjhAzNvsb7QxZddSwMKROzkk9Q,5163
|
|
1029
1030
|
django_cfg/static/js/api/base.mjs,sha256=KUxZHHdELAV8mNnACpwJRvaQhdJxp-n5LFEQ4oUZxBo,4707
|
|
1030
1031
|
django_cfg/static/js/api/index.mjs,sha256=_-Q04jjHcgwi4CGfiaLyiOR6NW7Yu1HBhJWp2J1cjpc,2538
|
|
@@ -1059,9 +1060,9 @@ django_cfg/utils/version_check.py,sha256=WO51J2m2e-wVqWCRwbultEwu3q1lQasV67Mw2aa
|
|
|
1059
1060
|
django_cfg/CHANGELOG.md,sha256=jtT3EprqEJkqSUh7IraP73vQ8PmKUMdRtznQsEnqDZk,2052
|
|
1060
1061
|
django_cfg/CONTRIBUTING.md,sha256=DU2kyQ6PU0Z24ob7O_OqKWEYHcZmJDgzw-lQCmu6uBg,3041
|
|
1061
1062
|
django_cfg/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
|
|
1062
|
-
django_cfg/pyproject.toml,sha256=
|
|
1063
|
-
django_cfg-1.4.
|
|
1064
|
-
django_cfg-1.4.
|
|
1065
|
-
django_cfg-1.4.
|
|
1066
|
-
django_cfg-1.4.
|
|
1067
|
-
django_cfg-1.4.
|
|
1063
|
+
django_cfg/pyproject.toml,sha256=kAwzl-dSNGJtDEsF7j8PufTqwQrVq1eMy4zCLm9zf_M,8681
|
|
1064
|
+
django_cfg-1.4.114.dist-info/METADATA,sha256=a8yk0DiKdgIIOHcPGyVpXxyPVvv-El4ju0Hp1t_55Qw,23904
|
|
1065
|
+
django_cfg-1.4.114.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
1066
|
+
django_cfg-1.4.114.dist-info/entry_points.txt,sha256=Ucmde4Z2wEzgb4AggxxZ0zaYDb9HpyE5blM3uJ0_VNg,56
|
|
1067
|
+
django_cfg-1.4.114.dist-info/licenses/LICENSE,sha256=xHuytiUkSZCRG3N11nk1X6q1_EGQtv6aL5O9cqNRhKE,1071
|
|
1068
|
+
django_cfg-1.4.114.dist-info/RECORD,,
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Crontab Serializers
|
|
3
|
-
|
|
4
|
-
Serializers for crontab monitoring endpoints.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from rest_framework import serializers
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class CrontabJobSerializer(serializers.Serializer):
|
|
11
|
-
"""
|
|
12
|
-
Serializer for individual cron job configuration.
|
|
13
|
-
|
|
14
|
-
Maps to CrontabJobConfig Pydantic model.
|
|
15
|
-
"""
|
|
16
|
-
|
|
17
|
-
name = serializers.CharField(help_text="Job identifier name")
|
|
18
|
-
job_type = serializers.ChoiceField(
|
|
19
|
-
choices=['command', 'callable'],
|
|
20
|
-
help_text="Job type: Django command or Python callable"
|
|
21
|
-
)
|
|
22
|
-
command = serializers.CharField(
|
|
23
|
-
required=False,
|
|
24
|
-
allow_null=True,
|
|
25
|
-
help_text="Management command name (for command type jobs)"
|
|
26
|
-
)
|
|
27
|
-
callable_path = serializers.CharField(
|
|
28
|
-
required=False,
|
|
29
|
-
allow_null=True,
|
|
30
|
-
help_text="Python callable path (for callable type jobs)"
|
|
31
|
-
)
|
|
32
|
-
command_args = serializers.ListField(
|
|
33
|
-
child=serializers.CharField(),
|
|
34
|
-
required=False,
|
|
35
|
-
help_text="Command positional arguments"
|
|
36
|
-
)
|
|
37
|
-
command_kwargs = serializers.DictField(
|
|
38
|
-
required=False,
|
|
39
|
-
help_text="Command keyword arguments"
|
|
40
|
-
)
|
|
41
|
-
minute = serializers.CharField(help_text="Cron minute field")
|
|
42
|
-
hour = serializers.CharField(help_text="Cron hour field")
|
|
43
|
-
day_of_month = serializers.CharField(help_text="Cron day of month field")
|
|
44
|
-
month_of_year = serializers.CharField(help_text="Cron month field")
|
|
45
|
-
day_of_week = serializers.CharField(help_text="Cron day of week field")
|
|
46
|
-
enabled = serializers.BooleanField(help_text="Whether job is enabled")
|
|
47
|
-
comment = serializers.CharField(
|
|
48
|
-
required=False,
|
|
49
|
-
allow_null=True,
|
|
50
|
-
help_text="Optional job description"
|
|
51
|
-
)
|
|
52
|
-
schedule_display = serializers.CharField(
|
|
53
|
-
required=False,
|
|
54
|
-
help_text="Human-readable schedule description"
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class CrontabJobsSerializer(serializers.Serializer):
|
|
59
|
-
"""Serializer for list of all cron jobs."""
|
|
60
|
-
|
|
61
|
-
enabled = serializers.BooleanField(help_text="Whether crontab is enabled")
|
|
62
|
-
jobs_count = serializers.IntegerField(help_text="Total number of jobs")
|
|
63
|
-
enabled_jobs_count = serializers.IntegerField(help_text="Number of enabled jobs")
|
|
64
|
-
jobs = CrontabJobSerializer(many=True, help_text="List of all cron jobs")
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class CrontabStatusSerializer(serializers.Serializer):
|
|
68
|
-
"""Serializer for crontab configuration status."""
|
|
69
|
-
|
|
70
|
-
enabled = serializers.BooleanField(help_text="Whether crontab is enabled")
|
|
71
|
-
jobs_count = serializers.IntegerField(help_text="Total number of jobs")
|
|
72
|
-
enabled_jobs_count = serializers.IntegerField(help_text="Number of enabled jobs")
|
|
73
|
-
lock_jobs = serializers.BooleanField(help_text="Whether job locking is enabled")
|
|
74
|
-
command_prefix = serializers.CharField(
|
|
75
|
-
required=False,
|
|
76
|
-
allow_null=True,
|
|
77
|
-
help_text="Command prefix for all jobs"
|
|
78
|
-
)
|
|
79
|
-
comment = serializers.CharField(
|
|
80
|
-
required=False,
|
|
81
|
-
allow_null=True,
|
|
82
|
-
help_text="Crontab configuration comment"
|
|
83
|
-
)
|
|
84
|
-
timestamp = serializers.CharField(help_text="Status check timestamp (ISO format)")
|
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Crontab Service
|
|
3
|
-
|
|
4
|
-
Business logic for crontab/scheduled jobs monitoring and information.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import logging
|
|
8
|
-
from datetime import datetime
|
|
9
|
-
from typing import Any, Dict, List
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class CrontabService:
|
|
15
|
-
"""
|
|
16
|
-
Service for crontab monitoring and information.
|
|
17
|
-
|
|
18
|
-
%%PRIORITY:HIGH%%
|
|
19
|
-
%%AI_HINT: Provides information about scheduled cron jobs%%
|
|
20
|
-
|
|
21
|
-
TAGS: crontab, scheduling, monitoring, service
|
|
22
|
-
DEPENDS_ON: [django_cfg.core.config]
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def __init__(self):
|
|
26
|
-
"""Initialize crontab service."""
|
|
27
|
-
self.logger = logger
|
|
28
|
-
|
|
29
|
-
def _get_schedule_display(self, job) -> str:
|
|
30
|
-
"""
|
|
31
|
-
Generate human-readable schedule description.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
job: CrontabJobConfig instance
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
Human-readable schedule string
|
|
38
|
-
"""
|
|
39
|
-
parts = []
|
|
40
|
-
|
|
41
|
-
# Minute
|
|
42
|
-
if job.minute == "*":
|
|
43
|
-
parts.append("every minute")
|
|
44
|
-
elif job.minute.startswith("*/"):
|
|
45
|
-
interval = job.minute[2:]
|
|
46
|
-
parts.append(f"every {interval} minutes")
|
|
47
|
-
else:
|
|
48
|
-
parts.append(f"at minute {job.minute}")
|
|
49
|
-
|
|
50
|
-
# Hour
|
|
51
|
-
if job.hour == "*":
|
|
52
|
-
parts.append("of every hour")
|
|
53
|
-
elif job.hour.startswith("*/"):
|
|
54
|
-
interval = job.hour[2:]
|
|
55
|
-
parts.append(f"every {interval} hours")
|
|
56
|
-
else:
|
|
57
|
-
parts.append(f"at {job.hour}:00")
|
|
58
|
-
|
|
59
|
-
# Day of month
|
|
60
|
-
if job.day_of_month != "*":
|
|
61
|
-
parts.append(f"on day {job.day_of_month}")
|
|
62
|
-
|
|
63
|
-
# Month
|
|
64
|
-
if job.month_of_year != "*":
|
|
65
|
-
months = {
|
|
66
|
-
"1": "January", "2": "February", "3": "March", "4": "April",
|
|
67
|
-
"5": "May", "6": "June", "7": "July", "8": "August",
|
|
68
|
-
"9": "September", "10": "October", "11": "November", "12": "December"
|
|
69
|
-
}
|
|
70
|
-
month_name = months.get(job.month_of_year, job.month_of_year)
|
|
71
|
-
parts.append(f"in {month_name}")
|
|
72
|
-
|
|
73
|
-
# Day of week
|
|
74
|
-
if job.day_of_week != "*":
|
|
75
|
-
days = {
|
|
76
|
-
"0": "Sunday", "1": "Monday", "2": "Tuesday", "3": "Wednesday",
|
|
77
|
-
"4": "Thursday", "5": "Friday", "6": "Saturday"
|
|
78
|
-
}
|
|
79
|
-
if "-" in job.day_of_week:
|
|
80
|
-
parts.append(f"on weekdays ({job.day_of_week})")
|
|
81
|
-
else:
|
|
82
|
-
day_name = days.get(job.day_of_week, job.day_of_week)
|
|
83
|
-
parts.append(f"on {day_name}")
|
|
84
|
-
|
|
85
|
-
return " ".join(parts)
|
|
86
|
-
|
|
87
|
-
def _format_job(self, job) -> Dict[str, Any]:
|
|
88
|
-
"""
|
|
89
|
-
Format a single job for API response.
|
|
90
|
-
|
|
91
|
-
Args:
|
|
92
|
-
job: CrontabJobConfig instance
|
|
93
|
-
|
|
94
|
-
Returns:
|
|
95
|
-
Formatted job dictionary
|
|
96
|
-
"""
|
|
97
|
-
job_data = {
|
|
98
|
-
'name': job.name,
|
|
99
|
-
'job_type': job.job_type,
|
|
100
|
-
'minute': job.minute,
|
|
101
|
-
'hour': job.hour,
|
|
102
|
-
'day_of_month': job.day_of_month,
|
|
103
|
-
'month_of_year': job.month_of_year,
|
|
104
|
-
'day_of_week': job.day_of_week,
|
|
105
|
-
'enabled': job.enabled,
|
|
106
|
-
'schedule_display': self._get_schedule_display(job),
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
# Add command or callable info
|
|
110
|
-
if job.job_type == 'command':
|
|
111
|
-
job_data['command'] = job.command
|
|
112
|
-
if job.command_args:
|
|
113
|
-
job_data['command_args'] = job.command_args
|
|
114
|
-
if job.command_kwargs:
|
|
115
|
-
job_data['command_kwargs'] = job.command_kwargs
|
|
116
|
-
else:
|
|
117
|
-
job_data['callable_path'] = job.callable_path
|
|
118
|
-
|
|
119
|
-
# Add comment if present
|
|
120
|
-
if job.comment:
|
|
121
|
-
job_data['comment'] = job.comment
|
|
122
|
-
|
|
123
|
-
return job_data
|
|
124
|
-
|
|
125
|
-
def get_all_jobs(self) -> Dict[str, Any]:
|
|
126
|
-
"""
|
|
127
|
-
Get all configured cron jobs.
|
|
128
|
-
|
|
129
|
-
Returns:
|
|
130
|
-
Dictionary with jobs list and summary
|
|
131
|
-
|
|
132
|
-
USED_BY: CrontabViewSet.jobs endpoint
|
|
133
|
-
"""
|
|
134
|
-
try:
|
|
135
|
-
from django_cfg.core.config import get_current_config
|
|
136
|
-
|
|
137
|
-
config = get_current_config()
|
|
138
|
-
|
|
139
|
-
# Check if crontab is configured
|
|
140
|
-
if not hasattr(config, 'crontab') or not config.crontab:
|
|
141
|
-
return {
|
|
142
|
-
'enabled': False,
|
|
143
|
-
'jobs_count': 0,
|
|
144
|
-
'enabled_jobs_count': 0,
|
|
145
|
-
'jobs': []
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
crontab_config = config.crontab
|
|
149
|
-
|
|
150
|
-
# Format all jobs
|
|
151
|
-
jobs = [self._format_job(job) for job in crontab_config.jobs]
|
|
152
|
-
|
|
153
|
-
# Count enabled jobs
|
|
154
|
-
enabled_jobs_count = sum(1 for job in crontab_config.jobs if job.enabled)
|
|
155
|
-
|
|
156
|
-
return {
|
|
157
|
-
'enabled': crontab_config.enabled,
|
|
158
|
-
'jobs_count': len(jobs),
|
|
159
|
-
'enabled_jobs_count': enabled_jobs_count,
|
|
160
|
-
'jobs': jobs
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
except Exception as e:
|
|
164
|
-
self.logger.error(f"Failed to get cron jobs: {e}", exc_info=True)
|
|
165
|
-
raise
|
|
166
|
-
|
|
167
|
-
def get_status(self) -> Dict[str, Any]:
|
|
168
|
-
"""
|
|
169
|
-
Get crontab configuration status and summary.
|
|
170
|
-
|
|
171
|
-
Returns:
|
|
172
|
-
Dictionary with crontab configuration status
|
|
173
|
-
|
|
174
|
-
USED_BY: CrontabViewSet.crontab_status endpoint
|
|
175
|
-
"""
|
|
176
|
-
try:
|
|
177
|
-
from django_cfg.core.config import get_current_config
|
|
178
|
-
|
|
179
|
-
config = get_current_config()
|
|
180
|
-
|
|
181
|
-
# Check if crontab is configured
|
|
182
|
-
if not hasattr(config, 'crontab') or not config.crontab:
|
|
183
|
-
return {
|
|
184
|
-
'enabled': False,
|
|
185
|
-
'jobs_count': 0,
|
|
186
|
-
'enabled_jobs_count': 0,
|
|
187
|
-
'lock_jobs': False,
|
|
188
|
-
'command_prefix': None,
|
|
189
|
-
'comment': None,
|
|
190
|
-
'timestamp': datetime.now().isoformat(),
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
crontab_config = config.crontab
|
|
194
|
-
|
|
195
|
-
# Count enabled jobs
|
|
196
|
-
enabled_jobs_count = sum(1 for job in crontab_config.jobs if job.enabled)
|
|
197
|
-
|
|
198
|
-
return {
|
|
199
|
-
'enabled': crontab_config.enabled,
|
|
200
|
-
'jobs_count': len(crontab_config.jobs),
|
|
201
|
-
'enabled_jobs_count': enabled_jobs_count,
|
|
202
|
-
'lock_jobs': crontab_config.lock_jobs,
|
|
203
|
-
'command_prefix': crontab_config.command_prefix,
|
|
204
|
-
'comment': crontab_config.comment,
|
|
205
|
-
'timestamp': datetime.now().isoformat(),
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
except Exception as e:
|
|
209
|
-
self.logger.error(f"Failed to get crontab status: {e}", exc_info=True)
|
|
210
|
-
raise
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Crontab ViewSet
|
|
3
|
-
|
|
4
|
-
Endpoints for cron job monitoring:
|
|
5
|
-
- GET /crontab/jobs/ - List all configured cron jobs
|
|
6
|
-
- GET /crontab/status/ - Crontab configuration status
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import logging
|
|
10
|
-
|
|
11
|
-
from drf_spectacular.utils import extend_schema
|
|
12
|
-
from rest_framework import status, viewsets
|
|
13
|
-
|
|
14
|
-
from django_cfg.mixins import AdminAPIMixin
|
|
15
|
-
from rest_framework.decorators import action
|
|
16
|
-
from rest_framework.response import Response
|
|
17
|
-
|
|
18
|
-
from ..services import CrontabService
|
|
19
|
-
from ..serializers import CrontabJobsSerializer, CrontabStatusSerializer
|
|
20
|
-
|
|
21
|
-
logger = logging.getLogger(__name__)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class CrontabViewSet(AdminAPIMixin, viewsets.GenericViewSet):
|
|
25
|
-
"""
|
|
26
|
-
Crontab Monitoring ViewSet
|
|
27
|
-
|
|
28
|
-
Provides endpoints for monitoring scheduled cron jobs.
|
|
29
|
-
Requires admin authentication (JWT, Session, or Basic Auth).
|
|
30
|
-
"""
|
|
31
|
-
|
|
32
|
-
serializer_class = CrontabJobsSerializer
|
|
33
|
-
|
|
34
|
-
@extend_schema(
|
|
35
|
-
summary="Get all cron jobs",
|
|
36
|
-
description="Retrieve list of all configured cron jobs with schedules and details",
|
|
37
|
-
responses={200: CrontabJobsSerializer},
|
|
38
|
-
tags=["Dashboard - Crontab"]
|
|
39
|
-
)
|
|
40
|
-
@action(detail=False, methods=['get'], url_path='jobs', serializer_class=CrontabJobsSerializer)
|
|
41
|
-
def jobs(self, request):
|
|
42
|
-
"""Get all configured cron jobs."""
|
|
43
|
-
try:
|
|
44
|
-
crontab_service = CrontabService()
|
|
45
|
-
jobs_data = crontab_service.get_all_jobs()
|
|
46
|
-
return Response(jobs_data)
|
|
47
|
-
|
|
48
|
-
except Exception as e:
|
|
49
|
-
logger.error(f"Crontab jobs API error: {e}", exc_info=True)
|
|
50
|
-
return Response({
|
|
51
|
-
'error': str(e)
|
|
52
|
-
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
53
|
-
|
|
54
|
-
@extend_schema(
|
|
55
|
-
summary="Get crontab status",
|
|
56
|
-
description="Retrieve crontab configuration status and summary",
|
|
57
|
-
responses={200: CrontabStatusSerializer},
|
|
58
|
-
tags=["Dashboard - Crontab"]
|
|
59
|
-
)
|
|
60
|
-
@action(detail=False, methods=['get'], url_path='status', serializer_class=CrontabStatusSerializer)
|
|
61
|
-
def crontab_status(self, request):
|
|
62
|
-
"""Get crontab configuration status."""
|
|
63
|
-
try:
|
|
64
|
-
crontab_service = CrontabService()
|
|
65
|
-
status_data = crontab_service.get_status()
|
|
66
|
-
return Response(status_data)
|
|
67
|
-
|
|
68
|
-
except Exception as e:
|
|
69
|
-
logger.error(f"Crontab status API error: {e}", exc_info=True)
|
|
70
|
-
return Response({
|
|
71
|
-
'error': str(e)
|
|
72
|
-
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Crontab settings generator for django-cfg.
|
|
3
|
-
|
|
4
|
-
Generates django-crontab settings and handles INSTALLED_APPS integration.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from typing import TYPE_CHECKING, Any, Dict
|
|
8
|
-
|
|
9
|
-
from django_cfg.modules.django_logging import logger
|
|
10
|
-
|
|
11
|
-
if TYPE_CHECKING:
|
|
12
|
-
from django_cfg.models.django.crontab import CrontabConfig
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class CrontabSettingsGenerator:
|
|
16
|
-
"""
|
|
17
|
-
Generates crontab scheduling settings for django-crontab.
|
|
18
|
-
|
|
19
|
-
Automatically:
|
|
20
|
-
- Generates CRONJOBS configuration
|
|
21
|
-
- Adds django_crontab to INSTALLED_APPS if enabled
|
|
22
|
-
- Configures lock files and command prefixes
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def __init__(self, config: "CrontabConfig"):
|
|
26
|
-
"""
|
|
27
|
-
Initialize with crontab configuration.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
config: CrontabConfig instance
|
|
31
|
-
"""
|
|
32
|
-
self.config = config
|
|
33
|
-
|
|
34
|
-
def generate(self) -> Dict[str, Any]:
|
|
35
|
-
"""
|
|
36
|
-
Generate crontab settings.
|
|
37
|
-
|
|
38
|
-
Returns:
|
|
39
|
-
Dictionary with crontab configuration
|
|
40
|
-
"""
|
|
41
|
-
if not self.config or not self.config.enabled:
|
|
42
|
-
return {}
|
|
43
|
-
|
|
44
|
-
settings = self.config.to_django_settings()
|
|
45
|
-
|
|
46
|
-
# Log configuration
|
|
47
|
-
enabled_jobs = self.config.get_enabled_jobs()
|
|
48
|
-
if enabled_jobs:
|
|
49
|
-
logger.info(
|
|
50
|
-
f"✓ Configured {len(enabled_jobs)} crontab job(s) "
|
|
51
|
-
f"[django-crontab integration]"
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
# Log individual jobs in debug mode
|
|
55
|
-
for job in enabled_jobs:
|
|
56
|
-
logger.debug(
|
|
57
|
-
f" - {job.name}: {job.schedule} → "
|
|
58
|
-
f"{job.command if job.job_type == 'command' else job.callable_path}"
|
|
59
|
-
)
|
|
60
|
-
|
|
61
|
-
return settings
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
__all__ = ["CrontabSettingsGenerator"]
|