maleo-foundation 0.2.16__py3-none-any.whl → 0.2.17__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.
Files changed (36) hide show
  1. maleo_foundation/client/services/encryption/aes.py +41 -11
  2. maleo_foundation/client/services/encryption/rsa.py +59 -16
  3. maleo_foundation/client/services/hash/bcrypt.py +24 -9
  4. maleo_foundation/client/services/hash/hmac.py +26 -8
  5. maleo_foundation/client/services/hash/sha256.py +16 -6
  6. maleo_foundation/client/services/key.py +34 -12
  7. maleo_foundation/client/services/signature.py +45 -12
  8. maleo_foundation/client/services/token.py +68 -16
  9. maleo_foundation/expanded_types/client.py +6 -3
  10. maleo_foundation/expanded_types/encryption/aes.py +2 -1
  11. maleo_foundation/expanded_types/encryption/rsa.py +2 -1
  12. maleo_foundation/expanded_types/general.py +2 -1
  13. maleo_foundation/expanded_types/hash.py +2 -1
  14. maleo_foundation/expanded_types/key.py +2 -1
  15. maleo_foundation/expanded_types/query.py +6 -3
  16. maleo_foundation/expanded_types/service.py +6 -3
  17. maleo_foundation/expanded_types/signature.py +2 -1
  18. maleo_foundation/expanded_types/token.py +2 -1
  19. maleo_foundation/managers/client/base.py +5 -1
  20. maleo_foundation/managers/client/google/storage.py +5 -1
  21. maleo_foundation/managers/client/maleo.py +20 -4
  22. maleo_foundation/managers/db.py +21 -6
  23. maleo_foundation/managers/service.py +108 -23
  24. maleo_foundation/middlewares/authentication.py +35 -8
  25. maleo_foundation/middlewares/base.py +53 -15
  26. maleo_foundation/models/table.py +21 -4
  27. maleo_foundation/models/transfers/parameters/service.py +30 -4
  28. maleo_foundation/utils/controller.py +23 -6
  29. maleo_foundation/utils/dependencies/auth.py +14 -4
  30. maleo_foundation/utils/exceptions.py +21 -6
  31. maleo_foundation/utils/loaders/credential/google.py +3 -1
  32. maleo_foundation/utils/query.py +38 -7
  33. {maleo_foundation-0.2.16.dist-info → maleo_foundation-0.2.17.dist-info}/METADATA +1 -1
  34. {maleo_foundation-0.2.16.dist-info → maleo_foundation-0.2.17.dist-info}/RECORD +36 -36
  35. {maleo_foundation-0.2.16.dist-info → maleo_foundation-0.2.17.dist-info}/WHEEL +0 -0
  36. {maleo_foundation-0.2.16.dist-info → maleo_foundation-0.2.17.dist-info}/top_level.txt +0 -0
@@ -7,12 +7,18 @@ from maleo_foundation.authentication import Credentials, User
7
7
  from maleo_foundation.enums import BaseEnums
8
8
  from maleo_foundation.client.manager import MaleoFoundationClientManager
9
9
  from maleo_foundation.models.schemas import BaseGeneralSchemas
10
- from maleo_foundation.models.transfers.parameters.token import MaleoFoundationTokenParametersTransfers
10
+ from maleo_foundation.models.transfers.parameters.token \
11
+ import MaleoFoundationTokenParametersTransfers
11
12
  from maleo_foundation.utils.exceptions import BaseExceptions
12
13
  from maleo_foundation.utils.logging import MiddlewareLogger
13
14
 
14
15
  class Backend(AuthenticationBackend):
15
- def __init__(self, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager):
16
+ def __init__(
17
+ self,
18
+ keys:BaseGeneralSchemas.RSAKeys,
19
+ logger:MiddlewareLogger,
20
+ maleo_foundation:MaleoFoundationClientManager
21
+ ):
16
22
  super().__init__()
17
23
  self._keys = keys
18
24
  self._logger = logger
@@ -29,8 +35,14 @@ class Backend(AuthenticationBackend):
29
35
  raise AuthenticationError("Authorization scheme must be Bearer token")
30
36
 
31
37
  #* Decode token
32
- decode_token_parameters = MaleoFoundationTokenParametersTransfers.Decode(key=self._keys.public, token=token)
33
- decode_token_result = self._maleo_foundation.services.token.decode(parameters=decode_token_parameters)
38
+ decode_token_parameters = (
39
+ MaleoFoundationTokenParametersTransfers
40
+ .Decode(key=self._keys.public, token=token)
41
+ )
42
+ decode_token_result = (
43
+ self._maleo_foundation.services.token
44
+ .decode(parameters=decode_token_parameters)
45
+ )
34
46
  if decode_token_result.success:
35
47
  payload = decode_token_result.data
36
48
  return (
@@ -50,8 +62,14 @@ class Backend(AuthenticationBackend):
50
62
  if "token" in conn.cookies:
51
63
  token = conn.cookies["token"]
52
64
  #* Decode token
53
- decode_token_parameters = MaleoFoundationTokenParametersTransfers.Decode(key=self._keys.public, token=token)
54
- decode_token_result = self._maleo_foundation.services.token.decode(parameters=decode_token_parameters)
65
+ decode_token_parameters = (
66
+ MaleoFoundationTokenParametersTransfers
67
+ .Decode(key=self._keys.public, token=token)
68
+ )
69
+ decode_token_result = (
70
+ self._maleo_foundation.services.token
71
+ .decode(parameters=decode_token_parameters)
72
+ )
55
73
  if decode_token_result.success:
56
74
  payload = decode_token_result.data
57
75
  return (
@@ -70,7 +88,12 @@ class Backend(AuthenticationBackend):
70
88
 
71
89
  return Credentials(), User(authenticated=False)
72
90
 
73
- def add_authentication_middleware(app:FastAPI, keys:BaseGeneralSchemas.RSAKeys, logger:MiddlewareLogger, maleo_foundation:MaleoFoundationClientManager) -> None:
91
+ def add_authentication_middleware(
92
+ app:FastAPI,
93
+ keys:BaseGeneralSchemas.RSAKeys,
94
+ logger:MiddlewareLogger,
95
+ maleo_foundation:MaleoFoundationClientManager
96
+ ) -> None:
74
97
  """
75
98
  Adds Authentication middleware to the FastAPI application.
76
99
 
@@ -96,4 +119,8 @@ def add_authentication_middleware(app:FastAPI, keys:BaseGeneralSchemas.RSAKeys,
96
119
  add_authentication_middleware(app=app, limit=10, window=1, cleanup_interval=60, ip_timeout=300)
97
120
  ```
98
121
  """
99
- app.add_middleware(AuthenticationMiddleware, backend=Backend(keys, logger, maleo_foundation), on_error=BaseExceptions.authentication_error_handler)
122
+ app.add_middleware(
123
+ AuthenticationMiddleware,
124
+ backend=Backend(keys, logger, maleo_foundation),
125
+ on_error=BaseExceptions.authentication_error_handler
126
+ )
@@ -13,9 +13,12 @@ from maleo_foundation.enums import BaseEnums
13
13
  from maleo_foundation.client.manager import MaleoFoundationClientManager
14
14
  from maleo_foundation.models.schemas import BaseGeneralSchemas
15
15
  from maleo_foundation.models.responses import BaseResponses
16
- from maleo_foundation.models.transfers.general.token import MaleoFoundationTokenGeneralTransfers
17
- from maleo_foundation.models.transfers.parameters.token import MaleoFoundationTokenParametersTransfers
18
- from maleo_foundation.models.transfers.parameters.signature import MaleoFoundationSignatureParametersTransfers
16
+ from maleo_foundation.models.transfers.general.token \
17
+ import MaleoFoundationTokenGeneralTransfers
18
+ from maleo_foundation.models.transfers.parameters.token \
19
+ import MaleoFoundationTokenParametersTransfers
20
+ from maleo_foundation.models.transfers.parameters.signature \
21
+ import MaleoFoundationSignatureParametersTransfers
19
22
  from maleo_foundation.utils.extractor import BaseExtractors
20
23
  from maleo_foundation.utils.logging import MiddlewareLogger
21
24
 
@@ -89,14 +92,20 @@ class BaseMiddleware(BaseHTTPMiddleware):
89
92
  self._last_cleanup = now
90
93
  self._logger.debug(f"Cleaned up request cache. Removed {len(inactive_ips)} inactive IPs. Current tracked IPs: {len(self._requests)}")
91
94
 
92
- def _check_rate_limit(self, client_ip:str) -> bool:
95
+ def _check_rate_limit(
96
+ self,
97
+ client_ip:str
98
+ ) -> bool:
93
99
  """Check if the client has exceeded their rate limit"""
94
100
  with self._lock:
95
101
  now = datetime.now() #* Define current timestamp
96
102
  self._last_seen[client_ip] = now #* Update last seen timestamp for this IP
97
103
 
98
104
  #* Filter requests within the window
99
- self._requests[client_ip] = [timestamp for timestamp in self._requests[client_ip] if now - timestamp <= self._window]
105
+ self._requests[client_ip] = [
106
+ timestamp for timestamp in self._requests[client_ip]
107
+ if now - timestamp <= self._window
108
+ ]
100
109
 
101
110
  #* Check if the request count exceeds the limit
102
111
  if len(self._requests[client_ip]) >= self._limit:
@@ -106,7 +115,11 @@ class BaseMiddleware(BaseHTTPMiddleware):
106
115
  self._requests[client_ip].append(now)
107
116
  return False
108
117
 
109
- def _append_cors_headers(self, request:Request, response:Response) -> Response:
118
+ def _append_cors_headers(
119
+ self,
120
+ request:Request,
121
+ response:Response
122
+ ) -> Response:
110
123
  origin = request.headers.get("Origin")
111
124
 
112
125
  if origin in self._allow_origins:
@@ -131,18 +144,29 @@ class BaseMiddleware(BaseHTTPMiddleware):
131
144
  response.headers["X-Response-Timestamp"] = response_timestamp.isoformat() #* Define and add response timestamp header
132
145
  #* Generate signature header
133
146
  message = f"{request.method}|{request.url.path}|{request_timestamp.isoformat()}|{response_timestamp.isoformat()}|{str(process_time)}"
134
- sign_parameters = MaleoFoundationSignatureParametersTransfers.Sign(key=self._keys.private, password=self._keys.password, message=message)
147
+ sign_parameters = (
148
+ MaleoFoundationSignatureParametersTransfers
149
+ .Sign(key=self._keys.private, password=self._keys.password, message=message)
150
+ )
135
151
  sign_result = self._maleo_foundation.services.signature.sign(parameters=sign_parameters)
136
152
  if sign_result.success:
137
153
  response.headers["X-Signature"] = sign_result.data.signature
138
154
  response = self._append_cors_headers(request=request, response=response) #* Re-append CORS headers
139
- if authentication.user.is_authenticated \
140
- and authentication.credentials.token_type == BaseEnums.TokenType.REFRESH \
141
- and authentication.credentials.payload is not None \
142
- and (response.status_code >= 200 and response.status_code < 300):
155
+ if (authentication.user.is_authenticated
156
+ and authentication.credentials.token_type == BaseEnums.TokenType.REFRESH
157
+ and authentication.credentials.payload is not None
158
+ and (response.status_code >= 200 and response.status_code < 300)
159
+ ):
143
160
  #* Regenerate new authorization
144
- payload = MaleoFoundationTokenGeneralTransfers.BaseEncodePayload.model_validate(authentication.credentials.payload.model_dump())
145
- parameters = MaleoFoundationTokenParametersTransfers.Encode(key=self._keys.private, password=self._keys.password, payload=payload)
161
+ payload = (
162
+ MaleoFoundationTokenGeneralTransfers
163
+ .BaseEncodePayload
164
+ .model_validate(authentication.credentials.payload.model_dump())
165
+ )
166
+ parameters = (
167
+ MaleoFoundationTokenParametersTransfers
168
+ .Encode(key=self._keys.private, password=self._keys.password, payload=payload)
169
+ )
146
170
  result = self._maleo_foundation.services.token.encode(parameters=parameters)
147
171
  if result.success:
148
172
  response.headers["X-New-Authorization"] = result.data.token
@@ -160,7 +184,14 @@ class BaseMiddleware(BaseHTTPMiddleware):
160
184
  log_level:str = "info",
161
185
  client_ip:str = "unknown"
162
186
  ) -> Response:
163
- response = self._add_response_headers(request, authentication, response, request_timestamp, response_timestamp, process_time)
187
+ response = self._add_response_headers(
188
+ request,
189
+ authentication,
190
+ response,
191
+ request_timestamp,
192
+ response_timestamp,
193
+ process_time
194
+ )
164
195
  log_func = getattr(self._logger, log_level)
165
196
  log_func(
166
197
  f"Request {authentication_info} | IP: {client_ip} | Host: {request.client.host} | Port: {request.client.port} | Method: {request.method} | URL: {request.url.path} | "
@@ -199,7 +230,14 @@ class BaseMiddleware(BaseHTTPMiddleware):
199
230
  f"Headers: {dict(request.headers)} - Response | Status: 500 | Exception:\n{json.dumps(error_details, indent=4)}"
200
231
  )
201
232
 
202
- return self._add_response_headers(request, authentication, response, request_timestamp, response_timestamp, process_time)
233
+ return self._add_response_headers(
234
+ request,
235
+ authentication,
236
+ response,
237
+ request_timestamp,
238
+ response_timestamp,
239
+ process_time
240
+ )
203
241
 
204
242
  async def _request_processor(self, request:Request) -> Optional[Response]:
205
243
  return None
@@ -18,12 +18,29 @@ class BaseTable:
18
18
  uuid = Column(UUID, default=uuid4, unique=True, nullable=False)
19
19
 
20
20
  #* Timestamps
21
- created_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), nullable=False)
22
- updated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), onupdate=func.now(), nullable=False)
21
+ created_at = Column(
22
+ TIMESTAMP(timezone=True),
23
+ server_default=func.now(),
24
+ nullable=False
25
+ )
26
+ updated_at = Column(
27
+ TIMESTAMP(timezone=True),
28
+ server_default=func.now(),
29
+ onupdate=func.now(),
30
+ nullable=False
31
+ )
23
32
  deleted_at = Column(TIMESTAMP(timezone=True))
24
33
  restored_at = Column(TIMESTAMP(timezone=True))
25
34
  deactivated_at = Column(TIMESTAMP(timezone=True))
26
- activated_at = Column(TIMESTAMP(timezone=True), server_default=func.now(), nullable=False)
35
+ activated_at = Column(
36
+ TIMESTAMP(timezone=True),
37
+ server_default=func.now(),
38
+ nullable=False
39
+ )
27
40
 
28
41
  #* Statuses
29
- status = Column(Enum(BaseEnums.StatusType, name="statustype"), default=BaseEnums.StatusType.ACTIVE, nullable=False)
42
+ status = Column(
43
+ Enum(BaseEnums.StatusType, name="statustype"),
44
+ default=BaseEnums.StatusType.ACTIVE,
45
+ nullable=False
46
+ )
@@ -27,7 +27,13 @@ class BaseServiceParametersTransfers:
27
27
  parts = item.split('.')
28
28
  if len(parts) == 2 and parts[1].lower() in ["asc", "desc"]:
29
29
  try:
30
- sort_columns.append(BaseGeneralSchemas.SortColumn(name=parts[0], order=BaseEnums.SortOrder(parts[1].lower())))
30
+ sort_columns.append(
31
+ BaseGeneralSchemas
32
+ .SortColumn(
33
+ name=parts[0],
34
+ order=BaseEnums.SortOrder(parts[1].lower())
35
+ )
36
+ )
31
37
  except ValueError:
32
38
  continue
33
39
 
@@ -64,7 +70,14 @@ class BaseServiceParametersTransfers:
64
70
 
65
71
  #* Only add filter if at least one date is specified
66
72
  if from_date or to_date:
67
- date_filters.append(BaseGeneralSchemas.DateFilter(name=name, from_date=from_date, to_date=to_date))
73
+ date_filters.append(
74
+ BaseGeneralSchemas
75
+ .DateFilter(
76
+ name=name,
77
+ from_date=from_date,
78
+ to_date=to_date
79
+ )
80
+ )
68
81
 
69
82
  #* Update date_filters
70
83
  self.date_filters = date_filters
@@ -88,7 +101,13 @@ class BaseServiceParametersTransfers:
88
101
  parts = item.split('.')
89
102
  if len(parts) == 2 and parts[1].lower() in ["asc", "desc"]:
90
103
  try:
91
- sort_columns.append(BaseGeneralSchemas.SortColumn(name=parts[0], order=BaseEnums.SortOrder(parts[1].lower())))
104
+ sort_columns.append(
105
+ BaseGeneralSchemas
106
+ .SortColumn(
107
+ name=parts[0],
108
+ order=BaseEnums.SortOrder(parts[1].lower())
109
+ )
110
+ )
92
111
  except ValueError:
93
112
  continue
94
113
 
@@ -125,7 +144,14 @@ class BaseServiceParametersTransfers:
125
144
 
126
145
  #* Only add filter if at least one date is specified
127
146
  if from_date or to_date:
128
- date_filters.append(BaseGeneralSchemas.DateFilter(name=name, from_date=from_date, to_date=to_date))
147
+ date_filters.append(
148
+ BaseGeneralSchemas
149
+ .DateFilter(
150
+ name=name,
151
+ from_date=from_date,
152
+ to_date=to_date
153
+ )
154
+ )
129
155
 
130
156
  #* Update date_filters
131
157
  self.date_filters = date_filters
@@ -3,8 +3,10 @@ from functools import wraps
3
3
  from typing import Awaitable, Callable, Dict, List
4
4
  from maleo_foundation.types import BaseTypes
5
5
  from maleo_foundation.models.responses import BaseResponses
6
- from maleo_foundation.models.transfers.parameters.general import BaseGeneralParametersTransfers
7
- from maleo_foundation.models.transfers.results.service.controllers.rest import BaseServiceRESTControllerResults
6
+ from maleo_foundation.models.transfers.parameters.general \
7
+ import BaseGeneralParametersTransfers
8
+ from maleo_foundation.models.transfers.results.service.controllers.rest \
9
+ import BaseServiceRESTControllerResults
8
10
  from maleo_foundation.expanded_types.general import BaseGeneralExpandedTypes
9
11
 
10
12
  class BaseControllerUtils:
@@ -33,7 +35,11 @@ class BaseControllerUtils:
33
35
  if dependent in expand:
34
36
  other = f"'{dependency}' must also be expanded if '{dependent}' is expanded"
35
37
  content = BaseResponses.InvalidExpand(other=other).model_dump()
36
- return BaseServiceRESTControllerResults(success=False, content=content, status_code=status.HTTP_400_BAD_REQUEST)
38
+ return BaseServiceRESTControllerResults(
39
+ success=False,
40
+ content=content,
41
+ status_code=status.HTTP_400_BAD_REQUEST
42
+ )
37
43
 
38
44
  #* Call the original function
39
45
  result = await func(parameters, *args, **kwargs)
@@ -42,18 +48,29 @@ class BaseControllerUtils:
42
48
  return result
43
49
 
44
50
  #* Process the fields if needed
45
- if result.success and result.content.get("data", None) is not None and field_expansion_processors is not None:
51
+ if (result.success
52
+ and result.content.get("data", None) is not None
53
+ and field_expansion_processors is not None
54
+ ):
46
55
  data = result.content["data"]
47
56
  if isinstance(data, List):
48
57
  for idx, dt in enumerate(data):
49
58
  for processor in field_expansion_processors:
50
59
  raw_parameters = {"data": dt, "expand": expand}
51
- parameters = BaseGeneralParametersTransfers.FieldExpansionProcessor.model_validate(raw_parameters)
60
+ parameters = (
61
+ BaseGeneralParametersTransfers
62
+ .FieldExpansionProcessor
63
+ .model_validate(raw_parameters)
64
+ )
52
65
  dt = processor(parameters)
53
66
  data[idx] = dt
54
67
  elif isinstance(data, Dict):
55
68
  raw_parameters = {"data": data, "expand": expand}
56
- parameters = BaseGeneralParametersTransfers.FieldExpansionProcessor.model_validate(raw_parameters)
69
+ parameters = (
70
+ BaseGeneralParametersTransfers
71
+ .FieldExpansionProcessor
72
+ .model_validate(raw_parameters)
73
+ )
57
74
  for processor in field_expansion_processors:
58
75
  data = processor(parameters)
59
76
  result.content["data"] = data
@@ -6,9 +6,19 @@ from maleo_foundation.authorization import TOKEN_SCHEME, Authorization
6
6
 
7
7
  class AuthDependencies:
8
8
  @staticmethod
9
- def authentication(request:Request) -> Authentication:
10
- return Authentication(credentials=request.auth, user=request.user)
9
+ def authentication(
10
+ request:Request
11
+ ) -> Authentication:
12
+ return Authentication(
13
+ credentials=request.auth,
14
+ user=request.user
15
+ )
11
16
 
12
17
  @staticmethod
13
- def authorization(token:HTTPAuthorizationCredentials = Security(TOKEN_SCHEME)) -> Authorization:
14
- return Authorization(scheme=token.scheme, credentials=token.credentials)
18
+ def authorization(
19
+ token:HTTPAuthorizationCredentials = Security(TOKEN_SCHEME)
20
+ ) -> Authorization:
21
+ return Authorization(
22
+ scheme=token.scheme,
23
+ credentials=token.credentials
24
+ )
@@ -6,24 +6,39 @@ from starlette.exceptions import HTTPException as StarletteHTTPException
6
6
  from sqlalchemy.exc import SQLAlchemyError
7
7
  from typing import Optional
8
8
  from maleo_foundation.models.responses import BaseResponses
9
- from maleo_foundation.models.transfers.results.service.general import BaseServiceGeneralResultsTransfers
10
- from maleo_foundation.models.transfers.results.service.query import BaseServiceQueryResultsTransfers
9
+ from maleo_foundation.models.transfers.results.service.general \
10
+ import BaseServiceGeneralResultsTransfers
11
+ from maleo_foundation.models.transfers.results.service.query \
12
+ import BaseServiceQueryResultsTransfers
11
13
  from maleo_foundation.utils.logging import BaseLogger
12
14
 
13
15
  class BaseExceptions:
14
16
  @staticmethod
15
17
  def authentication_error_handler(request:Request, exc:Exception):
16
- return JSONResponse(content=BaseResponses.Unauthorized(other=str(exc)).model_dump(mode="json"), status_code=status.HTTP_401_UNAUTHORIZED)
18
+ return JSONResponse(
19
+ content=BaseResponses.Unauthorized(other=str(exc)).model_dump(mode="json"),
20
+ status_code=status.HTTP_401_UNAUTHORIZED
21
+ )
17
22
 
18
23
  @staticmethod
19
24
  async def validation_exception_handler(request:Request, exc:RequestValidationError):
20
- return JSONResponse(content=BaseResponses.ValidationError(other=exc.errors()).model_dump(mode="json"), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
25
+ return JSONResponse(
26
+ content=BaseResponses.ValidationError(other=exc.errors()).model_dump(mode="json"),
27
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY
28
+ )
21
29
 
22
30
  @staticmethod
23
31
  async def http_exception_handler(request:Request, exc:StarletteHTTPException):
24
32
  if exc.status_code in BaseResponses.other_responses:
25
- return JSONResponse(content=BaseResponses.other_responses[exc.status_code]["model"]().model_dump(mode="json"), status_code=exc.status_code)
26
- return JSONResponse(content=BaseResponses.ServerError().model_dump(mode="json"), status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
33
+ return JSONResponse(
34
+ content=BaseResponses.other_responses[exc.status_code]["model"]().model_dump(mode="json"),
35
+ status_code=exc.status_code
36
+ )
37
+
38
+ return JSONResponse(
39
+ content=BaseResponses.ServerError().model_dump(mode="json"),
40
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR
41
+ )
27
42
 
28
43
  @staticmethod
29
44
  def database_exception_handler(
@@ -15,7 +15,9 @@ class GoogleCredentialsLoader:
15
15
  if credentials_path is not None:
16
16
  credentials_path = Path(credentials_path)
17
17
  if credentials_path.exists() or credentials_path.is_file():
18
- credentials = Credentials.from_service_account_file(filename=str(credentials_path))
18
+ credentials = Credentials.from_service_account_file(
19
+ filename=str(credentials_path)
20
+ )
19
21
  else:
20
22
  credentials, _ = default()
21
23
  return credentials
@@ -10,7 +10,12 @@ from maleo_foundation.extended_types import ExtendedTypes
10
10
 
11
11
  class BaseQueryUtils:
12
12
  @staticmethod
13
- def filter_column(query:Query, table:Type[DeclarativeMeta], column:str, value:BaseTypes.OptionalAny) -> Query:
13
+ def filter_column(
14
+ query:Query,
15
+ table:Type[DeclarativeMeta],
16
+ column:str,
17
+ value:BaseTypes.OptionalAny
18
+ ) -> Query:
14
19
  if not value:
15
20
  return query
16
21
  column_attr = getattr(table, column, None)
@@ -24,7 +29,12 @@ class BaseQueryUtils:
24
29
  return query
25
30
 
26
31
  @staticmethod
27
- def filter_ids(query:Query, table:Type[DeclarativeMeta], column:str, ids:BaseTypes.OptionalListOfIntegers) -> Query:
32
+ def filter_ids(
33
+ query:Query,
34
+ table:Type[DeclarativeMeta],
35
+ column:str,
36
+ ids:BaseTypes.OptionalListOfIntegers
37
+ ) -> Query:
28
38
  if ids is not None:
29
39
  column_attr = getattr(table, column, None)
30
40
  if column_attr:
@@ -33,7 +43,11 @@ class BaseQueryUtils:
33
43
  return query
34
44
 
35
45
  @staticmethod
36
- def filter_timestamps(query:Query, table:Type[DeclarativeMeta], date_filters:ExtendedTypes.ListOfDateFilters) -> Query:
46
+ def filter_timestamps(
47
+ query:Query,
48
+ table:Type[DeclarativeMeta],
49
+ date_filters:ExtendedTypes.ListOfDateFilters
50
+ ) -> Query:
37
51
  if date_filters and len(date_filters) > 0:
38
52
  for date_filter in date_filters:
39
53
  try:
@@ -42,7 +56,12 @@ class BaseQueryUtils:
42
56
  column_attr:InstrumentedAttribute = getattr(table, date_filter.name)
43
57
  if isinstance(column.type, (TIMESTAMP, DATE)):
44
58
  if date_filter.from_date and date_filter.to_date:
45
- query = query.filter(column_attr.between(date_filter.from_date, date_filter.to_date))
59
+ query = query.filter(
60
+ column_attr.between(
61
+ date_filter.from_date,
62
+ date_filter.to_date
63
+ )
64
+ )
46
65
  elif date_filter.from_date:
47
66
  query = query.filter(column_attr >= date_filter.from_date)
48
67
  elif date_filter.to_date:
@@ -52,14 +71,22 @@ class BaseQueryUtils:
52
71
  return query
53
72
 
54
73
  @staticmethod
55
- def filter_statuses(query:Query, table:Type[DeclarativeMeta], statuses:BaseTypes.OptionalListOfStatuses) -> Query:
74
+ def filter_statuses(
75
+ query:Query,
76
+ table:Type[DeclarativeMeta],
77
+ statuses:BaseTypes.OptionalListOfStatuses
78
+ ) -> Query:
56
79
  if statuses is not None:
57
80
  status_filters = [table.status == status for status in statuses]
58
81
  query = query.filter(or_(*status_filters))
59
82
  return query
60
83
 
61
84
  @staticmethod
62
- def filter_search(query:Query, table:Type[DeclarativeMeta], search:BaseTypes.OptionalString) -> Query:
85
+ def filter_search(
86
+ query:Query,
87
+ table:Type[DeclarativeMeta],
88
+ search:BaseTypes.OptionalString
89
+ ) -> Query:
63
90
  if search:
64
91
  search_term = f"%{search}%" #* Use wildcard for partial matching
65
92
  search_filters = []
@@ -78,7 +105,11 @@ class BaseQueryUtils:
78
105
  return query
79
106
 
80
107
  @staticmethod
81
- def sort(query:Query, table:Type[DeclarativeMeta], sort_columns:ExtendedTypes.ListOfSortColumns) -> Query:
108
+ def sort(
109
+ query:Query,
110
+ table:Type[DeclarativeMeta],
111
+ sort_columns:ExtendedTypes.ListOfSortColumns
112
+ ) -> Query:
82
113
  for sort_column in sort_columns:
83
114
  try:
84
115
  sort_col = getattr(table, sort_column.name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.2.16
3
+ Version: 0.2.17
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT