maleo-foundation 0.0.77__tar.gz → 0.0.79__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.
Files changed (68) hide show
  1. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/PKG-INFO +1 -1
  2. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/general/http.py +12 -3
  3. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/enums.py +9 -1
  4. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/schemas/general.py +2 -40
  5. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/__init__.py +2 -0
  6. maleo_foundation-0.0.79/maleo_foundation/models/transfers/general/__init__.py +5 -0
  7. maleo_foundation-0.0.79/maleo_foundation/models/transfers/general/token.py +44 -0
  8. maleo_foundation-0.0.79/maleo_foundation/utils/keyloader.py +65 -0
  9. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation.egg-info/PKG-INFO +1 -1
  10. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation.egg-info/SOURCES.txt +3 -0
  11. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/pyproject.toml +1 -1
  12. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/README.md +0 -0
  13. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/__init__.py +0 -0
  14. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/__init__.py +0 -0
  15. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/general/__init__.py +0 -0
  16. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/google/__init__.py +0 -0
  17. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/google/cloud/__init__.py +0 -0
  18. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/google/cloud/logging.py +0 -0
  19. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/google/cloud/secret.py +0 -0
  20. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/google/cloud/storage.py +0 -0
  21. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/utils/__init__.py +0 -0
  22. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/clients/utils/logger.py +0 -0
  23. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/constants.py +0 -0
  24. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/db/__init__.py +0 -0
  25. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/db/engine.py +0 -0
  26. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/db/manager.py +0 -0
  27. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/db/session.py +0 -0
  28. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/db/table.py +0 -0
  29. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/expanded_types/__init__.py +0 -0
  30. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/expanded_types/client.py +0 -0
  31. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/expanded_types/general.py +0 -0
  32. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/expanded_types/query.py +0 -0
  33. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/expanded_types/service.py +0 -0
  34. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/extended_types.py +0 -0
  35. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/middlewares/__init__.py +0 -0
  36. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/middlewares/base.py +0 -0
  37. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/middlewares/cors.py +0 -0
  38. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/__init__.py +0 -0
  39. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/responses.py +0 -0
  40. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/schemas/__init__.py +0 -0
  41. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/schemas/parameter.py +0 -0
  42. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/schemas/result.py +0 -0
  43. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/parameters/__init__.py +0 -0
  44. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/parameters/client.py +0 -0
  45. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/parameters/general.py +0 -0
  46. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/parameters/service.py +0 -0
  47. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/__init__.py +0 -0
  48. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/client/__init__.py +0 -0
  49. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/client/controllers/__init__.py +0 -0
  50. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/client/controllers/http.py +0 -0
  51. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/client/service.py +0 -0
  52. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/service/__init__.py +0 -0
  53. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/service/controllers/__init__.py +0 -0
  54. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/service/controllers/rest.py +0 -0
  55. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/service/general.py +0 -0
  56. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/models/transfers/results/service/query.py +0 -0
  57. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/types.py +0 -0
  58. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/__init__.py +0 -0
  59. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/controller.py +0 -0
  60. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/exceptions.py +0 -0
  61. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/formatter/__init__.py +0 -0
  62. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/formatter/case.py +0 -0
  63. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/logger.py +0 -0
  64. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation/utils/query.py +0 -0
  65. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation.egg-info/dependency_links.txt +0 -0
  66. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation.egg-info/requires.txt +0 -0
  67. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/maleo_foundation.egg-info/top_level.txt +0 -0
  68. {maleo_foundation-0.0.77 → maleo_foundation-0.0.79}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.0.77
3
+ Version: 0.0.79
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -4,6 +4,7 @@ from typing import AsyncGenerator, Optional
4
4
 
5
5
  class HTTPClientManager:
6
6
  client:Optional[httpx.AsyncClient] = None
7
+ base_url:Optional[str] = None
7
8
 
8
9
  @classmethod
9
10
  def initialize(cls) -> None:
@@ -20,12 +21,12 @@ class HTTPClientManager:
20
21
  yield cls.client
21
22
 
22
23
  @classmethod
23
- async def inject(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
24
+ async def inject_client(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
24
25
  return cls._client_handler()
25
26
 
26
27
  @classmethod
27
28
  @asynccontextmanager
28
- async def get(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
29
+ async def get_client(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
29
30
  """
30
31
  Async context manager for manual HTTP client handling.
31
32
  Supports `async with HTTPClientManager.get() as client:`
@@ -33,9 +34,17 @@ class HTTPClientManager:
33
34
  async for client in cls._client_handler():
34
35
  yield client
35
36
 
37
+ @classmethod
38
+ def get_url(cls) -> str:
39
+ if cls.base_url is None:
40
+ raise RuntimeError("Base URL has not been initialized. Call initialize first.")
41
+ return cls.base_url
42
+
36
43
  @classmethod
37
44
  async def dispose(cls) -> None:
38
45
  """Dispose of the HTTP client and release any resources."""
39
46
  if cls.client is not None:
40
47
  await cls.client.aclose()
41
- cls.client = None
48
+ cls.client = None
49
+ if cls.base_url is not None:
50
+ cls.base_url = None
@@ -1,5 +1,5 @@
1
1
  import logging
2
- from enum import IntEnum, StrEnum
2
+ from enum import IntEnum, StrEnum, Enum
3
3
  from fastapi import responses
4
4
 
5
5
  class BaseEnums:
@@ -40,6 +40,14 @@ class BaseEnums:
40
40
  class ClientControllerType(StrEnum):
41
41
  HTTP = "http"
42
42
 
43
+ class KeyType(StrEnum):
44
+ PRIVATE = "private"
45
+ PUBLIC = "public"
46
+
47
+ class KeyFormatType(Enum):
48
+ BYTES = bytes
49
+ STRING = str
50
+
43
51
  class RESTControllerResponseType(StrEnum):
44
52
  NONE = "none"
45
53
  HTML = "html"
@@ -1,8 +1,7 @@
1
1
  from __future__ import annotations
2
- from datetime import datetime, timedelta, timezone
3
- from pydantic import BaseModel, Field, model_validator
2
+ from datetime import datetime
3
+ from pydantic import BaseModel, Field
4
4
  from uuid import UUID
5
- from maleo_foundation.constants import REFRESH_TOKEN_DURATION_DAYS, ACCESS_TOKEN_DURATION_MINUTES
6
5
  from maleo_foundation.enums import BaseEnums
7
6
  from maleo_foundation.types import BaseTypes
8
7
 
@@ -81,42 +80,5 @@ class BaseGeneralSchemas:
81
80
  class Secret(BaseModel):
82
81
  secret:UUID = Field(..., description="Data's secret")
83
82
 
84
- class TokenPayload(BaseModel):
85
- t:BaseEnums.TokenType = Field(..., description="Token Type")
86
- sr:UUID = Field(..., description="System role")
87
- u:UUID = Field(..., description="user")
88
- o:BaseTypes.OptionalUUID = Field(..., description="Organization")
89
- uor:BaseTypes.OptionalListOfUUIDs = Field(..., description="User Organization Role")
90
- iat_dt:datetime = Field(datetime.now(timezone.utc), description="Issued at (datetime)")
91
- iat:int = Field(None, description="Issued at (integer)")
92
- exp_dt:datetime = Field(None, description="Expired at (datetime)")
93
- exp:int = Field(None, description="Expired at (integet)")
94
-
95
- @model_validator(mode="before")
96
- @classmethod
97
- def set_iat_and_exp(cls, values:dict):
98
- iat_dt = values.get("iat_dt", None)
99
- if not iat_dt:
100
- iat_dt = datetime.now(timezone.utc)
101
- else:
102
- if not isinstance(iat_dt, datetime):
103
- iat_dt = datetime.fromisoformat(iat_dt)
104
- values["iat_dt"] = iat_dt
105
- #* Convert `iat` to timestamp (int)
106
- values["iat"] = int(iat_dt.timestamp())
107
- exp_dt = values.get("exp_dt", None)
108
- if not exp_dt:
109
- if values["t"] == BaseEnums.TokenType.REFRESH:
110
- exp_dt = iat_dt + timedelta(days=REFRESH_TOKEN_DURATION_DAYS)
111
- elif values["t"] == BaseEnums.TokenType.ACCESS:
112
- exp_dt = iat_dt + timedelta(minutes=ACCESS_TOKEN_DURATION_MINUTES)
113
- else:
114
- if not isinstance(exp_dt, datetime):
115
- exp_dt = datetime.fromisoformat(exp_dt)
116
- values["exp_dt"] = exp_dt
117
- #* Convert `exp_dt` to timestamp (int)
118
- values["exp"] = int(exp_dt.timestamp())
119
- return values
120
-
121
83
  class Data(BaseModel):
122
84
  data:BaseTypes.StringToAnyDict = Field(..., description="Data")
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
+ from .general import BaseGeneralTransfers
2
3
  from .parameters import BaseParametersTransfers
3
4
  from .results import BaseResultsTransfers
4
5
 
5
6
  class BaseTransfers:
7
+ General = BaseGeneralTransfers
6
8
  Parameters = BaseParametersTransfers
7
9
  Results = BaseResultsTransfers
@@ -0,0 +1,5 @@
1
+ from __future__ import annotations
2
+ from .token import BaseTokenGeneralTransfers
3
+
4
+ class BaseGeneralTransfers:
5
+ Token = BaseTokenGeneralTransfers
@@ -0,0 +1,44 @@
1
+ from pydantic import BaseModel, Field, model_validator
2
+ from datetime import datetime, timedelta, timezone
3
+ from maleo_foundation.types import BaseTypes
4
+
5
+ class BaseTokenGeneralTransfers:
6
+ class DecodePayload(BaseModel):
7
+ sr:str = Field(..., description="System role")
8
+ u_u:str = Field(..., description="user's username")
9
+ u_e:str = Field(..., description="user's email")
10
+ u_ut:str = Field(..., description="user's type")
11
+ o:BaseTypes.OptionalString = Field(..., description="Organization's key")
12
+ o_ot:BaseTypes.OptionalString = Field(..., description="Organization's type")
13
+ uor:BaseTypes.OptionalListOfStrings = Field(..., description="User Organization Role")
14
+ iat_dt:datetime = Field(datetime.now(timezone.utc), description="Issued at (datetime)")
15
+ iat:int = Field(..., description="Issued at (integer)")
16
+ exp_dt:datetime = Field(..., description="Expired at (datetime)")
17
+ exp:int = Field(..., description="Expired at (integet)")
18
+
19
+ class EncodePayload(DecodePayload):
20
+ exp_in:int = Field(5, ge=5, description="Expires in (integer, minutes)", exclude=True)
21
+
22
+ @model_validator(mode="before")
23
+ @classmethod
24
+ def set_iat_and_exp(cls, values:dict):
25
+ iat_dt = values.get("iat_dt", None)
26
+ if not iat_dt:
27
+ iat_dt = datetime.now(timezone.utc)
28
+ else:
29
+ if not isinstance(iat_dt, datetime):
30
+ iat_dt = datetime.fromisoformat(iat_dt)
31
+ values["iat_dt"] = iat_dt
32
+ #* Convert `iat` to timestamp (int)
33
+ values["iat"] = int(iat_dt.timestamp())
34
+ exp_in = values.get("exp_in")
35
+ exp_dt = values.get("exp_dt", None)
36
+ if not exp_dt:
37
+ exp_dt = iat_dt + timedelta(minutes=exp_in)
38
+ else:
39
+ if not isinstance(exp_dt, datetime):
40
+ exp_dt = datetime.fromisoformat(exp_dt)
41
+ values["exp_dt"] = exp_dt
42
+ #* Convert `exp_dt` to timestamp (int)
43
+ values["exp"] = int(exp_dt.timestamp())
44
+ return values
@@ -0,0 +1,65 @@
1
+ import pathlib
2
+ from cryptography.hazmat.primitives import serialization
3
+ from typing import Union
4
+ from maleo_foundation.enums import BaseEnums
5
+
6
+ def load_key(
7
+ type:BaseEnums.KeyType,
8
+ path: Union[str, pathlib.Path],
9
+ password:Union[str, bytes, None] = None,
10
+ format:BaseEnums.KeyFormatType = BaseEnums.KeyFormatType.STRING,
11
+ ) -> Union[bytes, str]:
12
+ """
13
+ Load an RSA private or public key strictly from a file.
14
+
15
+ Args:
16
+ path (str | pathlib.Path): Path to the PEM file.
17
+ password (str | bytes | None): Password for encrypted private keys (optional).
18
+
19
+ Returns:
20
+ rsa.RSAPrivateKey | rsa.RSAPublicKey
21
+ """
22
+ if not isinstance(type, BaseEnums.KeyType):
23
+ raise TypeError("Invalid key type")
24
+
25
+ file_path = pathlib.Path(path)
26
+
27
+ if not file_path.is_file():
28
+ raise FileNotFoundError(f"Key file not found: {file_path}")
29
+
30
+ if not isinstance(password, (str, bytes, None)):
31
+ raise TypeError("Invalid passsword type")
32
+
33
+ if not isinstance(type, BaseEnums.KeyFormatType):
34
+ raise TypeError("Invalid key format type")
35
+
36
+ key_data = file_path.read_bytes()
37
+
38
+ if type == BaseEnums.KeyType.PRIVATE:
39
+ private_key = serialization.load_pem_private_key(
40
+ key_data,
41
+ password=password.encode() if isinstance(password, str) else password,
42
+ )
43
+ private_key_bytes = private_key.private_bytes(
44
+ encoding=serialization.Encoding.PEM,
45
+ format=serialization.PrivateFormat.PKCS8,
46
+ encryption_algorithm=serialization.NoEncryption()
47
+ )
48
+ if format == BaseEnums.KeyFormatType.BYTES:
49
+ return private_key_bytes
50
+ elif format == BaseEnums.KeyFormatType.STRING:
51
+ return private_key_bytes.decode()
52
+
53
+ elif type == BaseEnums.KeyType.PUBLIC:
54
+ public_key = serialization.load_pem_public_key(key_data)
55
+ public_key_bytes = public_key.public_bytes(
56
+ encoding=serialization.Encoding.PEM,
57
+ format=serialization.PublicFormat.SubjectPublicKeyInfo
58
+ )
59
+ if format == BaseEnums.KeyFormatType.BYTES:
60
+ return public_key_bytes
61
+ elif format == BaseEnums.KeyFormatType.STRING:
62
+ return public_key_bytes.decode()
63
+
64
+ else:
65
+ raise ValueError(f"Unsupported key type: {type}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.0.77
3
+ Version: 0.0.79
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -40,6 +40,8 @@ maleo_foundation/models/schemas/general.py
40
40
  maleo_foundation/models/schemas/parameter.py
41
41
  maleo_foundation/models/schemas/result.py
42
42
  maleo_foundation/models/transfers/__init__.py
43
+ maleo_foundation/models/transfers/general/__init__.py
44
+ maleo_foundation/models/transfers/general/token.py
43
45
  maleo_foundation/models/transfers/parameters/__init__.py
44
46
  maleo_foundation/models/transfers/parameters/client.py
45
47
  maleo_foundation/models/transfers/parameters/general.py
@@ -57,6 +59,7 @@ maleo_foundation/models/transfers/results/service/controllers/rest.py
57
59
  maleo_foundation/utils/__init__.py
58
60
  maleo_foundation/utils/controller.py
59
61
  maleo_foundation/utils/exceptions.py
62
+ maleo_foundation/utils/keyloader.py
60
63
  maleo_foundation/utils/logger.py
61
64
  maleo_foundation/utils/query.py
62
65
  maleo_foundation/utils/formatter/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maleo_foundation"
7
- version = "0.0.77"
7
+ version = "0.0.79"
8
8
  description = "Foundation package for Maleo"
9
9
  authors = [
10
10
  { name = "Agra Bima Yuda", email = "agra@nexmedis.com" }