utg-base 1.21.1__py3-none-any.whl → 1.22.0__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.
- utg_base/celery/serializers/periodic_task.py +2 -2
- utg_base/celery/views/periodic_task.py +15 -1
- utg_base/permissions/decorators.py +6 -2
- utg_base/utils/data.py +36 -0
- {utg_base-1.21.1.dist-info → utg_base-1.22.0.dist-info}/METADATA +1 -1
- {utg_base-1.21.1.dist-info → utg_base-1.22.0.dist-info}/RECORD +7 -7
- {utg_base-1.21.1.dist-info → utg_base-1.22.0.dist-info}/WHEEL +0 -0
|
@@ -7,7 +7,7 @@ from utg_base.celery.serializers import TaskResultSerializer
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class CrontabScheduleSerializer(serializers.ModelSerializer):
|
|
10
|
-
timezone = serializers.SerializerMethodField()
|
|
10
|
+
timezone = serializers.SerializerMethodField(read_only=True)
|
|
11
11
|
|
|
12
12
|
class Meta:
|
|
13
13
|
model = CrontabSchedule
|
|
@@ -18,7 +18,7 @@ class CrontabScheduleSerializer(serializers.ModelSerializer):
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class PeriodicTaskSerializer(serializers.ModelSerializer):
|
|
21
|
-
crontab = CrontabScheduleSerializer(
|
|
21
|
+
crontab = CrontabScheduleSerializer()
|
|
22
22
|
task_result = serializers.SerializerMethodField(read_only=True)
|
|
23
23
|
|
|
24
24
|
class Meta:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
|
|
3
3
|
from celery import current_app
|
|
4
|
-
from django_celery_beat.models import PeriodicTask
|
|
4
|
+
from django_celery_beat.models import PeriodicTask, CrontabSchedule
|
|
5
5
|
from drf_spectacular.utils import extend_schema
|
|
6
6
|
from rest_framework import viewsets, filters
|
|
7
7
|
from rest_framework.exceptions import NotFound, ValidationError
|
|
@@ -23,6 +23,20 @@ class PeriodicTaskViewSet(viewsets.ModelViewSet):
|
|
|
23
23
|
filter_backends = [filters.SearchFilter]
|
|
24
24
|
search_fields = ['name']
|
|
25
25
|
|
|
26
|
+
@extend_schema(request={'application/json': PeriodicTaskSerializer()})
|
|
27
|
+
def partial_update(self, request, *args, **kwargs):
|
|
28
|
+
crontab = request.data.pop('crontab')
|
|
29
|
+
response = super().partial_update(request, *args, **kwargs)
|
|
30
|
+
|
|
31
|
+
if crontab:
|
|
32
|
+
instance = self.get_object()
|
|
33
|
+
crontab, _ = CrontabSchedule.objects.get_or_create(**crontab)
|
|
34
|
+
|
|
35
|
+
instance.crontab = crontab
|
|
36
|
+
instance.save()
|
|
37
|
+
|
|
38
|
+
return Response(self.serializer_class(instance).data)
|
|
39
|
+
|
|
26
40
|
|
|
27
41
|
@extend_schema(tags=['admin/periodic-tasks'])
|
|
28
42
|
class PeriodicTaskRunNowView(APIView):
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from functools import wraps
|
|
2
2
|
from typing import Literal, Dict, Union, List
|
|
3
3
|
|
|
4
|
-
from rest_framework.exceptions import PermissionDenied
|
|
5
|
-
|
|
6
4
|
from .utils import has_perms as has_permissions
|
|
7
5
|
|
|
8
6
|
|
|
@@ -13,15 +11,20 @@ def has_perm(*permission: str, operator: Literal["OR", "AND"] = "OR"):
|
|
|
13
11
|
has_perm('PERM1', 'PERM2')
|
|
14
12
|
|
|
15
13
|
:param permission: One or many permissions.
|
|
14
|
+
:param operator: Any of (OR, AND)
|
|
16
15
|
"""
|
|
16
|
+
|
|
17
17
|
def decorator(view_func):
|
|
18
18
|
view_func._perms = permission
|
|
19
|
+
|
|
19
20
|
@wraps(view_func)
|
|
20
21
|
def _wrapped_view(self, request, *args, **kwargs):
|
|
21
22
|
if not has_permissions(user_id=request.user.id, perms=list(permission), operator=operator, request=request):
|
|
22
23
|
self.permission_denied(request)
|
|
23
24
|
return view_func(self, request, *args, **kwargs)
|
|
25
|
+
|
|
24
26
|
return _wrapped_view
|
|
27
|
+
|
|
25
28
|
return decorator
|
|
26
29
|
|
|
27
30
|
|
|
@@ -34,6 +37,7 @@ def has_class_perm(permissions_map: Dict[str, Union[str, List[str]]], operator:
|
|
|
34
37
|
'update': ['perm4']
|
|
35
38
|
})
|
|
36
39
|
"""
|
|
40
|
+
|
|
37
41
|
def decorator(cls):
|
|
38
42
|
for action, perms in permissions_map.items():
|
|
39
43
|
if isinstance(perms, str):
|
utg_base/utils/data.py
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
from collections import defaultdict
|
|
1
3
|
from collections.abc import Iterable
|
|
2
4
|
from copy import deepcopy
|
|
3
5
|
|
|
4
6
|
from django.db.models import QuerySet
|
|
5
7
|
|
|
8
|
+
from utg_base.utils.date import UDate, UDateTime
|
|
9
|
+
|
|
6
10
|
|
|
7
11
|
def deep_map(data: dict | list, func_cond, func_map, in_place=True):
|
|
8
12
|
if not in_place:
|
|
@@ -153,3 +157,35 @@ def compute_change_percent(current, previous, ndigits=2):
|
|
|
153
157
|
if not current or previous in (None, 0):
|
|
154
158
|
return None
|
|
155
159
|
return round(((current - previous) / previous) * 100, ndigits)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def list_to_dict(rows: Iterable[dict], key: str, key_func=None) -> dict:
|
|
163
|
+
if not key_func:
|
|
164
|
+
key_func = lambda x: x
|
|
165
|
+
return {row[key_func(key)]: row for row in rows}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def generate_series(start: UDate | UDateTime, end: UDate | UDateTime, step: datetime.timedelta):
|
|
169
|
+
current = start
|
|
170
|
+
if step.total_seconds() == 0:
|
|
171
|
+
raise ValueError("step cannot be zero")
|
|
172
|
+
|
|
173
|
+
series = []
|
|
174
|
+
while current <= end:
|
|
175
|
+
series.append(current)
|
|
176
|
+
current += step
|
|
177
|
+
|
|
178
|
+
return series
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def fill_series(series: Iterable, data: dict, keys: str | list[str]):
|
|
182
|
+
result = defaultdict(list)
|
|
183
|
+
|
|
184
|
+
for term in series:
|
|
185
|
+
for key in keys:
|
|
186
|
+
result[key].append(data.get(term, {}).get(key, None))
|
|
187
|
+
|
|
188
|
+
data = []
|
|
189
|
+
for key in keys:
|
|
190
|
+
data.append(result[key])
|
|
191
|
+
return data
|
|
@@ -17,11 +17,11 @@ utg_base/celery/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
17
17
|
utg_base/celery/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
18
|
utg_base/celery/management/commands/migrate_tasks.py,sha256=TAvPmYAmMkODdPAucbQDya2dd-BkVFCvWJrolqFdz6w,1667
|
|
19
19
|
utg_base/celery/serializers/__init__.py,sha256=NjQ4dcnyoX9p5ljUBCjDegTKt7icia48GkVSmFCK9Ao,96
|
|
20
|
-
utg_base/celery/serializers/periodic_task.py,sha256=
|
|
20
|
+
utg_base/celery/serializers/periodic_task.py,sha256=XrBSwmb15HqrfQgRHn1_rOHTvQZXPoR_Mo0wmj5gMeU,1298
|
|
21
21
|
utg_base/celery/serializers/task_result.py,sha256=pt6BRjjvqU1Ah8IUSyL67AZJ1Z5iXAelYe6z-Pv1Nco,220
|
|
22
22
|
utg_base/celery/urls.py,sha256=ww-ZwAzK0CnOZxqh4gaEYGuRoCgkrolB3jvKsLZEknI,524
|
|
23
23
|
utg_base/celery/views/__init__.py,sha256=WPNtK_40JCSYGWkDgtpTdOWJ_GOp_dBKs9eK4VNq5Xs,114
|
|
24
|
-
utg_base/celery/views/periodic_task.py,sha256=
|
|
24
|
+
utg_base/celery/views/periodic_task.py,sha256=UWYew868jmw937uBCaaqarwsfSYhxbCZ9BnjPf-6CtA,2475
|
|
25
25
|
utg_base/celery/views/task_result.py,sha256=c9HIcohrToRfz1jfZRRZ1ri15FOasjKgMYnzKcA2X8M,726
|
|
26
26
|
utg_base/constants/__init__.py,sha256=Bpyeki5V2djF1p6XnhybBnmDiiYpNQwIBvCYI0tlQ68,102
|
|
27
27
|
utg_base/constants/accessibility_type.py,sha256=dJBoA1E7NAGpHzifD_NDL_GPhRY3c6Fabez-34ghLl0,265
|
|
@@ -40,7 +40,7 @@ utg_base/models/__init__.py,sha256=1zXygGICiR3iUCKdkNal9d3i3kNp654gFgBf_VlR2gI,6
|
|
|
40
40
|
utg_base/models/jwt_user.py,sha256=6TQ5wB_OZBtGhRL-2MonBGZm0n0Y86s4BRTxiRlUJOk,375
|
|
41
41
|
utg_base/models/timestamp.py,sha256=AkCliNXnvs8Z17b1mcS7gOK7v6h3Jul6WCyGyVAkb-w,217
|
|
42
42
|
utg_base/permissions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
43
|
-
utg_base/permissions/decorators.py,sha256=
|
|
43
|
+
utg_base/permissions/decorators.py,sha256=db26UrbOk66AuQBRFyxcNoQDSC3EWkencptRHk0ikUM,2105
|
|
44
44
|
utg_base/permissions/folder.py,sha256=uJv40FVb7R379qss66a5oUcLK7KCUIL6DPbzEcGOw38,694
|
|
45
45
|
utg_base/permissions/utils.py,sha256=Rp8_ZuU5SdXri4amfFlMmrBoJUjwwQ4GYxDujRpt8YU,3264
|
|
46
46
|
utg_base/references_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -60,7 +60,7 @@ utg_base/u_services/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
|
60
60
|
utg_base/u_services/models.py,sha256=seaxBj9vNWrPu1Y8r7NzHEuXemtSvqLkaw4S1Xgr58I,1310
|
|
61
61
|
utg_base/u_services/u_requests.py,sha256=fGNWWQ3RJOOARgNHkScsqlGXwP6sI-HnS3Y-HnSoVS4,1709
|
|
62
62
|
utg_base/utils/__init__.py,sha256=zRTdSLGpukInlb7oRD6vcI1jKQkkBR3jTCiOiwOmRyA,159
|
|
63
|
-
utg_base/utils/data.py,sha256=
|
|
63
|
+
utg_base/utils/data.py,sha256=8w0Lr8gj4Klu8903XWZlZeMzz9HxNX9_W08KVeIQMuw,5039
|
|
64
64
|
utg_base/utils/date.py,sha256=fS4o5Nd4HyNyHBJTSsasTlqSMNjnNHwocSYdinkKyeY,4371
|
|
65
65
|
utg_base/utils/dict_util.py,sha256=ipdCZO8aTukGQ319OWHb2Ij5MNtV-FioJQ4qCX3Th48,758
|
|
66
66
|
utg_base/utils/response_processors.py,sha256=WdZQL49wOJqCIY2MucAI6sez_llCqih0v_ltQa-mv7k,687
|
|
@@ -69,6 +69,6 @@ utg_base/utils/sql.py,sha256=rqIWcSjdjIMszdRnsnhV5TTYB8W17RPOujIQA9rKC_Y,762
|
|
|
69
69
|
utg_base/utils/string.py,sha256=ATwIo9uLa00p85h_NjRYLcjRs8o3KSGF7s2yhTg5GiA,1073
|
|
70
70
|
utg_base/utils/thread.py,sha256=4RqRnwtyHymY-dNcuPrMSTamE2V7wCMVfzzyIb0P4TI,2191
|
|
71
71
|
utg_base/utils/translation.py,sha256=GxJHUt0iar_0E7RWBPbeLFQ4DhgXBjffHCmxfKyjFtk,463
|
|
72
|
-
utg_base-1.
|
|
73
|
-
utg_base-1.
|
|
74
|
-
utg_base-1.
|
|
72
|
+
utg_base-1.22.0.dist-info/METADATA,sha256=3mO-4yLX73EtPVU5-gCl8NMCF8wmdw8Z5xzYYs9gZsY,960
|
|
73
|
+
utg_base-1.22.0.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
74
|
+
utg_base-1.22.0.dist-info/RECORD,,
|
|
File without changes
|