utg-base 1.1.0__py3-none-any.whl → 1.2.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/api/base.py +75 -0
- utg_base/api/views.py +13 -0
- utg_base/models/__init__.py +1 -2
- utg_base/services/__init__.py +1 -0
- utg_base/services/base_api.py +128 -0
- utg_base/utils/__init__.py +1 -0
- utg_base/utils/response_processors.py +27 -0
- {utg_base-1.1.0.dist-info → utg_base-1.2.0.dist-info}/METADATA +1 -1
- {utg_base-1.1.0.dist-info → utg_base-1.2.0.dist-info}/RECORD +10 -4
- {utg_base-1.1.0.dist-info → utg_base-1.2.0.dist-info}/WHEEL +0 -0
utg_base/api/base.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
from django.utils import timezone
|
|
2
|
+
from django.utils.translation import activate, get_language
|
|
3
|
+
from rest_framework.request import Request
|
|
4
|
+
from rest_framework.views import APIView
|
|
5
|
+
|
|
6
|
+
from ..models import JWTUser
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
AVAILABLE_LANGUAGES = ['uz', 'ru', 'crl']
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseRequest(Request):
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def user(self) -> JWTUser:
|
|
16
|
+
return super(BaseRequest, self).user()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BaseAPIView(APIView):
|
|
20
|
+
user_id_assign_fields_on_create = []
|
|
21
|
+
user_id_assign_fields_on_update = []
|
|
22
|
+
user_id_assign_fields_on_delete = []
|
|
23
|
+
deleted_at_field = None
|
|
24
|
+
|
|
25
|
+
def __init__(self, **kwargs):
|
|
26
|
+
# Check user_id_assign_fields_on_create
|
|
27
|
+
assert isinstance(self.user_id_assign_fields_on_create, list), (
|
|
28
|
+
'Expected iterable user_id_assign_fields_on_create field'
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# Check user_id_assign_fields_on_update
|
|
32
|
+
assert isinstance(self.user_id_assign_fields_on_update, list), (
|
|
33
|
+
'Expected iterable user_id_assign_fields_on_update field'
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Check user_id_assign_fields_on_delete
|
|
37
|
+
assert isinstance(self.user_id_assign_fields_on_delete, list), (
|
|
38
|
+
'Expected iterable user_id_assign_fields_on_delete field'
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Check deleted_at_field
|
|
42
|
+
assert isinstance(self.deleted_at_field, (str, type(None))), (
|
|
43
|
+
'Expected str | None deleted_at_field field'
|
|
44
|
+
)
|
|
45
|
+
super().__init__(**kwargs)
|
|
46
|
+
self.request: BaseRequest | None = None
|
|
47
|
+
|
|
48
|
+
def perform_create(self, serializer):
|
|
49
|
+
kws = {}
|
|
50
|
+
for attr in getattr(self, 'user_id_assign_fields_on_create', []):
|
|
51
|
+
kws[attr] = self.request.user.id
|
|
52
|
+
serializer.save(**kws)
|
|
53
|
+
|
|
54
|
+
def perform_update(self, serializer):
|
|
55
|
+
kws = {}
|
|
56
|
+
for attr in getattr(self, 'user_id_assign_fields_on_update', []):
|
|
57
|
+
kws[attr] = self.request.user.id
|
|
58
|
+
serializer.save(**kws)
|
|
59
|
+
|
|
60
|
+
def perform_destroy(self, instance):
|
|
61
|
+
for attr in getattr(self, 'user_id_assign_fields_on_delete', []):
|
|
62
|
+
setattr(instance, attr, self.request.user.id)
|
|
63
|
+
if self.deleted_at_field and hasattr(instance, self.deleted_at_field):
|
|
64
|
+
setattr(instance, self.deleted_at_field, timezone.now())
|
|
65
|
+
instance.save()
|
|
66
|
+
|
|
67
|
+
def update_lang(self):
|
|
68
|
+
activate(self.get_language())
|
|
69
|
+
|
|
70
|
+
def get_language(self):
|
|
71
|
+
if lang_from_header := self.request.headers.get('accept-language'):
|
|
72
|
+
if lang_from_header and lang_from_header not in AVAILABLE_LANGUAGES:
|
|
73
|
+
lang_from_header = 'ru'
|
|
74
|
+
|
|
75
|
+
return lang_from_header or get_language()
|
utg_base/api/views.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
from django.db.models import Manager
|
|
3
|
+
from rest_framework import generics
|
|
4
|
+
|
|
5
|
+
from .base import BaseAPIView
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TranslatedListView(generics.ListAPIView, BaseAPIView):
|
|
9
|
+
manager: Manager
|
|
10
|
+
|
|
11
|
+
def get_queryset(self):
|
|
12
|
+
self.update_lang()
|
|
13
|
+
return self.manager.all()
|
utg_base/models/__init__.py
CHANGED
|
@@ -1,2 +1 @@
|
|
|
1
|
-
from
|
|
2
|
-
from energy_base.models.deviation_reason_type import DeviationReasonType
|
|
1
|
+
from .jwt_user import JWTUser
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .base_api import BaseServiceAPI
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
from typing import Callable, Any
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
import urllib3
|
|
5
|
+
from requests import Response
|
|
6
|
+
|
|
7
|
+
from utg_base.utils import call_processor
|
|
8
|
+
|
|
9
|
+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseServiceAPI:
|
|
13
|
+
name: str = None
|
|
14
|
+
base_url: str = None
|
|
15
|
+
default_response_processor: Callable[[Response], Any] = None
|
|
16
|
+
|
|
17
|
+
def request(self, method, path, data=None, json=None, params=None, headers=None,
|
|
18
|
+
authenticator: Callable[[dict], dict] | None = 'default',
|
|
19
|
+
response_processor: Callable[[Response], Any] | None = 'default',
|
|
20
|
+
**kwargs):
|
|
21
|
+
"""
|
|
22
|
+
Make an HTTP request using the requests' library.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
method: The HTTP method (GET, POST, PUT, DELETE, etc.).
|
|
26
|
+
path: The API endpoint path.
|
|
27
|
+
data: Dictionary or bytes to be sent in the body of the request (for form data).
|
|
28
|
+
json: JSON serializable data to be sent in the body of the request (for JSON data).
|
|
29
|
+
params: Query parameters as a dictionary.
|
|
30
|
+
headers: Headers to be included in the request.
|
|
31
|
+
authenticator: Optional authenticator function to handle authentication with headers.
|
|
32
|
+
This function should modify the headers for authentication purposes.
|
|
33
|
+
Example authenticator function:
|
|
34
|
+
def my_authenticator(headers):
|
|
35
|
+
headers['Authorization'] = 'Bearer YOUR_ACCESS_TOKEN'
|
|
36
|
+
return headers
|
|
37
|
+
|
|
38
|
+
response_processor: Optional function to process the response data.
|
|
39
|
+
This function should take the requests.Response object as input and return processed data.
|
|
40
|
+
Example response processor function:
|
|
41
|
+
def process_response(response):
|
|
42
|
+
return response.json()
|
|
43
|
+
Kwargs:
|
|
44
|
+
auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
The response data, processed if a response processor is provided.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
if headers is None:
|
|
51
|
+
headers = {}
|
|
52
|
+
|
|
53
|
+
if callable(authenticator):
|
|
54
|
+
headers = authenticator(headers)
|
|
55
|
+
|
|
56
|
+
if authenticator == 'default' and hasattr(self, 'authenticate') and callable(self.authenticate):
|
|
57
|
+
headers = self.authenticate(headers)
|
|
58
|
+
|
|
59
|
+
response = requests.request(
|
|
60
|
+
method=method,
|
|
61
|
+
url=self.base_url + path,
|
|
62
|
+
data=data,
|
|
63
|
+
json=json,
|
|
64
|
+
params=params,
|
|
65
|
+
headers=headers,
|
|
66
|
+
verify=False,
|
|
67
|
+
**kwargs
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
if response_processor == 'default':
|
|
71
|
+
if hasattr(self, 'default_response_processor') and callable(self.default_response_processor):
|
|
72
|
+
return self.default_response_processor(response)
|
|
73
|
+
return response
|
|
74
|
+
|
|
75
|
+
if response_processor is not None:
|
|
76
|
+
return response_processor(response)
|
|
77
|
+
|
|
78
|
+
return response
|
|
79
|
+
|
|
80
|
+
def call(self, method, path, data=None, json=None, params=None, headers=None):
|
|
81
|
+
data = self.request(
|
|
82
|
+
method=method,
|
|
83
|
+
path=path,
|
|
84
|
+
data=data,
|
|
85
|
+
json=json,
|
|
86
|
+
params=params,
|
|
87
|
+
headers=headers,
|
|
88
|
+
response_processor=call_processor
|
|
89
|
+
)
|
|
90
|
+
return {
|
|
91
|
+
'path': self.base_url + path,
|
|
92
|
+
'method': method,
|
|
93
|
+
'status': data['status'],
|
|
94
|
+
'reason': data['reason'],
|
|
95
|
+
'request': params if method == 'get' else json,
|
|
96
|
+
'response': data['response'],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
def authenticate(self, headers: dict) -> dict:
|
|
100
|
+
"""
|
|
101
|
+
Example authenticate method:
|
|
102
|
+
authenticate(self, headers):
|
|
103
|
+
headers['Authorization'] = 'Bearer YOUR_ACCESS_TOKEN'
|
|
104
|
+
return headers
|
|
105
|
+
:param headers:
|
|
106
|
+
:return:
|
|
107
|
+
"""
|
|
108
|
+
return headers
|
|
109
|
+
|
|
110
|
+
def get(self, path, data=None, json=None, params=None, headers=None,
|
|
111
|
+
authenticator: Callable[[dict], dict] | None = 'default',
|
|
112
|
+
response_processor: Callable[[Response], Any] | None = 'default'):
|
|
113
|
+
return self.request('get', path, data, json, params, headers, authenticator, response_processor)
|
|
114
|
+
|
|
115
|
+
def post(self, path, data=None, json=None, params=None, headers=None,
|
|
116
|
+
authenticator: Callable[[dict], dict] | None = 'default',
|
|
117
|
+
response_processor: Callable[[Response], Any] | None = 'default'):
|
|
118
|
+
return self.request('post', path, data, json, params, headers, authenticator, response_processor)
|
|
119
|
+
|
|
120
|
+
def put(self, path, data=None, json=None, params=None, headers=None,
|
|
121
|
+
authenticator: Callable[[dict], dict] | None = 'default',
|
|
122
|
+
response_processor: Callable[[Response], Any] | None = 'default'):
|
|
123
|
+
return self.request('put', path, data, json, params, headers, authenticator, response_processor)
|
|
124
|
+
|
|
125
|
+
def patch(self, path, data=None, json=None, params=None, headers=None,
|
|
126
|
+
authenticator: Callable[[dict], dict] | None = 'default',
|
|
127
|
+
response_processor: Callable[[Response], Any] | None = 'default'):
|
|
128
|
+
return self.request('patch', path, data, json, params, headers, authenticator, response_processor)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .response_processors import call_processor, data_processor
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from requests import Response
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def call_processor(response: Response):
|
|
5
|
+
try:
|
|
6
|
+
data = response.json()
|
|
7
|
+
except Exception as e:
|
|
8
|
+
data = response.text
|
|
9
|
+
return {
|
|
10
|
+
'status': response.status_code,
|
|
11
|
+
'reason': response.reason,
|
|
12
|
+
'response': data,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def data_processor(response: Response):
|
|
17
|
+
try:
|
|
18
|
+
data = response.json()
|
|
19
|
+
except Exception as e:
|
|
20
|
+
raise Exception({
|
|
21
|
+
'status': response.status_code,
|
|
22
|
+
'reason': response.reason,
|
|
23
|
+
'response': response.text,
|
|
24
|
+
'exception': str(e)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return data
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
utg_base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
utg_base/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
utg_base/api/base.py,sha256=gbL3TtJKqdstpfbycvHorqpWaVRI87C1zix_MrJn0Cc,2560
|
|
3
4
|
utg_base/api/pagination.py,sha256=zzIUwW3iF5G_11gFsno9y1DmgFiULQIWRHUj0LKhYfE,854
|
|
4
5
|
utg_base/api/routers.py,sha256=lU54MVN2BF_q1AWp9EdXkG3m_ivYRtvbNGXFIRKz7u0,177
|
|
6
|
+
utg_base/api/views.py,sha256=yYCEJRouFA71cI2Ubc1A736oLg9NGWyTIVnD-Q85k6w,279
|
|
5
7
|
utg_base/authentications/__init__.py,sha256=a6twO_bBf8FAHYl7PXawfR2UbBwwdueG1uS_dbq2g_I,109
|
|
6
8
|
utg_base/authentications/microservice_authentication.py,sha256=6aAncxIpA4FcyRegd7QqRYvW5Wn8FxyPU0nQqCVuEs4,976
|
|
7
9
|
utg_base/authentications/models.py,sha256=JQonSdXeSeoF003QlmPvH58nWmVJRKlWWjW_ySqXaYg,2496
|
|
8
10
|
utg_base/logging.py,sha256=MNPUQ9Hdg-0YTFlJBOwhajqKz-8Y5P4POkqRNIU9ga8,5078
|
|
9
|
-
utg_base/models/__init__.py,sha256=
|
|
11
|
+
utg_base/models/__init__.py,sha256=ylLp_n2WJqvmuG-4X8yv119Ikcx-OFSYHUcnggUeQeo,30
|
|
10
12
|
utg_base/models/jwt_user.py,sha256=6TQ5wB_OZBtGhRL-2MonBGZm0n0Y86s4BRTxiRlUJOk,375
|
|
11
13
|
utg_base/references_api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
14
|
utg_base/references_api/admin.py,sha256=suMo4x8I3JBxAFBVIdE-5qnqZ6JAZV0FESABHOSc-vg,63
|
|
@@ -15,6 +17,10 @@ utg_base/references_api/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
|
|
|
15
17
|
utg_base/references_api/models.py,sha256=Vjc0p2XbAPgE6HyTF6vll98A4eDhA5AvaQqsc4kQ9AQ,57
|
|
16
18
|
utg_base/references_api/urls.py,sha256=WkLACQ8GfK5pJkvt8FuYdOxcqSZHj7pYRw51M9WluGw,390
|
|
17
19
|
utg_base/references_api/utils.py,sha256=VzQMnGeWC0I-6BkK_9Lo9eSH6wd4C766oQ84n7SBWyc,5818
|
|
18
|
-
utg_base
|
|
19
|
-
utg_base
|
|
20
|
-
utg_base
|
|
20
|
+
utg_base/services/__init__.py,sha256=LqtwUiqEZPIbKRGJfve5D5m3ucV6Kw1Nbo5Jnj_hPhY,37
|
|
21
|
+
utg_base/services/base_api.py,sha256=fxwy7VagfyngvcbNdk7b3G5XOyykaJQQyDMub1EyCLA,5187
|
|
22
|
+
utg_base/utils/__init__.py,sha256=wpQYZVF_uF7tVm3tPkyyvZPibPMRKaG4ebe3WPA68uc,63
|
|
23
|
+
utg_base/utils/response_processors.py,sha256=Eim0NIbCt2GH_grzrD6DHqr5iczCHfu1wr9lqThlX3U,605
|
|
24
|
+
utg_base-1.2.0.dist-info/METADATA,sha256=ta_caUY5Jm94LtCn66BJynhRxHUyt99l-JG2hj2HvpY,660
|
|
25
|
+
utg_base-1.2.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
26
|
+
utg_base-1.2.0.dist-info/RECORD,,
|
|
File without changes
|