maleo-foundation 0.2.100__py3-none-any.whl → 0.3.1__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.
- maleo_foundation/enums.py +16 -1
- maleo_foundation/managers/db.py +16 -1
- maleo_foundation/managers/service.py +11 -1
- maleo_foundation/middlewares/base.py +4 -2
- maleo_foundation/models/transfers/general/database.py +2 -2
- maleo_foundation/models/transfers/general/request.py +15 -7
- maleo_foundation/utils/extractor.py +3 -3
- {maleo_foundation-0.2.100.dist-info → maleo_foundation-0.3.1.dist-info}/METADATA +1 -1
- {maleo_foundation-0.2.100.dist-info → maleo_foundation-0.3.1.dist-info}/RECORD +11 -11
- {maleo_foundation-0.2.100.dist-info → maleo_foundation-0.3.1.dist-info}/WHEEL +0 -0
- {maleo_foundation-0.2.100.dist-info → maleo_foundation-0.3.1.dist-info}/top_level.txt +0 -0
maleo_foundation/enums.py
CHANGED
@@ -169,4 +169,19 @@ class BaseEnums:
|
|
169
169
|
EXP_3DY = int(3*24*60*60)
|
170
170
|
EXP_1WK = int(1*7*24*60*60)
|
171
171
|
EXP_2WK = int(2*7*24*60*60)
|
172
|
-
EXP_1MO = int(1*30*24*60*60)
|
172
|
+
EXP_1MO = int(1*30*24*60*60)
|
173
|
+
|
174
|
+
class Service(StrEnum):
|
175
|
+
TELEMETRY = "maleo-telemetry"
|
176
|
+
METADATA = "maleo-metadata"
|
177
|
+
IDENTITY = "maleo-identity"
|
178
|
+
ACCESS = "maleo-access"
|
179
|
+
WORKSHOP = "maleo-workshop"
|
180
|
+
SOAPIE = "maleo-soapie"
|
181
|
+
MEDIX = "maleo-medix"
|
182
|
+
FHIR = "maleo-fhir"
|
183
|
+
DICOM = "maleo-dicom"
|
184
|
+
SCRIBE = "maleo-scribe"
|
185
|
+
CDS = "maleo-cds"
|
186
|
+
IMAGING = "maleo-imaging"
|
187
|
+
MCU = "maleo-mcu"
|
maleo_foundation/managers/db.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
from contextlib import contextmanager
|
3
3
|
from pydantic import BaseModel, Field
|
4
|
-
from sqlalchemy import MetaData
|
4
|
+
from sqlalchemy import MetaData, text
|
5
5
|
from sqlalchemy.engine import Engine, create_engine
|
6
6
|
from sqlalchemy.exc import SQLAlchemyError
|
7
7
|
from sqlalchemy.ext.declarative import DeclarativeMeta
|
@@ -124,6 +124,21 @@ class DatabaseManager:
|
|
124
124
|
def session(self) -> SessionManager:
|
125
125
|
return self._session
|
126
126
|
|
127
|
+
def check_connection(self) -> bool:
|
128
|
+
"""Check database connectivity by executing a simple query."""
|
129
|
+
self._logger.info("Checking database connectivity...")
|
130
|
+
try:
|
131
|
+
with self._session.get() as session:
|
132
|
+
session.execute(text("SELECT 1"))
|
133
|
+
self._logger.info("Database connectivity check successful.")
|
134
|
+
return True
|
135
|
+
except SQLAlchemyError as se:
|
136
|
+
self._logger.error(f"Database connectivity check failed: {se}", exc_info=True)
|
137
|
+
return False
|
138
|
+
except Exception as e:
|
139
|
+
self._logger.error(f"Unexpected error during connectivity check: {e}", exc_info=True)
|
140
|
+
return False
|
141
|
+
|
127
142
|
def dispose(self) -> None:
|
128
143
|
#* Dispose session
|
129
144
|
if self._session is not None:
|
@@ -5,6 +5,7 @@ from pathlib import Path
|
|
5
5
|
from pydantic_settings import BaseSettings
|
6
6
|
from pydantic import BaseModel, Field
|
7
7
|
from redis.asyncio.client import Redis
|
8
|
+
from redis.exceptions import RedisError
|
8
9
|
from starlette.exceptions import HTTPException
|
9
10
|
from starlette.types import Lifespan, AppType
|
10
11
|
from sqlalchemy import MetaData
|
@@ -332,6 +333,15 @@ class ServiceManager:
|
|
332
333
|
def cache(self) -> CacheManagers:
|
333
334
|
return self._cache
|
334
335
|
|
336
|
+
def check_redis_connection(self) -> bool:
|
337
|
+
try:
|
338
|
+
self._redis.ping()
|
339
|
+
self._loggers.application.info("Redis connection check successful.")
|
340
|
+
return True
|
341
|
+
except RedisError as e:
|
342
|
+
self._loggers.application.error(f"Redis connection check failed: {e}", exc_info=True)
|
343
|
+
return False
|
344
|
+
|
335
345
|
def _initialize_cloud_storage(self) -> None:
|
336
346
|
environment = (
|
337
347
|
BaseEnums.EnvironmentType.STAGING
|
@@ -395,7 +405,7 @@ class ServiceManager:
|
|
395
405
|
def create_app(
|
396
406
|
self,
|
397
407
|
router: APIRouter,
|
398
|
-
lifespan: Optional[Lifespan[AppType]]=None
|
408
|
+
lifespan: Optional[Lifespan[AppType]] = None
|
399
409
|
) -> FastAPI:
|
400
410
|
self._loggers.application.info("Creating FastAPI application")
|
401
411
|
root_path = "" if self._settings.ENVIRONMENT == "local" else f"/{self._configs.service.key.removeprefix("maleo-")}"
|
@@ -217,7 +217,8 @@ class RequestLogger:
|
|
217
217
|
log_func(
|
218
218
|
f"Request | ID: {request_context.request_id} {authentication_info} | "
|
219
219
|
f"IP: {request_context.ip_address} | Host: {request_context.host} | "
|
220
|
-
f"Method: {request_context.method} | URL: {request_context.url}
|
220
|
+
f"Method: {request_context.method} | URL: {request_context.url} | "
|
221
|
+
f"Query Parameters: {request_context.query_params} - "
|
221
222
|
f"Response | Status: {response.status_code}"
|
222
223
|
)
|
223
224
|
|
@@ -239,7 +240,8 @@ class RequestLogger:
|
|
239
240
|
self.logger.error(
|
240
241
|
f"Request | ID: {request_context.request_id} {authentication_info} | "
|
241
242
|
f"IP: {request_context.ip_address} | Host: {request_context.host} | "
|
242
|
-
f"Method: {request_context.method} | URL: {request_context.url}
|
243
|
+
f"Method: {request_context.method} | URL: {request_context.url} | "
|
244
|
+
f"Query Parameters: {request_context.query_params} - "
|
243
245
|
f"Response | Status: 500 | Exception:\n{json.dumps(error_details, indent=4)}"
|
244
246
|
)
|
245
247
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from datetime import datetime, timezone
|
2
2
|
from uuid import UUID
|
3
|
-
from pydantic import BaseModel, Field
|
4
|
-
from typing import
|
3
|
+
from pydantic import BaseModel, Field
|
4
|
+
from typing import Optional
|
5
5
|
from .request import RequestContext
|
6
6
|
from .token import MaleoFoundationTokenGeneralTransfers
|
7
7
|
from maleo_foundation.types import BaseTypes
|
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from datetime import datetime, timezone
|
3
|
-
from pydantic import BaseModel, Field
|
3
|
+
from pydantic import BaseModel, Field, field_serializer
|
4
|
+
from starlette.datastructures import QueryParams
|
4
5
|
from typing import Dict, Any
|
5
6
|
from uuid import UUID
|
6
7
|
from maleo_foundation.types import BaseTypes
|
@@ -10,8 +11,8 @@ class RequestContext(BaseModel):
|
|
10
11
|
requested_at: datetime = Field(datetime.now(tz=timezone.utc), description="Request timestamp")
|
11
12
|
method: str = Field(..., description="Request's method")
|
12
13
|
url: str = Field(..., description="Request's URL")
|
13
|
-
path_params:
|
14
|
-
query_params:
|
14
|
+
path_params: BaseTypes.OptionalStringToAnyDict = Field(None, description="Request's path parameters")
|
15
|
+
query_params: BaseTypes.OptionalString = Field(None, description="Request's query parameters")
|
15
16
|
ip_address: str = Field("unknown", description="Client's IP address")
|
16
17
|
is_internal: BaseTypes.OptionalBoolean = Field(None, description="True if IP is internal")
|
17
18
|
user_agent: BaseTypes.OptionalString = Field(None, description="User-Agent string")
|
@@ -24,14 +25,21 @@ class RequestContext(BaseModel):
|
|
24
25
|
forwarded_proto: BaseTypes.OptionalString = Field(None, description="Forwarded protocol (http/https)")
|
25
26
|
language: BaseTypes.OptionalString = Field(None, description="Accepted languages from client")
|
26
27
|
|
28
|
+
class Config:
|
29
|
+
arbitrary_types_allowed = True
|
30
|
+
|
31
|
+
@field_serializer('query_params', when_used='json')
|
32
|
+
def serialize_query_params(self, qp: QueryParams, _info) -> str:
|
33
|
+
return str(qp)
|
34
|
+
|
27
35
|
def to_google_pubsub_object(self) -> Dict[str, Any]:
|
28
36
|
result = {
|
29
37
|
"request_id": str(self.request_id),
|
30
38
|
"requested_at": self.requested_at.isoformat(),
|
31
39
|
"method": self.method,
|
32
40
|
"url": self.url,
|
33
|
-
"path_params": {"map": self.path_params},
|
34
|
-
"query_params": {"
|
41
|
+
"path_params": None if self.path_params is None else {"map": self.path_params},
|
42
|
+
"query_params": None if self.query_params is None else {"string": self.query_params},
|
35
43
|
"ip_address": self.ip_address,
|
36
44
|
"is_internal": None if self.is_internal is None else {"boolean": self.is_internal},
|
37
45
|
"user_agent": None if self.user_agent is None else {"string": self.user_agent},
|
@@ -54,8 +62,8 @@ class RequestContext(BaseModel):
|
|
54
62
|
requested_at = datetime.fromisoformat(obj["requested_at"]),
|
55
63
|
method = obj["method"],
|
56
64
|
url = obj["url"],
|
57
|
-
path_params = obj["path_params"]["map"]
|
58
|
-
query_params = obj["query_params"]["
|
65
|
+
path_params = None if obj["path_params`"] is None else obj["path_params"]["map"],
|
66
|
+
query_params = None if obj["query_params"] is None else obj["query_params"]["string"],
|
59
67
|
ip_address = obj["ip_address"],
|
60
68
|
is_internal = None if obj["is_internal"] is None else bool(obj["is_internal"]["boolean"]),
|
61
69
|
user_agent = None if obj["user_agent"] is None else obj["user_agent"]["string"],
|
@@ -39,10 +39,10 @@ def extract_request_context(request: Request) -> RequestContext:
|
|
39
39
|
requested_at=datetime.now(tz=timezone.utc),
|
40
40
|
method=request.method,
|
41
41
|
url=request.url.path,
|
42
|
-
path_params=
|
43
|
-
query_params=
|
42
|
+
path_params=None if not request.path_params else request.path_params,
|
43
|
+
query_params=None if not request.query_params else str(request.query_params),
|
44
44
|
ip_address=ip_address,
|
45
|
-
is_internal=ip_address.startswith("10.") or ip_address.startswith("192.168.") or ip_address.startswith("172."),
|
45
|
+
is_internal=None if ip_address=="unknown" else (ip_address.startswith("10.") or ip_address.startswith("192.168.") or ip_address.startswith("172.")),
|
46
46
|
user_agent=headers.get("user-agent"),
|
47
47
|
ua_browser=ua_browser,
|
48
48
|
ua_mobile=headers.get("sec-ch-ua-mobile"),
|
@@ -2,7 +2,7 @@ maleo_foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
2
2
|
maleo_foundation/authentication.py,sha256=6Kw-cl9PlxPNc2nD7Z4sYug2_MhRas6IfyVygQyTHlc,1584
|
3
3
|
maleo_foundation/authorization.py,sha256=HGXCJ47AU1YFMDSmGhrMMmlHnAyghcFZVUiPa1FSvog,283
|
4
4
|
maleo_foundation/constants.py,sha256=JLQNTY5LJ0gjsT2aicNTRyi9hcOtk31ffFS6ywZXbZM,1449
|
5
|
-
maleo_foundation/enums.py,sha256=
|
5
|
+
maleo_foundation/enums.py,sha256=POXtnQq6i7DRlfSUvEOR2YxyViqjsILxucrBQuxlJ-c,5350
|
6
6
|
maleo_foundation/extended_types.py,sha256=pIKt-_9tby4rmune3fmWcCW_mohaNRh_1lywBmdc-L4,301
|
7
7
|
maleo_foundation/rest_controller_result.py,sha256=4KbCmk70IEHj1L1bNJfFg1Y3ifnRSnmvK6dYyVJddok,2014
|
8
8
|
maleo_foundation/types.py,sha256=bUcCR-qRlxxttMxJQnVmtBic3EXEd_urcC2P55evWPc,2451
|
@@ -32,9 +32,9 @@ maleo_foundation/expanded_types/encryption/__init__.py,sha256=yvqKW_VprQP_3YSL-A
|
|
32
32
|
maleo_foundation/expanded_types/encryption/aes.py,sha256=1rj43qjIO0TePpr1mErT_NJnqFZSgMM9gybfFxsTams,488
|
33
33
|
maleo_foundation/expanded_types/encryption/rsa.py,sha256=Esf_H8nMz2kOLAWa3M7dlD-sFdFIZylNjB_qB20Yaww,488
|
34
34
|
maleo_foundation/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
|
-
maleo_foundation/managers/db.py,sha256=
|
35
|
+
maleo_foundation/managers/db.py,sha256=y5oP3bTXKeXYKqng-E_HZ-3wC0ZPtl5bls0AEEej6zM,6050
|
36
36
|
maleo_foundation/managers/middleware.py,sha256=IjHPuOzXKEK44DqhJejJ6wXacAiUi9GwWAdeuwD0lI4,4271
|
37
|
-
maleo_foundation/managers/service.py,sha256=
|
37
|
+
maleo_foundation/managers/service.py,sha256=LwkDW2U8NRiMrZxtlA9xYx2uj23PBayKqJIaO9NzGpM,19727
|
38
38
|
maleo_foundation/managers/cache/__init__.py,sha256=CeY0oof2bVl_v5WS-FKXNwn2gf3xrEMfUsHK9cHo59s,471
|
39
39
|
maleo_foundation/managers/cache/base.py,sha256=oXxeMjw4iptFwvdESeYF0mgmEzoAzzCAQbnYwTO5tZ4,867
|
40
40
|
maleo_foundation/managers/cache/redis.py,sha256=LMxBNCmal6JjsAi7FTeN191PR1zFGw4jjfrJ9lJ_zu0,1162
|
@@ -47,7 +47,7 @@ maleo_foundation/managers/client/google/parameter.py,sha256=Jy-rMz_xhepmxBI2rWPx
|
|
47
47
|
maleo_foundation/managers/client/google/secret.py,sha256=m-mjaLvYMLgAEn1OxmP0IVTYFQi1jSpDdutLxNA6t6g,4620
|
48
48
|
maleo_foundation/managers/client/google/storage.py,sha256=lEPw4N07nV9r7KjvF2Pb3RM1ZQBK9Riqj7vh6XOEY5Q,5417
|
49
49
|
maleo_foundation/middlewares/authentication.py,sha256=PkC1mtI1LwX6iBTNvpFf-kxFNt6YkshWupM_lt7CaCI,4851
|
50
|
-
maleo_foundation/middlewares/base.py,sha256=
|
50
|
+
maleo_foundation/middlewares/base.py,sha256=IszulI930Fm4T4LQZJIyV8kebAlXt4joR6knB3QZUgA,16437
|
51
51
|
maleo_foundation/middlewares/cors.py,sha256=9hLh_h253bvIn7-A7mUblyrJQ37XNpV7aLeHW6ZTHz8,2294
|
52
52
|
maleo_foundation/models/__init__.py,sha256=AaKehO7c1HyKhoTGRmNHDddSeBXkW-_YNrpOGBu8Ms8,246
|
53
53
|
maleo_foundation/models/responses.py,sha256=rhCQ9ERe1BgM2Bx7c4_Qj0Eoq7bJG0xdbnhCiTao6eI,5668
|
@@ -63,9 +63,9 @@ maleo_foundation/models/schemas/signature.py,sha256=pP78JZpoizQguVKXv4AXQmB8ebVy
|
|
63
63
|
maleo_foundation/models/schemas/token.py,sha256=Ay-ntAiKeBjCT4YYw0S3Zd4e-KvHSYvG_hzCMYzd5qY,567
|
64
64
|
maleo_foundation/models/transfers/__init__.py,sha256=oJLJ3Geeme6vBw7R2Dhvdvg4ziVvzEYAGJaP-tm_90w,299
|
65
65
|
maleo_foundation/models/transfers/general/__init__.py,sha256=rzHpxhyNphl5RVrsAlzEvuYEonmWgb69gJ8XOLMvFDc,4686
|
66
|
-
maleo_foundation/models/transfers/general/database.py,sha256=
|
66
|
+
maleo_foundation/models/transfers/general/database.py,sha256=LEMhHNmqoT7zhZisdI0ZEmFX8zENWUKfcQ4FJsAfr8E,1956
|
67
67
|
maleo_foundation/models/transfers/general/key.py,sha256=S37SqD3qwTbgMk7785hW7Kl9d4Kouh4uPZcGoyMQ_-Q,755
|
68
|
-
maleo_foundation/models/transfers/general/request.py,sha256=
|
68
|
+
maleo_foundation/models/transfers/general/request.py,sha256=NTYFOmucc4bMfoocBeHGNLs6mbRdqXyVtp1_yDiv_Gg,4849
|
69
69
|
maleo_foundation/models/transfers/general/signature.py,sha256=J9xQy2HjpCQOnES7RJqsUnDgjFPuakQ1mxyfdTdstSE,297
|
70
70
|
maleo_foundation/models/transfers/general/token.py,sha256=PU-_wLFaY2i8pwRi9-jlk4nh7XzoTKOk0BEsUCGbD80,4979
|
71
71
|
maleo_foundation/models/transfers/parameters/__init__.py,sha256=oKW4RPIEISISRjsJzD8lsCGY1HhZRTzshPpWHcJu86k,353
|
@@ -104,7 +104,7 @@ maleo_foundation/utils/cleaner.py,sha256=dv80jDd8uAXuqyB5_UPbT2JksJ-hsq286DB2WCj
|
|
104
104
|
maleo_foundation/utils/client.py,sha256=CGwn8eH5WlwnE5tPMfMAH5V3BItBgVmYBZnXpLjTVSc,2826
|
105
105
|
maleo_foundation/utils/controller.py,sha256=Ub1R-JN6spmXakYrOY7igwaNt4Sg8LASASdXymxZcCI,6954
|
106
106
|
maleo_foundation/utils/exceptions.py,sha256=z24kzEP2geaAEElxXaEy7ln6KodebXvtlu-h1inZ_nw,6376
|
107
|
-
maleo_foundation/utils/extractor.py,sha256=
|
107
|
+
maleo_foundation/utils/extractor.py,sha256=ZNX0sQKcUwwh7paUZpdR04a18s8Ru2xNXhWZl-XN3l4,2197
|
108
108
|
maleo_foundation/utils/logging.py,sha256=yXo2ztzt5PBEtyPR8OtYhz5Ob5uwDVwa9wpbxnh_pys,7827
|
109
109
|
maleo_foundation/utils/merger.py,sha256=MdocyCOtIhqjcmqx2mJ0V8vtwsrunRXqhRdrBCruh7Q,622
|
110
110
|
maleo_foundation/utils/query.py,sha256=hhISpBAZ4SV_pGf7uGBC6fzLrs_yj5_8gj-kFFeeNrw,8060
|
@@ -122,7 +122,7 @@ maleo_foundation/utils/loaders/credential/__init__.py,sha256=qopTKvcMVoTFwyRijeg
|
|
122
122
|
maleo_foundation/utils/loaders/credential/google.py,sha256=yEL0DIVjiKSlZOxogC5pr_NAdWth9dj_ZatLjRsutIk,1269
|
123
123
|
maleo_foundation/utils/loaders/key/__init__.py,sha256=hVygcC2ImHc_aVrSrOmyedR8tMUZokWUKCKOSh5ctbo,106
|
124
124
|
maleo_foundation/utils/loaders/key/rsa.py,sha256=gDhyX6iTFtHiluuhFCozaZ3pOLKU2Y9TlrNMK_GVyGU,3796
|
125
|
-
maleo_foundation-0.
|
126
|
-
maleo_foundation-0.
|
127
|
-
maleo_foundation-0.
|
128
|
-
maleo_foundation-0.
|
125
|
+
maleo_foundation-0.3.1.dist-info/METADATA,sha256=7ZpZo-lRgi3r6lL7pMtWUQPrRcP8yn6rNlqKR5KKRY8,3597
|
126
|
+
maleo_foundation-0.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
127
|
+
maleo_foundation-0.3.1.dist-info/top_level.txt,sha256=_iBos3F_bhEOdjOnzeiEYSrCucasc810xXtLBXI8cQc,17
|
128
|
+
maleo_foundation-0.3.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|