maleo-foundation 0.2.20__tar.gz → 0.2.21__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 (126) hide show
  1. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/PKG-INFO +6 -1
  2. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/enums.py +20 -1
  3. maleo_foundation-0.2.21/maleo_foundation/managers/cache/__init__.py +15 -0
  4. maleo_foundation-0.2.21/maleo_foundation/managers/cache/redis.py +20 -0
  5. maleo_foundation-0.2.21/maleo_foundation/managers/client/google/parameter.py +33 -0
  6. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/service.py +35 -0
  7. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/service/__init__.py +2 -0
  8. maleo_foundation-0.2.21/maleo_foundation/models/transfers/results/service/repository.py +51 -0
  9. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/exceptions.py +73 -0
  10. maleo_foundation-0.2.21/maleo_foundation/utils/repository.py +61 -0
  11. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation.egg-info/PKG-INFO +6 -1
  12. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation.egg-info/SOURCES.txt +5 -0
  13. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation.egg-info/requires.txt +5 -0
  14. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/pyproject.toml +6 -1
  15. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/README.md +0 -0
  16. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/__init__.py +0 -0
  17. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/authentication.py +0 -0
  18. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/authorization.py +0 -0
  19. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/__init__.py +0 -0
  20. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/manager.py +0 -0
  21. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/__init__.py +0 -0
  22. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/encryption/__init__.py +0 -0
  23. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/encryption/aes.py +0 -0
  24. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/encryption/rsa.py +0 -0
  25. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/hash/__init__.py +0 -0
  26. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/hash/bcrypt.py +0 -0
  27. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/hash/hmac.py +0 -0
  28. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/hash/sha256.py +0 -0
  29. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/key.py +0 -0
  30. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/signature.py +0 -0
  31. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/client/services/token.py +0 -0
  32. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/constants.py +0 -0
  33. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/__init__.py +0 -0
  34. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/client.py +0 -0
  35. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/encryption/__init__.py +0 -0
  36. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/encryption/aes.py +0 -0
  37. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/encryption/rsa.py +0 -0
  38. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/general.py +0 -0
  39. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/hash.py +0 -0
  40. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/key.py +0 -0
  41. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/query.py +0 -0
  42. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/service.py +0 -0
  43. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/signature.py +0 -0
  44. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/expanded_types/token.py +0 -0
  45. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/extended_types.py +0 -0
  46. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/__init__.py +0 -0
  47. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/__init__.py +0 -0
  48. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/base.py +0 -0
  49. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/google/__init__.py +0 -0
  50. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/google/base.py +0 -0
  51. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/google/secret.py +0 -0
  52. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/google/storage.py +0 -0
  53. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/client/maleo.py +0 -0
  54. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/db.py +0 -0
  55. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/managers/middleware.py +0 -0
  56. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/middlewares/authentication.py +0 -0
  57. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/middlewares/base.py +0 -0
  58. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/middlewares/cors.py +0 -0
  59. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/__init__.py +0 -0
  60. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/responses.py +0 -0
  61. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/__init__.py +0 -0
  62. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/encryption.py +0 -0
  63. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/general.py +0 -0
  64. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/hash.py +0 -0
  65. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/key.py +0 -0
  66. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/parameter.py +0 -0
  67. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/result.py +0 -0
  68. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/signature.py +0 -0
  69. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/schemas/token.py +0 -0
  70. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/table.py +0 -0
  71. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/__init__.py +0 -0
  72. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/general/__init__.py +0 -0
  73. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/general/key.py +0 -0
  74. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/general/signature.py +0 -0
  75. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/general/token.py +0 -0
  76. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/__init__.py +0 -0
  77. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/client.py +0 -0
  78. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/encryption/__init__.py +0 -0
  79. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/encryption/aes.py +0 -0
  80. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/encryption/rsa.py +0 -0
  81. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/general.py +0 -0
  82. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/hash/__init__.py +0 -0
  83. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/hash/bcrypt.py +0 -0
  84. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/hash/hmac.py +0 -0
  85. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/hash/sha256.py +0 -0
  86. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/key.py +0 -0
  87. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/service.py +0 -0
  88. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/signature.py +0 -0
  89. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/parameters/token.py +0 -0
  90. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/__init__.py +0 -0
  91. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/client/__init__.py +0 -0
  92. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/client/controllers/__init__.py +0 -0
  93. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/client/controllers/http.py +0 -0
  94. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/client/service.py +0 -0
  95. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/encryption/__init__.py +0 -0
  96. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/encryption/aes.py +0 -0
  97. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/encryption/rsa.py +0 -0
  98. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/hash.py +0 -0
  99. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/key.py +0 -0
  100. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/service/controllers/__init__.py +0 -0
  101. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/service/controllers/rest.py +0 -0
  102. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/service/general.py +0 -0
  103. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/service/query.py +0 -0
  104. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/signature.py +0 -0
  105. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/models/transfers/results/token.py +0 -0
  106. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/types.py +0 -0
  107. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/__init__.py +0 -0
  108. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/controller.py +0 -0
  109. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/dependencies/__init__.py +0 -0
  110. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/dependencies/auth.py +0 -0
  111. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/extractor.py +0 -0
  112. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/formatter/__init__.py +0 -0
  113. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/formatter/case.py +0 -0
  114. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/__init__.py +0 -0
  115. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/credential/__init__.py +0 -0
  116. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/credential/google.py +0 -0
  117. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/json.py +0 -0
  118. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/key/__init__.py +0 -0
  119. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/key/rsa.py +0 -0
  120. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/loaders/yaml.py +0 -0
  121. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/logging.py +0 -0
  122. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/mergers.py +0 -0
  123. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation/utils/query.py +0 -0
  124. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation.egg-info/dependency_links.txt +0 -0
  125. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/maleo_foundation.egg-info/top_level.txt +0 -0
  126. {maleo_foundation-0.2.20 → maleo_foundation-0.2.21}/setup.cfg +0 -0
@@ -1,13 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.2.20
3
+ Version: 0.2.21
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
7
7
  Requires-Python: >=3.7
8
8
  Description-Content-Type: text/markdown
9
+ Requires-Dist: aiocache>=0.12.3
10
+ Requires-Dist: aioredis>=2.0.1
9
11
  Requires-Dist: annotated-types>=0.7.0
10
12
  Requires-Dist: anyio>=4.9.0
13
+ Requires-Dist: async-timeout>=5.0.1
11
14
  Requires-Dist: bcrypt>=4.3.0
12
15
  Requires-Dist: build>=1.2.2.post1
13
16
  Requires-Dist: cachetools>=5.5.2
@@ -25,6 +28,7 @@ Requires-Dist: google-cloud-appengine-logging>=1.6.1
25
28
  Requires-Dist: google-cloud-audit-log>=0.3.2
26
29
  Requires-Dist: google-cloud-core>=2.4.3
27
30
  Requires-Dist: google-cloud-logging>=3.12.0
31
+ Requires-Dist: google-cloud-parametermanager>=0.1.3
28
32
  Requires-Dist: google-cloud-secret-manager>=2.23.3
29
33
  Requires-Dist: google-cloud-storage>=2.19.0
30
34
  Requires-Dist: google-crc32c>=1.7.1
@@ -66,6 +70,7 @@ Requires-Dist: pyproject_hooks>=1.2.0
66
70
  Requires-Dist: python-dotenv>=1.1.0
67
71
  Requires-Dist: PyYAML>=6.0.2
68
72
  Requires-Dist: readme_renderer>=44.0
73
+ Requires-Dist: redis>=6.1.0
69
74
  Requires-Dist: requests>=2.32.3
70
75
  Requires-Dist: requests-toolbelt>=1.0.0
71
76
  Requires-Dist: rfc3986>=2.0.0
@@ -100,4 +100,23 @@ class BaseEnums:
100
100
  WARN = logging.WARN
101
101
  INFO = logging.INFO
102
102
  DEBUG = logging.DEBUG
103
- NOTSET = logging.NOTSET
103
+ NOTSET = logging.NOTSET
104
+
105
+ class CacheType(StrEnum):
106
+ SERVICE = "service"
107
+ CLIENT = "client"
108
+
109
+ class CacheTTL(IntEnum):
110
+ TTL_15SC = int(15)
111
+ TTL_30SC = int(30)
112
+ TTL_1MN = int(1*60)
113
+ TTL_5MN = int(5*60)
114
+ TTL_10MN = int(10*60)
115
+ TTL_30MN = int(30*60)
116
+ TTL_1HR = int(1*60*60)
117
+ TTL_6HR = int(6*60*60)
118
+ TTL_12HR = int(12*60*60)
119
+ TTL_1DY = int(1*24*60*60)
120
+ TTL_7DY = int(7*24*60*60)
121
+ TTL_1WK = int(1*24*60*60)
122
+ TTL_7WK = int(7*24*60*60)
@@ -0,0 +1,15 @@
1
+ from __future__ import annotations
2
+ from pydantic import BaseModel, Field
3
+ from redis.asyncio.client import Redis
4
+ from .redis import RedisCacheConfigurations
5
+
6
+ SKIP_CACHE_FUNC = lambda x: x is None
7
+
8
+ class CacheConfigurations(BaseModel):
9
+ redis:RedisCacheConfigurations = Field(..., description="Redis cache's configurations")
10
+
11
+ class CacheManagers(BaseModel):
12
+ redis:Redis = Field(..., description="Redis client")
13
+
14
+ class Config:
15
+ arbitrary_types_allowed=True
@@ -0,0 +1,20 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import Union
3
+ from maleo_foundation.types import BaseTypes
4
+ from maleo_foundation.enums import BaseEnums
5
+
6
+ class RedisCacheNamespaces(BaseModel):
7
+ base:str = Field(..., description="Base's redis namespace")
8
+
9
+ def create(self, type:BaseEnums.CacheType, *ext:str) -> str:
10
+ return "::".join([self.base, type, *ext])
11
+
12
+ class RedisCacheConfigurations(BaseModel):
13
+ ttl:Union[int, float] = Field(BaseEnums.CacheTTL.TTL_5MN, description="Default TTL")
14
+ namespaces:RedisCacheNamespaces = Field(..., description="Redis cache's namepsaces")
15
+ host:str = Field(..., description="Redis instance's host")
16
+ port:int = Field(6379, description="Redis instance's port")
17
+ db:int = Field(0, description="Redis instance's db")
18
+ password:BaseTypes.OptionalString = Field(None, description="AUTH password")
19
+ decode_responses:bool = Field(False, description="Whether to decode responses")
20
+ health_check_interval:int = Field(30, description="Health check interval")
@@ -0,0 +1,33 @@
1
+ from google.api_core import retry
2
+ from google.api_core.exceptions import NotFound
3
+ from google.cloud import parametermanager
4
+ from google.oauth2.service_account import Credentials
5
+ from pathlib import Path
6
+ from typing import Optional, Union
7
+ from maleo_foundation.types import BaseTypes
8
+ from maleo_foundation.utils.logging import SimpleConfig
9
+ from .base import GoogleClientManager
10
+
11
+ class GoogleParameterManager(GoogleClientManager):
12
+ def __init__(
13
+ self,
14
+ log_config:SimpleConfig,
15
+ service_key:BaseTypes.OptionalString=None,
16
+ credentials:Optional[Credentials]=None,
17
+ credentials_path:Optional[Union[Path, str]]=None
18
+ ) -> None:
19
+ key = "google-parameter-manager"
20
+ name = "GoogleParameterManager"
21
+ super().__init__(key, name, log_config, service_key, credentials, credentials_path)
22
+ self._client = parametermanager.ParameterManagerClient(credentials=self._credentials)
23
+ self._logger.info("Client manager initialized successfully")
24
+
25
+ @property
26
+ def client(self) -> parametermanager.ParameterManagerClient:
27
+ return self._client
28
+
29
+ def dispose(self) -> None:
30
+ if self._client is not None:
31
+ self._logger.info("Disposing client manager")
32
+ self._client = None
33
+ self._logger.info("Client manager disposed successfully")
@@ -4,6 +4,7 @@ from google.oauth2.service_account import Credentials
4
4
  from pathlib import Path
5
5
  from pydantic_settings import BaseSettings
6
6
  from pydantic import BaseModel, Field
7
+ from redis.asyncio.client import Redis
7
8
  from starlette.exceptions import HTTPException
8
9
  from starlette.types import Lifespan, AppType
9
10
  from sqlalchemy import MetaData
@@ -15,6 +16,11 @@ from maleo_foundation.models.transfers.general.token \
15
16
  import MaleoFoundationTokenGeneralTransfers
16
17
  from maleo_foundation.models.transfers.parameters.token \
17
18
  import MaleoFoundationTokenParametersTransfers
19
+ from maleo_foundation.managers.cache import CacheConfigurations, CacheManagers
20
+ from maleo_foundation.managers.cache.redis import (
21
+ RedisCacheNamespaces,
22
+ RedisCacheConfigurations
23
+ )
18
24
  from maleo_foundation.managers.db import DatabaseConfigurations, DatabaseManager
19
25
  from maleo_foundation.managers.client.google.secret import GoogleSecretManager
20
26
  from maleo_foundation.managers.client.google.storage import GoogleCloudStorage
@@ -114,6 +120,7 @@ class StaticConfigurations(BaseModel):
114
120
  class Configurations(BaseModel):
115
121
  service:ServiceConfigurations = Field(..., description="Service's configurations")
116
122
  middleware:MiddlewareConfigurations = Field(..., description="Middleware's configurations")
123
+ cache:CacheConfigurations = Field(..., description="Cache's configurations")
117
124
  database:DatabaseConfigurations = Field(..., description="Database's configurations")
118
125
  client:ClientConfigurations = Field(..., description="Client's configurations")
119
126
 
@@ -148,6 +155,7 @@ class ServiceManager:
148
155
  self._load_configs()
149
156
  self._load_keys()
150
157
  self._initialize_loggers()
158
+ self._initialize_cache()
151
159
  self._initialize_db()
152
160
  self._initialize_foundation()
153
161
 
@@ -234,6 +242,13 @@ class ServiceManager:
234
242
  runtime_configurations = YAMLLoader.load_from_string(data)
235
243
  runtime_configs = RuntimeConfigurations.model_validate(runtime_configurations)
236
244
 
245
+ #* Load redis cache configurations
246
+ namespaces = RedisCacheNamespaces(base=self._settings.SERVICE_KEY)
247
+ host = self._secret_manager.get(name=f"maleo-redis-host-{self._settings.ENVIRONMENT}")
248
+ password = self._secret_manager.get(name=f"maleo-redis-password-{self._settings.ENVIRONMENT}")
249
+ redis = RedisCacheConfigurations(namespaces=namespaces, host=host, password=password)
250
+ cache = CacheConfigurations(redis=redis)
251
+
237
252
  #* Load database configurations
238
253
  password = self._secret_manager.get(name=f"maleo-db-password-{self._settings.ENVIRONMENT}")
239
254
  host = self._secret_manager.get(name=f"maleo-db-host-{self._settings.ENVIRONMENT}")
@@ -247,6 +262,7 @@ class ServiceManager:
247
262
  merged_configs = BaseMergers.deep_merge(
248
263
  static_configs.model_dump(),
249
264
  runtime_configs.model_dump(exclude={"database"}),
265
+ {"cache": cache.model_dump()},
250
266
  {"database": database.model_dump()}
251
267
  )
252
268
  self._configs = Configurations.model_validate(merged_configs)
@@ -303,6 +319,25 @@ class ServiceManager:
303
319
  def loggers(self) -> Loggers:
304
320
  return self._loggers
305
321
 
322
+ def _initialize_cache(self) -> None:
323
+ self._redis = Redis(
324
+ host=self._configs.cache.redis.host,
325
+ port=self._configs.cache.redis.port,
326
+ db=self._configs.cache.redis.db,
327
+ password=self._configs.cache.redis.password,
328
+ decode_responses=self._configs.cache.redis.decode_responses,
329
+ health_check_interval=self._configs.cache.redis.health_check_interval
330
+ )
331
+ self._cache = CacheManagers(redis=self._redis)
332
+
333
+ @property
334
+ def redis(self) -> Redis:
335
+ return self._redis
336
+
337
+ @property
338
+ def cache(self) -> CacheManagers:
339
+ return self._cache
340
+
306
341
  def _initialize_db(self) -> None:
307
342
  self._database = DatabaseManager(
308
343
  metadata=self._db_metadata,
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
2
  from .general import BaseServiceGeneralResultsTransfers
3
3
  from .query import BaseServiceQueryResultsTransfers
4
+ from .repository import BaseServiceRepositoryResultsTransfers
4
5
  from .controllers import BaseServiceControllerResultsTransfers
5
6
 
6
7
  class BaseServiceResultsTransfers:
7
8
  General = BaseServiceGeneralResultsTransfers
8
9
  Query = BaseServiceQueryResultsTransfers
10
+ Repository = BaseServiceRepositoryResultsTransfers
9
11
  Controller = BaseServiceControllerResultsTransfers
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+ from pydantic import model_validator
3
+ from maleo_foundation.models.schemas.general import BaseGeneralSchemas
4
+ from maleo_foundation.models.schemas.result import BaseResultSchemas
5
+
6
+ class BaseServiceRepositoryResultsTransfers:
7
+ class Row(
8
+ BaseGeneralSchemas.Status,
9
+ BaseGeneralSchemas.Timestamps,
10
+ BaseGeneralSchemas.Identifiers,
11
+ BaseResultSchemas.BaseRow
12
+ ): pass
13
+
14
+ class Fail(BaseResultSchemas.Fail): pass
15
+
16
+ class NotFound(BaseResultSchemas.NotFound): pass
17
+
18
+ class NoData(BaseResultSchemas.NoData): pass
19
+
20
+ class SingleData(BaseResultSchemas.SingleData):
21
+ data:BaseServiceRepositoryResultsTransfers.Row
22
+
23
+ class UnpaginatedMultipleData(BaseResultSchemas.UnpaginatedMultipleData):
24
+ data:list[BaseServiceRepositoryResultsTransfers.Row]
25
+
26
+ class PaginatedMultipleData(BaseResultSchemas.PaginatedMultipleData):
27
+ data:list[BaseServiceRepositoryResultsTransfers.Row]
28
+
29
+ @model_validator(mode="before")
30
+ @classmethod
31
+ def calculate_pagination(cls, values: dict) -> dict:
32
+ """Calculates pagination metadata before validation."""
33
+ total_data = values.get("total_data", 0)
34
+ data = values.get("data", [])
35
+
36
+ #* Get pagination values from inherited SimplePagination
37
+ page = values.get("page", 1)
38
+ limit = values.get("limit", 10)
39
+
40
+ #* Calculate total pages
41
+ total_pages = (total_data // limit) + (1 if total_data % limit > 0 else 0)
42
+
43
+ #* Assign computed pagination object before validation
44
+ values["pagination"] = BaseGeneralSchemas.ExtendedPagination(
45
+ page=page,
46
+ limit=limit,
47
+ data_count=len(data),
48
+ total_data=total_data,
49
+ total_pages=total_pages
50
+ )
51
+ return values
@@ -1,7 +1,9 @@
1
+ import asyncio
1
2
  from fastapi import Request, status
2
3
  from fastapi.exceptions import RequestValidationError
3
4
  from fastapi.responses import JSONResponse
4
5
  from functools import wraps
6
+ from pydantic import ValidationError
5
7
  from starlette.exceptions import HTTPException as StarletteHTTPException
6
8
  from sqlalchemy.exc import SQLAlchemyError
7
9
  from typing import Optional
@@ -10,6 +12,8 @@ from maleo_foundation.models.transfers.results.service.general \
10
12
  import BaseServiceGeneralResultsTransfers
11
13
  from maleo_foundation.models.transfers.results.service.query \
12
14
  import BaseServiceQueryResultsTransfers
15
+ from maleo_foundation.models.transfers.results.service.repository \
16
+ import BaseServiceRepositoryResultsTransfers
13
17
  from maleo_foundation.utils.logging import BaseLogger
14
18
 
15
19
  class BaseExceptions:
@@ -69,6 +73,75 @@ class BaseExceptions:
69
73
  return wrapper
70
74
  return decorator
71
75
 
76
+ @staticmethod
77
+ def repository_exception_handler(
78
+ operation:str,
79
+ logger:Optional[BaseLogger] = None,
80
+ fail_result_class:type[BaseServiceRepositoryResultsTransfers.Fail] = BaseServiceRepositoryResultsTransfers.Fail
81
+ ):
82
+ """Decorator to handle repository-related exceptions consistently for sync and async functions."""
83
+ def decorator(func):
84
+ def _handler(e:Exception, category:str, description:str):
85
+ if logger:
86
+ logger.error(
87
+ f"{category} occurred while {operation}: '{str(e)}'",
88
+ exc_info=True
89
+ )
90
+ return fail_result_class(
91
+ message=f"Failed {operation}",
92
+ description=description,
93
+ other=category
94
+ )
95
+ if asyncio.iscoroutinefunction(func):
96
+ @wraps(func)
97
+ async def async_wrapper(*args, **kwargs):
98
+ try:
99
+ return await func(*args, **kwargs)
100
+ except ValidationError as e:
101
+ return _handler(
102
+ e,
103
+ category="Validation error",
104
+ description=f"A validation error occurred while {operation}. Please try again later or contact administrator."
105
+ )
106
+ except SQLAlchemyError as e:
107
+ return _handler(
108
+ e,
109
+ category="Database operation failed",
110
+ description=f"A database error occurred while {operation}. Please try again later or contact administrator."
111
+ )
112
+ except Exception as e:
113
+ return _handler(
114
+ e,
115
+ category="Internal processing error",
116
+ description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator."
117
+ )
118
+ return async_wrapper
119
+ else:
120
+ @wraps(func)
121
+ def sync_wrapper(*args, **kwargs):
122
+ try:
123
+ return func(*args, **kwargs)
124
+ except ValidationError as e:
125
+ return _handler(
126
+ e,
127
+ category="Validation error",
128
+ description=f"A validation error occurred while {operation}. Please try again later or contact administrator."
129
+ )
130
+ except SQLAlchemyError as e:
131
+ return _handler(
132
+ e,
133
+ category="Database operation failed",
134
+ description=f"A database error occurred while {operation}. Please try again later or contact administrator."
135
+ )
136
+ except Exception as e:
137
+ return _handler(
138
+ e,
139
+ category="Internal processing error",
140
+ description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator."
141
+ )
142
+ return sync_wrapper
143
+ return decorator
144
+
72
145
  @staticmethod
73
146
  def service_exception_handler(
74
147
  operation:str,
@@ -0,0 +1,61 @@
1
+ import asyncio
2
+ from functools import wraps
3
+ from pydantic import ValidationError
4
+ from typing import Optional, Type, Union
5
+ from maleo_foundation.types import BaseTypes
6
+ from maleo_foundation.models.transfers.results.service.repository import \
7
+ BaseServiceRepositoryResultsTransfers
8
+
9
+ class BaseRepositoryUtils:
10
+ @staticmethod
11
+ def result_processor(
12
+ fail_class:Type[BaseServiceRepositoryResultsTransfers.Fail],
13
+ data_found_class:Union[
14
+ Type[BaseServiceRepositoryResultsTransfers.SingleData],
15
+ Type[BaseServiceRepositoryResultsTransfers.UnpaginatedMultipleData],
16
+ Type[BaseServiceRepositoryResultsTransfers.PaginatedMultipleData]
17
+ ],
18
+ no_data_class:Optional[Type[BaseServiceRepositoryResultsTransfers.NoData]] = None,
19
+ ):
20
+ """Decorator to handle repository-related exceptions consistently."""
21
+ def decorator(func):
22
+ def _processor(result:BaseTypes.StringToAnyDict):
23
+ if "success" not in result or "data" not in result:
24
+ raise ValueError("Result did not have both 'success' and 'data' field")
25
+ success = result.get("success")
26
+ data = result.get("data")
27
+ if success is False:
28
+ validated_result = fail_class.model_validate(result)
29
+ return validated_result
30
+ if success is True:
31
+ if data is None:
32
+ if no_data_class is None:
33
+ raise ValueError("'no_data_class' must be given to validate No Data")
34
+ validated_result = no_data_class.model_validate(result)
35
+ return validated_result
36
+ else:
37
+ validated_result = data_found_class.model_validate(result)
38
+ return validated_result
39
+ if asyncio.iscoroutinefunction(func):
40
+ @wraps(func)
41
+ async def async_wrapper(*args, **kwargs):
42
+ try:
43
+ result:BaseTypes.StringToAnyDict = await func(*args, **kwargs)
44
+ return _processor(result=result)
45
+ except ValidationError as e:
46
+ raise
47
+ except Exception as e:
48
+ raise
49
+ return async_wrapper
50
+ else:
51
+ @wraps(func)
52
+ def sync_wrapper(*args, **kwargs):
53
+ try:
54
+ result:BaseTypes.StringToAnyDict = func(*args, **kwargs)
55
+ return _processor(result=result)
56
+ except ValidationError as e:
57
+ raise
58
+ except Exception as e:
59
+ raise
60
+ return sync_wrapper
61
+ return decorator
@@ -1,13 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.2.20
3
+ Version: 0.2.21
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
7
7
  Requires-Python: >=3.7
8
8
  Description-Content-Type: text/markdown
9
+ Requires-Dist: aiocache>=0.12.3
10
+ Requires-Dist: aioredis>=2.0.1
9
11
  Requires-Dist: annotated-types>=0.7.0
10
12
  Requires-Dist: anyio>=4.9.0
13
+ Requires-Dist: async-timeout>=5.0.1
11
14
  Requires-Dist: bcrypt>=4.3.0
12
15
  Requires-Dist: build>=1.2.2.post1
13
16
  Requires-Dist: cachetools>=5.5.2
@@ -25,6 +28,7 @@ Requires-Dist: google-cloud-appengine-logging>=1.6.1
25
28
  Requires-Dist: google-cloud-audit-log>=0.3.2
26
29
  Requires-Dist: google-cloud-core>=2.4.3
27
30
  Requires-Dist: google-cloud-logging>=3.12.0
31
+ Requires-Dist: google-cloud-parametermanager>=0.1.3
28
32
  Requires-Dist: google-cloud-secret-manager>=2.23.3
29
33
  Requires-Dist: google-cloud-storage>=2.19.0
30
34
  Requires-Dist: google-crc32c>=1.7.1
@@ -66,6 +70,7 @@ Requires-Dist: pyproject_hooks>=1.2.0
66
70
  Requires-Dist: python-dotenv>=1.1.0
67
71
  Requires-Dist: PyYAML>=6.0.2
68
72
  Requires-Dist: readme_renderer>=44.0
73
+ Requires-Dist: redis>=6.1.0
69
74
  Requires-Dist: requests>=2.32.3
70
75
  Requires-Dist: requests-toolbelt>=1.0.0
71
76
  Requires-Dist: rfc3986>=2.0.0
@@ -41,11 +41,14 @@ maleo_foundation/managers/__init__.py
41
41
  maleo_foundation/managers/db.py
42
42
  maleo_foundation/managers/middleware.py
43
43
  maleo_foundation/managers/service.py
44
+ maleo_foundation/managers/cache/__init__.py
45
+ maleo_foundation/managers/cache/redis.py
44
46
  maleo_foundation/managers/client/__init__.py
45
47
  maleo_foundation/managers/client/base.py
46
48
  maleo_foundation/managers/client/maleo.py
47
49
  maleo_foundation/managers/client/google/__init__.py
48
50
  maleo_foundation/managers/client/google/base.py
51
+ maleo_foundation/managers/client/google/parameter.py
49
52
  maleo_foundation/managers/client/google/secret.py
50
53
  maleo_foundation/managers/client/google/storage.py
51
54
  maleo_foundation/middlewares/authentication.py
@@ -97,6 +100,7 @@ maleo_foundation/models/transfers/results/encryption/rsa.py
97
100
  maleo_foundation/models/transfers/results/service/__init__.py
98
101
  maleo_foundation/models/transfers/results/service/general.py
99
102
  maleo_foundation/models/transfers/results/service/query.py
103
+ maleo_foundation/models/transfers/results/service/repository.py
100
104
  maleo_foundation/models/transfers/results/service/controllers/__init__.py
101
105
  maleo_foundation/models/transfers/results/service/controllers/rest.py
102
106
  maleo_foundation/utils/__init__.py
@@ -106,6 +110,7 @@ maleo_foundation/utils/extractor.py
106
110
  maleo_foundation/utils/logging.py
107
111
  maleo_foundation/utils/mergers.py
108
112
  maleo_foundation/utils/query.py
113
+ maleo_foundation/utils/repository.py
109
114
  maleo_foundation/utils/dependencies/__init__.py
110
115
  maleo_foundation/utils/dependencies/auth.py
111
116
  maleo_foundation/utils/formatter/__init__.py
@@ -1,5 +1,8 @@
1
+ aiocache>=0.12.3
2
+ aioredis>=2.0.1
1
3
  annotated-types>=0.7.0
2
4
  anyio>=4.9.0
5
+ async-timeout>=5.0.1
3
6
  bcrypt>=4.3.0
4
7
  build>=1.2.2.post1
5
8
  cachetools>=5.5.2
@@ -17,6 +20,7 @@ google-cloud-appengine-logging>=1.6.1
17
20
  google-cloud-audit-log>=0.3.2
18
21
  google-cloud-core>=2.4.3
19
22
  google-cloud-logging>=3.12.0
23
+ google-cloud-parametermanager>=0.1.3
20
24
  google-cloud-secret-manager>=2.23.3
21
25
  google-cloud-storage>=2.19.0
22
26
  google-crc32c>=1.7.1
@@ -58,6 +62,7 @@ pyproject_hooks>=1.2.0
58
62
  python-dotenv>=1.1.0
59
63
  PyYAML>=6.0.2
60
64
  readme_renderer>=44.0
65
+ redis>=6.1.0
61
66
  requests>=2.32.3
62
67
  requests-toolbelt>=1.0.0
63
68
  rfc3986>=2.0.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maleo_foundation"
7
- version = "0.2.20"
7
+ version = "0.2.21"
8
8
  description = "Foundation package for Maleo"
9
9
  authors = [
10
10
  { name = "Agra Bima Yuda", email = "agra@nexmedis.com" }
@@ -13,8 +13,11 @@ license = { text = "MIT" }
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.7"
15
15
  dependencies = [
16
+ "aiocache>=0.12.3",
17
+ "aioredis>=2.0.1",
16
18
  "annotated-types>=0.7.0",
17
19
  "anyio>=4.9.0",
20
+ "async-timeout>=5.0.1",
18
21
  "bcrypt>=4.3.0",
19
22
  "build>=1.2.2.post1",
20
23
  "cachetools>=5.5.2",
@@ -32,6 +35,7 @@ dependencies = [
32
35
  "google-cloud-audit-log>=0.3.2",
33
36
  "google-cloud-core>=2.4.3",
34
37
  "google-cloud-logging>=3.12.0",
38
+ "google-cloud-parametermanager>=0.1.3",
35
39
  "google-cloud-secret-manager>=2.23.3",
36
40
  "google-cloud-storage>=2.19.0",
37
41
  "google-crc32c>=1.7.1",
@@ -73,6 +77,7 @@ dependencies = [
73
77
  "python-dotenv>=1.1.0",
74
78
  "PyYAML>=6.0.2",
75
79
  "readme_renderer>=44.0",
80
+ "redis>=6.1.0",
76
81
  "requests>=2.32.3",
77
82
  "requests-toolbelt>=1.0.0",
78
83
  "rfc3986>=2.0.0",