utg-base 1.0.0__tar.gz

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.
@@ -0,0 +1,19 @@
1
+ Metadata-Version: 2.1
2
+ Name: utg-base
3
+ Version: 1.0.0
4
+ Summary: UTG Base Package
5
+ Author: Rovshen
6
+ Author-email: rovshenashirov1619@gmail.com
7
+ Requires-Python: >=3.14,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Requires-Dist: croniter (>=2.0.3,<3.0.0)
10
+ Requires-Dist: django (>=5.2.7,<6.0.0)
11
+ Requires-Dist: django-filter (>=23.5,<24.0)
12
+ Requires-Dist: djangorestframework (>=3.16.1,<4.0.0)
13
+ Requires-Dist: djangorestframework-simplejwt[crypto] (>=5.3.1,<6.0.0)
14
+ Requires-Dist: drf-spectacular[sidecar] (>=0.27.1,<0.28.0)
15
+ Requires-Dist: inflect (>=7.2.1,<8.0.0)
16
+ Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ # UzTransGas Base
@@ -0,0 +1 @@
1
+ # UzTransGas Base
@@ -0,0 +1,25 @@
1
+ [tool.poetry]
2
+ name = "utg-base"
3
+ version = "1.0.0"
4
+ description = "UTG Base Package"
5
+ authors = ["Rovshen <rovshenashirov1619@gmail.com>"]
6
+ readme = "README.md"
7
+
8
+ [tool.poetry.dependencies]
9
+ python = "^3.14"
10
+ djangorestframework = "^3.16.1"
11
+ djangorestframework-simplejwt = { extras = ["crypto"], version = "^5.3.1" }
12
+ django = "^5.2.7"
13
+ django-filter = "^23.5"
14
+ croniter = "^2.0.3"
15
+ drf-spectacular = {extras = ["sidecar"], version = "^0.27.1"}
16
+ openpyxl = "^3.1.2"
17
+ inflect = "^7.2.1"
18
+
19
+ [[tool.poetry.source]]
20
+ name = "PyPI"
21
+ priority = "primary"
22
+
23
+ [build-system]
24
+ requires = ["poetry-core"]
25
+ build-backend = "poetry.core.masonry.api"
File without changes
File without changes
@@ -0,0 +1,33 @@
1
+ from rest_framework.pagination import PageNumberPagination
2
+ from rest_framework.response import Response
3
+
4
+
5
+ class Pagination(PageNumberPagination):
6
+ page_size_query_param = 'page_size'
7
+ max_page_size = 200
8
+
9
+ def get_paginated_response(self, data):
10
+ return Response({
11
+ 'page': self.page.number,
12
+ 'pageSize': self.page.paginator.per_page,
13
+ 'count': self.page.end_index() - self.page.start_index() + 1,
14
+ 'total': self.page.paginator.count,
15
+ 'pagesCount': self.page.paginator.num_pages,
16
+ 'data': data,
17
+ })
18
+
19
+
20
+ class LargeResultsSetPagination(Pagination):
21
+ page_size = 50
22
+
23
+
24
+ class StandardResultsSetPagination(Pagination):
25
+ page_size = 20
26
+
27
+
28
+ class SmallResultsSetPagination(Pagination):
29
+ page_size = 10
30
+
31
+
32
+ class MiniResultsSetPagination(Pagination):
33
+ page_size = 5
@@ -0,0 +1,7 @@
1
+ from rest_framework.routers import SimpleRouter
2
+
3
+
4
+ class OptionalSlashRouter(SimpleRouter):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.trailing_slash = '/?'
@@ -0,0 +1,2 @@
1
+ from .models import MicroserviceUser
2
+ from .microservice_authentication import MicroserviceUserAuthentication
@@ -0,0 +1,29 @@
1
+ from ipaddress import ip_address, ip_network
2
+
3
+ from rest_framework import authentication
4
+
5
+ from . import MicroserviceUser
6
+
7
+
8
+ class MicroserviceUserAuthentication(authentication.BaseAuthentication):
9
+ # List of local IP address ranges
10
+ local_ip_ranges = [
11
+ '127.0.0.0/8', # Loopback addresses
12
+ '10.0.0.0/8', # Private network addresses
13
+ '172.16.0.0/12', # Private network addresses
14
+ '192.168.0.0/16', # Private network addresses
15
+ # Add more local ranges if needed
16
+ ]
17
+
18
+ def authenticate(self, request):
19
+ client_ip = request.META.get('REMOTE_ADDR', None)
20
+ server_ip = request.META.get('SERVER_ADDR', None)
21
+
22
+ if any(ip_address(client_ip) in ip_network(ip_range, strict=False) for ip_range in self.local_ip_ranges):
23
+ return self.get_user(), None
24
+
25
+ if client_ip == server_ip:
26
+ return self.get_user(), None
27
+
28
+ def get_user(self) -> MicroserviceUser:
29
+ return MicroserviceUser()
@@ -0,0 +1,92 @@
1
+ from typing import List, Optional, Union
2
+
3
+ from django.contrib.auth import models as auth_models
4
+ from django.db.models.manager import EmptyManager
5
+ from django.utils.functional import cached_property
6
+
7
+
8
+ class MicroserviceUser:
9
+ is_active = True
10
+
11
+ _groups = EmptyManager(auth_models.Group)
12
+ _user_permissions = EmptyManager(auth_models.Permission)
13
+
14
+ def __str__(self) -> str:
15
+ return f"{self.id}"
16
+
17
+ @cached_property
18
+ def id(self) -> Union[int, str]:
19
+ return -1
20
+
21
+ @cached_property
22
+ def pk(self) -> Union[int, str]:
23
+ return self.id
24
+
25
+ @cached_property
26
+ def username(self) -> str:
27
+ return 'microservice'
28
+
29
+ @cached_property
30
+ def is_staff(self) -> bool:
31
+ return True
32
+
33
+ @cached_property
34
+ def is_superuser(self) -> bool:
35
+ return True
36
+
37
+ def __eq__(self, other: object) -> bool:
38
+ if not isinstance(other, MicroserviceUser):
39
+ return NotImplemented
40
+ return self.id == other.id
41
+
42
+ def __ne__(self, other: object) -> bool:
43
+ return not self.__eq__(other)
44
+
45
+ def __hash__(self) -> int:
46
+ return hash(self.id)
47
+
48
+ def save(self) -> None:
49
+ raise NotImplementedError("Microservice users have no DB representation")
50
+
51
+ def delete(self) -> None:
52
+ raise NotImplementedError("Microservice users have no DB representation")
53
+
54
+ def set_password(self, raw_password: str) -> None:
55
+ raise NotImplementedError("Microservice users have no DB representation")
56
+
57
+ def check_password(self, raw_password: str) -> None:
58
+ raise NotImplementedError("Microservice users have no DB representation")
59
+
60
+ @property
61
+ def groups(self) -> auth_models.Group:
62
+ return self._groups
63
+
64
+ @property
65
+ def user_permissions(self) -> auth_models.Permission:
66
+ return self._user_permissions
67
+
68
+ def get_group_permissions(self, obj: Optional[object] = None) -> set:
69
+ return set()
70
+
71
+ def get_all_permissions(self, obj: Optional[object] = None) -> set:
72
+ return set()
73
+
74
+ def has_perm(self, perm: str, obj: Optional[object] = None) -> bool:
75
+ return False
76
+
77
+ def has_perms(self, perm_list: List[str], obj: Optional[object] = None) -> bool:
78
+ return False
79
+
80
+ def has_module_perms(self, module: str) -> bool:
81
+ return False
82
+
83
+ @property
84
+ def is_anonymous(self) -> bool:
85
+ return False
86
+
87
+ @property
88
+ def is_authenticated(self) -> bool:
89
+ return True
90
+
91
+ def get_username(self) -> str:
92
+ return self.username
@@ -0,0 +1,135 @@
1
+ import logging
2
+ import os
3
+
4
+
5
+ class UtgBaseFilter(logging.Filter):
6
+ BASE_DIR = os.getcwd()
7
+
8
+ def filter(self, record):
9
+ sp = '/site-packages/'
10
+ path = record.pathname
11
+
12
+ if record.pathname.startswith(str(self.BASE_DIR)):
13
+ path = record.pathname[len(str(self.BASE_DIR)):]
14
+ elif sp in path:
15
+ path = path[path.index(sp, 0) + len(sp):]
16
+
17
+ path = path.replace('/', '.')
18
+ path = path.removeprefix('.')
19
+ record.path = path
20
+ return record
21
+
22
+
23
+ class UtgBaseLogging:
24
+ enable_file = int(os.environ.get('LOGGING_FILE', False))
25
+ enable_console_info = int(os.environ.get('LOGGING_CONSOLE_INFO', True))
26
+ enable_db_debug = int(os.environ.get('LOGGING_DB_DEBUG', False))
27
+ enable_loki = int(os.environ.get('LOGGING_LOKI', True))
28
+ enable_loki_debug = int(os.environ.get('LOGGING_LOKI_DEBUG', False))
29
+
30
+ logger = logging.getLogger('main')
31
+
32
+ format = '[%(asctime)s] %(levelname)s [%(path)s:%(lineno)s] [%(funcName)s] %(message)s'
33
+
34
+ __LOGGING = {
35
+ 'version': 1,
36
+ 'disable_existing_loggers': False,
37
+ 'filters': {
38
+ 'trim_path': {
39
+ '()': 'utg_base.logging.UtgBaseFilter',
40
+ },
41
+ },
42
+ 'formatters': {
43
+ 'simple': {
44
+ 'format': format,
45
+ 'datefmt': '%Y-%m-%d %H:%M:%S',
46
+ },
47
+ 'loki': {
48
+ 'class': 'django_loki.LokiFormatter', # required
49
+ 'format': format, # optional, default is logging.BASIC_FORMAT
50
+ 'datefmt': '%Y-%m-%d %H:%M:%S', # optional, default is '%Y-%m-%d %H:%M:%S'
51
+ },
52
+ },
53
+ 'handlers': {
54
+ 'file': {
55
+ 'level': 'ERROR',
56
+ 'class': 'logging.FileHandler',
57
+ 'filename': 'logs/django-error.log',
58
+ 'formatter': 'simple',
59
+ 'filters': ['trim_path'],
60
+ },
61
+ 'console_info': {
62
+ 'level': 'INFO',
63
+ 'class': 'logging.StreamHandler',
64
+ 'formatter': 'simple',
65
+ 'filters': ['trim_path'],
66
+ },
67
+ 'console_debug': {
68
+ 'level': 'DEBUG',
69
+ 'class': 'logging.StreamHandler',
70
+ 'formatter': 'simple',
71
+ 'filters': ['trim_path'],
72
+ },
73
+ 'loki': {
74
+ 'level': os.environ.get('LOKI_LEVEL', 'ERROR'), # required
75
+ 'class': 'django_loki.LokiHttpHandler', # required
76
+ 'host': os.environ.get('LOKI_HOST', os.environ.get('DB_HOST')),
77
+ # required, your grafana/Loki server host, e.g:192.168.25.30
78
+ 'formatter': 'loki', # required, loki formatter,
79
+ 'port': int(os.environ.get('LOKI_PORT', 3100)),
80
+ # optional, your grafana/Loki server port, default is 3100
81
+ 'timeout': float(os.environ.get('LOKI_TIMEOUT', 0.5)),
82
+ # optional, request Loki-server by http or https time out, default is 0.5
83
+ 'protocol': os.environ.get('LOKI_PROTOCOL', 'http'),
84
+ # optional, Loki-server protocol, default is http
85
+ 'source': os.environ.get('LOKI_SOURCE', 'Loki'), # optional, label name for Loki, default is Loki
86
+ 'src_host': os.environ.get('LOKI_SRC_HOST', 'localhost'),
87
+ # optional, label name for Loki, default is localhost
88
+ 'tz': 'Asia/Tashkent',
89
+ # optional, timezone for formatting timestamp, default is UTC, e.g:Asia/Shanghai
90
+ 'filters': ['trim_path'],
91
+ },
92
+ },
93
+ 'loggers': {
94
+ 'django': {
95
+ 'handlers': [],
96
+ 'level': 'DEBUG',
97
+ 'propagate': True,
98
+ },
99
+ 'django.db.backends': {
100
+ 'handlers': [],
101
+ 'level': 'DEBUG',
102
+ 'propagate': True,
103
+ },
104
+ 'main': {
105
+ 'handlers': [],
106
+ 'level': 'DEBUG',
107
+ 'propagate': True,
108
+ }
109
+ },
110
+ }
111
+
112
+ # noinspection PyUnresolvedReferences
113
+ @classmethod
114
+ def logging(cls):
115
+ _logging = cls.__LOGGING.copy()
116
+
117
+ if cls.enable_file:
118
+ _logging['loggers']['django']['handlers'].append('file')
119
+ if cls.enable_console_info:
120
+ _logging['loggers']['django']['handlers'].append('console_info')
121
+ if cls.enable_db_debug:
122
+ _logging['loggers']['django.db.backends']['handlers'].append('console_debug')
123
+ if cls.enable_loki:
124
+ _logging['loggers']['django']['handlers'].append('loki')
125
+ if cls.enable_loki_debug:
126
+ _logging['handlers']['loki_debug'] = _logging['handlers']['loki'].copy()
127
+ _logging['handlers']['loki_debug']['level'] = 'DEBUG'
128
+ _logging['loggers']['main']['handlers'].append('loki_debug')
129
+ _logging['loggers']['main']['handlers'].append('console_debug')
130
+
131
+ return _logging
132
+
133
+
134
+ LOGGING = UtgBaseLogging.logging()
135
+ logger = UtgBaseLogging.logger