maleo-foundation 0.2.75__py3-none-any.whl → 0.2.76__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.
@@ -11,16 +11,16 @@ ACCESS_TOKEN_DURATION_MINUTES:int = 5
11
11
  SORT_COLUMN_PATTERN = re.compile(r'^[a-z_]+\.(asc|desc)$')
12
12
  DATE_FILTER_PATTERN = re.compile(r'^[a-z_]+(?:\|from::\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2}))?(?:\|to::\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2}))?$')
13
13
  STATUS_UPDATE_CRITERIAS:dict[
14
- BaseEnums.StatusUpdateAction,
14
+ BaseEnums.StatusUpdateType,
15
15
  BaseTypes.OptionalListOfStatuses
16
16
  ] = {
17
- BaseEnums.StatusUpdateAction.DELETE: None,
18
- BaseEnums.StatusUpdateAction.RESTORE: None,
19
- BaseEnums.StatusUpdateAction.DEACTIVATE: [
17
+ BaseEnums.StatusUpdateType.DELETE: None,
18
+ BaseEnums.StatusUpdateType.RESTORE: None,
19
+ BaseEnums.StatusUpdateType.DEACTIVATE: [
20
20
  BaseEnums.StatusType.INACTIVE,
21
21
  BaseEnums.StatusType.ACTIVE,
22
22
  ],
23
- BaseEnums.StatusUpdateAction.ACTIVATE: [
23
+ BaseEnums.StatusUpdateType.ACTIVATE: [
24
24
  BaseEnums.StatusType.INACTIVE,
25
25
  BaseEnums.StatusType.ACTIVE,
26
26
  ]
maleo_foundation/enums.py CHANGED
@@ -44,19 +44,25 @@ class BaseEnums:
44
44
  ASC = "asc"
45
45
  DESC = "desc"
46
46
 
47
- class StatusUpdateAction(StrEnum):
47
+ class TokenType(StrEnum):
48
+ REFRESH = "refresh"
49
+ ACCESS = "access"
50
+
51
+ class StatusUpdateType(StrEnum):
48
52
  ACTIVATE = "activate"
49
53
  DEACTIVATE = "deactivate"
50
54
  RESTORE = "restore"
51
55
  DELETE = "delete"
52
56
 
53
- class TokenType(StrEnum):
54
- REFRESH = "refresh"
55
- ACCESS = "access"
57
+ class UpdateType(StrEnum):
58
+ STATUS = "status"
59
+ DATA = "data"
56
60
 
57
61
  class OperationType(StrEnum):
58
62
  CREATE = "create"
59
63
  UPDATE = "update"
64
+ RESTORE = "restore"
65
+ DELETE = "delete"
60
66
 
61
67
  class IdentifierTypes(StrEnum):
62
68
  ID = "id"
@@ -144,6 +150,23 @@ class BaseEnums:
144
150
  TTL_12HR = int(12*60*60)
145
151
  TTL_1DY = int(1*24*60*60)
146
152
  TTL_3DY = int(3*24*60*60)
147
- TTL_1WK = int(1*24*60*60)
148
- TTL_2WK = int(2*24*60*60)
149
- TTL_1MO = int(1*30*24*60*60)
153
+ TTL_1WK = int(1*7*24*60*60)
154
+ TTL_2WK = int(2*7*24*60*60)
155
+ TTL_1MO = int(1*30*24*60*60)
156
+
157
+ class Expiration(IntEnum):
158
+ EXP_15SC = int(15)
159
+ EXP_30SC = int(30)
160
+ EXP_1MN = int(1*60)
161
+ EXP_5MN = int(5*60)
162
+ EXP_10MN = int(10*60)
163
+ EXP_15MN = int(15*60)
164
+ EXP_30MN = int(30*60)
165
+ EXP_1HR = int(1*60*60)
166
+ EXP_6HR = int(6*60*60)
167
+ EXP_12HR = int(12*60*60)
168
+ EXP_1DY = int(1*24*60*60)
169
+ EXP_3DY = int(3*24*60*60)
170
+ EXP_1WK = int(1*7*24*60*60)
171
+ EXP_2WK = int(2*7*24*60*60)
172
+ EXP_1MO = int(1*30*24*60*60)
@@ -3,7 +3,9 @@ from datetime import timedelta
3
3
  from google.cloud.storage import Bucket, Client
4
4
  from google.oauth2.service_account import Credentials
5
5
  from pathlib import Path
6
+ from redis.asyncio.client import Redis
6
7
  from typing import Optional, Union
8
+ from maleo_foundation.enums import BaseEnums
7
9
  from maleo_foundation.types import BaseTypes
8
10
  from maleo_foundation.utils.logging import SimpleConfig
9
11
  from .base import GoogleClientManager
@@ -15,7 +17,8 @@ class GoogleCloudStorage(GoogleClientManager):
15
17
  service_key:BaseTypes.OptionalString=None,
16
18
  credentials:Optional[Credentials]=None,
17
19
  credentials_path:Optional[Union[Path, str]]=None,
18
- bucket_name:BaseTypes.OptionalString = None
20
+ bucket_name:BaseTypes.OptionalString = None,
21
+ redis:Optional[Redis] = None
19
22
  ) -> None:
20
23
  key = "google-cloud-storage"
21
24
  name = "GoogleCloudStorage"
@@ -31,6 +34,7 @@ class GoogleCloudStorage(GoogleClientManager):
31
34
  raise ValueError(f"Bucket '{self._bucket_name}' does not exist.")
32
35
  self._root_location = service_key
33
36
  self._logger.info("Client manager initialized successfully")
37
+ self._redis = redis
34
38
 
35
39
  @property
36
40
  def bucket_name(self) -> str:
@@ -53,8 +57,9 @@ class GoogleCloudStorage(GoogleClientManager):
53
57
  location:str,
54
58
  content_type:Optional[str]=None,
55
59
  make_public:bool=False,
56
- expiration:timedelta=timedelta(minutes=15),
57
- root_location_override:BaseTypes.OptionalString=None
60
+ expiration:BaseEnums=BaseEnums.Expiration.EXP_15MN,
61
+ root_location_override:BaseTypes.OptionalString=None,
62
+ set_in_redis:bool=False
58
63
  ) -> str:
59
64
  """
60
65
  Upload a file to Google Cloud Storage.
@@ -69,9 +74,11 @@ class GoogleCloudStorage(GoogleClientManager):
69
74
  str: The public URL or blob path depending on `make_public`.
70
75
  """
71
76
  if root_location_override is None or (isinstance(root_location_override, str) and len(root_location_override) <= 0):
72
- blob = self._bucket.blob(f"{self._root_location}/{location}")
77
+ blob_name = f"{self._root_location}/{location}"
73
78
  else:
74
- blob = self._bucket.blob(f"{root_location_override}/{location}")
79
+ blob_name = f"{root_location_override}/{location}"
80
+
81
+ blob = self._bucket.blob(blob_name=blob_name)
75
82
  blob.upload_from_string(content, content_type=content_type)
76
83
 
77
84
  if make_public:
@@ -80,16 +87,24 @@ class GoogleCloudStorage(GoogleClientManager):
80
87
  else:
81
88
  url = blob.generate_signed_url(
82
89
  version="v4",
83
- expiration=expiration,
90
+ expiration=timedelta(seconds=int(expiration)),
84
91
  method="GET"
85
92
  )
93
+
94
+ if set_in_redis:
95
+ if make_public:
96
+ self._redis.set(f"{self.key}:{blob_name}", url)
97
+ else:
98
+ self._redis.set(f"{self.key}:{blob_name}", url, ex=int(expiration))
99
+
86
100
  return url
87
101
 
88
102
  def generate_signed_url(
89
103
  self,
90
104
  location:str,
91
- expiration:timedelta=timedelta(minutes=15),
92
- root_location_override:BaseTypes.OptionalString=None
105
+ expiration:BaseEnums=BaseEnums.Expiration.EXP_15MN,
106
+ root_location_override:BaseTypes.OptionalString=None,
107
+ use_redis:bool=False
93
108
  ) -> str:
94
109
  """
95
110
  generate signed URL of a file in the bucket based on its location.
@@ -104,16 +119,29 @@ class GoogleCloudStorage(GoogleClientManager):
104
119
  Raises:
105
120
  ValueError: If the file does not exist
106
121
  """
122
+ if use_redis and self._redis is None:
123
+ raise ValueError("Can not use redis. Redis is not initialized")
124
+
107
125
  if root_location_override is None or (isinstance(root_location_override, str) and len(root_location_override) <= 0):
108
- blob = self._bucket.blob(blob_name=f"{self._root_location}/{location}")
126
+ blob_name=f"{self._root_location}/{location}"
109
127
  else:
110
- blob = self._bucket.blob(blob_name=f"{root_location_override}/{location}")
128
+ blob_name=f"{root_location_override}/{location}"
129
+
130
+ blob = self._bucket.blob(blob_name=blob_name)
111
131
  if not blob.exists():
112
132
  raise ValueError(f"File '{location}' did not exists.")
113
133
 
134
+ if use_redis:
135
+ if self._redis is None:
136
+ raise ValueError("Can not use redis. Redis is not initialized")
137
+ url = self._redis.get(blob_name)
138
+ if url is not None:
139
+ return url
140
+
114
141
  url = blob.generate_signed_url(
115
142
  version="v4",
116
- expiration=expiration,
143
+ expiration=timedelta(seconds=int(expiration)),
117
144
  method="GET"
118
145
  )
146
+ self._redis.set(f"{self.key}:{blob_name}", url, ex=int(expiration))
119
147
  return url
@@ -152,12 +152,12 @@ class ServiceManager:
152
152
  self._log_config.google_cloud_logging = None
153
153
  self._load_google_credentials()
154
154
  self._initialize_secret_manager()
155
- self._initialize_cloud_storage()
156
155
  self._load_maleo_credentials()
157
156
  self._load_configs()
158
157
  self._load_keys()
159
158
  self._initialize_loggers()
160
159
  self._initialize_cache()
160
+ self._initialize_cloud_storage()
161
161
  self._initialize_db()
162
162
  self._initialize_foundation()
163
163
 
@@ -187,23 +187,6 @@ class ServiceManager:
187
187
  def secret_manager(self) -> GoogleSecretManager:
188
188
  return self._secret_manager
189
189
 
190
- def _initialize_cloud_storage(self) -> None:
191
- environment = (
192
- BaseEnums.EnvironmentType.STAGING
193
- if self._settings.ENVIRONMENT == BaseEnums.EnvironmentType.LOCAL
194
- else self._settings.ENVIRONMENT
195
- )
196
- self._cloud_storage = GoogleCloudStorage(
197
- log_config=self._log_config,
198
- service_key=self._settings.SERVICE_KEY,
199
- bucket_name=f"maleo-suite-{environment}",
200
- credentials=self._google_credentials
201
- )
202
-
203
- @property
204
- def cloud_storage(self) -> GoogleCloudStorage:
205
- return self._cloud_storage
206
-
207
190
  def _load_maleo_credentials(self) -> None:
208
191
  environment = (
209
192
  BaseEnums.EnvironmentType.STAGING
@@ -348,6 +331,24 @@ class ServiceManager:
348
331
  def cache(self) -> CacheManagers:
349
332
  return self._cache
350
333
 
334
+ def _initialize_cloud_storage(self) -> None:
335
+ environment = (
336
+ BaseEnums.EnvironmentType.STAGING
337
+ if self._settings.ENVIRONMENT == BaseEnums.EnvironmentType.LOCAL
338
+ else self._settings.ENVIRONMENT
339
+ )
340
+ self._cloud_storage = GoogleCloudStorage(
341
+ log_config=self._log_config,
342
+ service_key=self._settings.SERVICE_KEY,
343
+ bucket_name=f"maleo-suite-{environment}",
344
+ credentials=self._google_credentials,
345
+ redis=self._redis
346
+ )
347
+
348
+ @property
349
+ def cloud_storage(self) -> GoogleCloudStorage:
350
+ return self._cloud_storage
351
+
351
352
  def _initialize_db(self) -> None:
352
353
  self._database = DatabaseManager(
353
354
  metadata=self._db_metadata,
@@ -11,12 +11,7 @@ class BaseTable:
11
11
  def __tablename__(cls) -> str:
12
12
  return CaseFormatter.to_snake_case(cls.__name__)
13
13
 
14
- #* ----- ----- Common columns definition ----- ----- *#
15
-
16
- #* Identifiers
17
- id = Column(Integer, primary_key=True)
18
- uuid = Column(UUID, default=uuid4, unique=True, nullable=False)
19
-
14
+ class DataMixin:
20
15
  #* Timestamps
21
16
  created_at = Column(
22
17
  TIMESTAMP(timezone=True),
@@ -43,4 +38,35 @@ class BaseTable:
43
38
  Enum(BaseEnums.StatusType, name="statustype"),
44
39
  default=BaseEnums.StatusType.ACTIVE,
45
40
  nullable=False
46
- )
41
+ )
42
+
43
+ class DataIdentifiers:
44
+ #* Identifiers
45
+ id = Column(Integer, primary_key=True)
46
+ uuid = Column(UUID, default=uuid4, unique=True, nullable=False)
47
+
48
+ class DataTable(
49
+ DataMixin,
50
+ DataIdentifiers
51
+ ): pass
52
+
53
+ class AccessIdentifiers:
54
+ #* Identifiers
55
+ access_id = Column(Integer, primary_key=True)
56
+ access_uuid = Column(UUID, default=uuid4, unique=True, nullable=False)
57
+ accessed_at = Column(
58
+ TIMESTAMP(timezone=True),
59
+ server_default=func.now(),
60
+ nullable=False
61
+ )
62
+ accessed_by = Column(Integer, default=0, nullable=False)
63
+
64
+ class AccessMixin:
65
+ id = Column(Integer)
66
+ uuid = Column(UUID)
67
+
68
+ class AccessTable(
69
+ DataMixin,
70
+ AccessMixin,
71
+ AccessIdentifiers
72
+ ): pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.2.75
3
+ Version: 0.2.76
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -1,8 +1,8 @@
1
1
  maleo_foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  maleo_foundation/authentication.py,sha256=kmM2QKh0st2p2pac9MKP7yYNpJzI0cFwTOrMtoQ0gMI,1575
3
3
  maleo_foundation/authorization.py,sha256=euq24UEhTaimmM24Ies-kZF1zqVwM_x0Zox_6k7zyqI,281
4
- maleo_foundation/constants.py,sha256=mhoMGDeRdL9yer1lnh_KcC-rqdLEjL5iX3SBMtgV6Zk,1452
5
- maleo_foundation/enums.py,sha256=p8O-I3sotn5CiJmeDlnEHbTkPAUd9M9N9qk8aosTT6A,4265
4
+ maleo_foundation/constants.py,sha256=MBVr6IKGHQ-4loOCQTPV3vzSGnwJswpDTGaJUmGMm_Y,1442
5
+ maleo_foundation/enums.py,sha256=_xPH4Vdg6DmbRKJw9NP0yBbX8IQO-WMZaRrejCITQfI,4905
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
@@ -34,7 +34,7 @@ maleo_foundation/expanded_types/encryption/rsa.py,sha256=Esf_H8nMz2kOLAWa3M7dlD-
34
34
  maleo_foundation/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  maleo_foundation/managers/db.py,sha256=cpY1IOiUytT9XXYtzS0E9OSYOuB7jBKo0XHe__uI1Jg,5340
36
36
  maleo_foundation/managers/middleware.py,sha256=77wRCC_CWc22nSDL-UJanO3rXmSB7wLzaAIXEFjXq6M,4249
37
- maleo_foundation/managers/service.py,sha256=3POmJNxxdBxU6mvHdCyMTV7zFSp6_H8tWM2pvj-HqGk,19148
37
+ maleo_foundation/managers/service.py,sha256=_0eme0NQMsf_8UlLmrLkD9OzHrLbrKjMYUNGYcA0EPI,19179
38
38
  maleo_foundation/managers/cache/__init__.py,sha256=CeY0oof2bVl_v5WS-FKXNwn2gf3xrEMfUsHK9cHo59s,471
39
39
  maleo_foundation/managers/cache/base.py,sha256=YyPjde4KTsp2IHV6NdFMysa0ev-1GX1rtX-0jQPuIBU,837
40
40
  maleo_foundation/managers/cache/redis.py,sha256=xLa8QfXdNtghs0eBxIqc04H3XTYmxLEzrqJZAFCigvM,1150
@@ -45,13 +45,13 @@ maleo_foundation/managers/client/google/__init__.py,sha256=47DEQpj8HBSa-_TImW-5J
45
45
  maleo_foundation/managers/client/google/base.py,sha256=eIdd6C2BFIu4EyZ1j017VZaJn_nSTPGFftBwQmVAUDA,1366
46
46
  maleo_foundation/managers/client/google/parameter.py,sha256=Lnj7mQgxWQpsQwbmDRK5_bF01M1QpM5PS0eZP2q17yQ,1337
47
47
  maleo_foundation/managers/client/google/secret.py,sha256=Ski1CHYeA8vjSk2Oc2Pf4CfFrzT_RcA6NEZwza7gM7Y,4464
48
- maleo_foundation/managers/client/google/storage.py,sha256=6pmpR44mOWhgad0ylyz0xoHCAfVo-AC3cT95tRKlNNM,4370
48
+ maleo_foundation/managers/client/google/storage.py,sha256=Hq79cVreWR2AGwUzpD57NzziZjqxj__TqYIBRy-A9A0,5340
49
49
  maleo_foundation/middlewares/authentication.py,sha256=UL6kL65SvqrzemlIDopoO9N1C05eWlYMHVR2tiRsVEA,4821
50
50
  maleo_foundation/middlewares/base.py,sha256=fLctfwzfWlGSPFnSiqbV-9wDhlG2SLA1DAs-hXk0diU,14600
51
51
  maleo_foundation/middlewares/cors.py,sha256=9uvBvY2N6Vxa9RP_YtESxcWo6Doi6uS0lzAG9iLY7Uc,2288
52
52
  maleo_foundation/models/__init__.py,sha256=AaKehO7c1HyKhoTGRmNHDddSeBXkW-_YNrpOGBu8Ms8,246
53
53
  maleo_foundation/models/responses.py,sha256=nE5qThK-WgcYB-9J4wHzJltMA3PLmWbMI-dkxAxAdII,5631
54
- maleo_foundation/models/table.py,sha256=tcOwj_Heqi6ode8rbD4eeSiixEYsAtUaUyJyqrYaMAw,1327
54
+ maleo_foundation/models/table.py,sha256=yFv9KAr0kp-QqfIFEPXqRn61pQKCCIory1zEL7Y7rVc,1873
55
55
  maleo_foundation/models/schemas/__init__.py,sha256=Xj8Ahsqyra-fmEaVcGPok5GOOsPQlKcknHYMvbjvENA,277
56
56
  maleo_foundation/models/schemas/encryption.py,sha256=KYs2P57AqWpEROuqTuSuyt1Zk-jsIUKFeRWIfSwem74,658
57
57
  maleo_foundation/models/schemas/general.py,sha256=W6bncs4z7tMiRL06xs4Q3mh9xHv7zXOXaDPC2VKr4vk,3430
@@ -118,7 +118,7 @@ maleo_foundation/utils/loaders/credential/__init__.py,sha256=qopTKvcMVoTFwyRijeg
118
118
  maleo_foundation/utils/loaders/credential/google.py,sha256=HUcuHD4tXHPt0eHInlFYxA_MDrGSOtbenpd0PX156OM,1255
119
119
  maleo_foundation/utils/loaders/key/__init__.py,sha256=hVygcC2ImHc_aVrSrOmyedR8tMUZokWUKCKOSh5ctbo,106
120
120
  maleo_foundation/utils/loaders/key/rsa.py,sha256=gDhyX6iTFtHiluuhFCozaZ3pOLKU2Y9TlrNMK_GVyGU,3796
121
- maleo_foundation-0.2.75.dist-info/METADATA,sha256=tva9GqGCYPgZsvrPCyDlXKyDKWymSUOKkbLGbr1848s,3598
122
- maleo_foundation-0.2.75.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
123
- maleo_foundation-0.2.75.dist-info/top_level.txt,sha256=_iBos3F_bhEOdjOnzeiEYSrCucasc810xXtLBXI8cQc,17
124
- maleo_foundation-0.2.75.dist-info/RECORD,,
121
+ maleo_foundation-0.2.76.dist-info/METADATA,sha256=xcB30u5nhK0ok6NTydC63dormNoi0ObMokMjqOTxyu0,3598
122
+ maleo_foundation-0.2.76.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
123
+ maleo_foundation-0.2.76.dist-info/top_level.txt,sha256=_iBos3F_bhEOdjOnzeiEYSrCucasc810xXtLBXI8cQc,17
124
+ maleo_foundation-0.2.76.dist-info/RECORD,,