aiteamutils 0.2.32__py3-none-any.whl → 0.2.33__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.
- aiteamutils/config.py +7 -2
- aiteamutils/database.py +16 -4
- aiteamutils/dependencies.py +12 -4
- aiteamutils/security.py +58 -23
- aiteamutils/version.py +1 -1
- {aiteamutils-0.2.32.dist-info → aiteamutils-0.2.33.dist-info}/METADATA +1 -1
- {aiteamutils-0.2.32.dist-info → aiteamutils-0.2.33.dist-info}/RECORD +8 -8
- {aiteamutils-0.2.32.dist-info → aiteamutils-0.2.33.dist-info}/WHEEL +0 -0
aiteamutils/config.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""설정 모듈."""
|
2
2
|
from typing import Union
|
3
3
|
from .database import init_database_service
|
4
|
+
from .exceptions import CustomException, ErrorCode
|
4
5
|
|
5
6
|
class Settings:
|
6
7
|
"""기본 설정 클래스"""
|
@@ -74,8 +75,12 @@ def get_settings() -> Settings:
|
|
74
75
|
Settings: 설정 객체
|
75
76
|
|
76
77
|
Raises:
|
77
|
-
|
78
|
+
CustomException: 설정이 초기화되지 않은 경우
|
78
79
|
"""
|
79
80
|
if _settings is None:
|
80
|
-
raise
|
81
|
+
raise CustomException(
|
82
|
+
ErrorCode.INTERNAL_ERROR,
|
83
|
+
detail="settings",
|
84
|
+
source_function="get_settings"
|
85
|
+
)
|
81
86
|
return _settings
|
aiteamutils/database.py
CHANGED
@@ -26,10 +26,14 @@ def get_database_service() -> 'DatabaseService':
|
|
26
26
|
DatabaseService: DatabaseService 인스턴스
|
27
27
|
|
28
28
|
Raises:
|
29
|
-
|
29
|
+
CustomException: DatabaseService가 초기화되지 않은 경우
|
30
30
|
"""
|
31
31
|
if _database_service is None:
|
32
|
-
raise
|
32
|
+
raise CustomException(
|
33
|
+
ErrorCode.DB_CONNECTION_ERROR,
|
34
|
+
detail="database_service",
|
35
|
+
source_function="get_database_service"
|
36
|
+
)
|
33
37
|
return _database_service
|
34
38
|
|
35
39
|
async def get_db() -> AsyncGenerator[AsyncSession, None]:
|
@@ -100,13 +104,21 @@ class DatabaseService:
|
|
100
104
|
)
|
101
105
|
self.db = session
|
102
106
|
else:
|
103
|
-
raise
|
107
|
+
raise CustomException(
|
108
|
+
ErrorCode.DB_CONNECTION_ERROR,
|
109
|
+
detail="db_url|session",
|
110
|
+
source_function="DatabaseService.__init__"
|
111
|
+
)
|
104
112
|
|
105
113
|
@asynccontextmanager
|
106
114
|
async def get_session(self) -> AsyncGenerator[AsyncSession, None]:
|
107
115
|
"""데이터베이스 세션을 생성하고 반환하는 비동기 컨텍스트 매니저."""
|
108
116
|
if self.session_factory is None:
|
109
|
-
raise
|
117
|
+
raise CustomException(
|
118
|
+
ErrorCode.DB_CONNECTION_ERROR,
|
119
|
+
detail="session_factory",
|
120
|
+
source_function="DatabaseService.get_session"
|
121
|
+
)
|
110
122
|
|
111
123
|
async with self.session_factory() as session:
|
112
124
|
try:
|
aiteamutils/dependencies.py
CHANGED
@@ -26,10 +26,14 @@ class ServiceRegistry:
|
|
26
26
|
service_class (Type): Service 클래스
|
27
27
|
|
28
28
|
Raises:
|
29
|
-
|
29
|
+
CustomException: 이미 등록된 서비스인 경우
|
30
30
|
"""
|
31
31
|
if name in self._services:
|
32
|
-
raise
|
32
|
+
raise CustomException(
|
33
|
+
ErrorCode.INTERNAL_ERROR,
|
34
|
+
detail=f"service|{name}",
|
35
|
+
source_function="ServiceRegistry.register"
|
36
|
+
)
|
33
37
|
self._services[name] = (repository_class, service_class)
|
34
38
|
|
35
39
|
def get(self, name: str) -> Tuple[Type, Type]:
|
@@ -42,10 +46,14 @@ class ServiceRegistry:
|
|
42
46
|
Tuple[Type, Type]: (Repository 클래스, Service 클래스) 튜플
|
43
47
|
|
44
48
|
Raises:
|
45
|
-
|
49
|
+
CustomException: 등록되지 않은 서비스인 경우
|
46
50
|
"""
|
47
51
|
if name not in self._services:
|
48
|
-
raise
|
52
|
+
raise CustomException(
|
53
|
+
ErrorCode.NOT_FOUND,
|
54
|
+
detail=f"service|{name}",
|
55
|
+
source_function="ServiceRegistry.get"
|
56
|
+
)
|
49
57
|
return self._services[name]
|
50
58
|
|
51
59
|
# ServiceRegistry 초기화
|
aiteamutils/security.py
CHANGED
@@ -157,8 +157,19 @@ def verify_password(plain_password: str, hashed_password: str) -> bool:
|
|
157
157
|
|
158
158
|
Returns:
|
159
159
|
bool: 비밀번호 일치 여부
|
160
|
+
|
161
|
+
Raises:
|
162
|
+
CustomException: 비밀번호 검증 실패 시
|
160
163
|
"""
|
161
|
-
|
164
|
+
try:
|
165
|
+
return pwd_context.verify(plain_password, hashed_password)
|
166
|
+
except Exception as e:
|
167
|
+
raise CustomException(
|
168
|
+
ErrorCode.INVALID_PASSWORD,
|
169
|
+
detail=plain_password,
|
170
|
+
source_function="security.verify_password",
|
171
|
+
original_error=e
|
172
|
+
)
|
162
173
|
|
163
174
|
def hash_password(password: str) -> str:
|
164
175
|
"""비밀번호를 해시화합니다.
|
@@ -168,8 +179,19 @@ def hash_password(password: str) -> str:
|
|
168
179
|
|
169
180
|
Returns:
|
170
181
|
str: 해시된 비밀번호
|
182
|
+
|
183
|
+
Raises:
|
184
|
+
CustomException: 비밀번호 해시화 실패 시
|
171
185
|
"""
|
172
|
-
|
186
|
+
try:
|
187
|
+
return pwd_context.hash(password)
|
188
|
+
except Exception as e:
|
189
|
+
raise CustomException(
|
190
|
+
ErrorCode.INTERNAL_ERROR,
|
191
|
+
detail=password,
|
192
|
+
source_function="security.hash_password",
|
193
|
+
original_error=e
|
194
|
+
)
|
173
195
|
|
174
196
|
def rate_limit(
|
175
197
|
max_requests: int,
|
@@ -288,10 +310,10 @@ async def create_jwt_token(
|
|
288
310
|
required_fields = {"username", "ulid"}
|
289
311
|
missing_fields = required_fields - set(user_data.keys())
|
290
312
|
if missing_fields:
|
291
|
-
raise
|
292
|
-
|
293
|
-
|
294
|
-
|
313
|
+
raise CustomException(
|
314
|
+
ErrorCode.REQUIRED_FIELD_MISSING,
|
315
|
+
detail="|".join(missing_fields),
|
316
|
+
source_function="security.create_jwt_token"
|
295
317
|
)
|
296
318
|
|
297
319
|
if token_type == "access":
|
@@ -337,10 +359,10 @@ async def create_jwt_token(
|
|
337
359
|
algorithm=settings.JWT_ALGORITHM
|
338
360
|
)
|
339
361
|
except Exception as e:
|
340
|
-
raise
|
341
|
-
|
342
|
-
|
343
|
-
|
362
|
+
raise CustomException(
|
363
|
+
ErrorCode.INTERNAL_ERROR,
|
364
|
+
detail=f"token|{token_type}",
|
365
|
+
source_function="security.create_jwt_token",
|
344
366
|
original_error=e
|
345
367
|
)
|
346
368
|
|
@@ -362,13 +384,13 @@ async def create_jwt_token(
|
|
362
384
|
|
363
385
|
return token
|
364
386
|
|
365
|
-
except
|
387
|
+
except CustomException as e:
|
366
388
|
raise e
|
367
389
|
except Exception as e:
|
368
|
-
raise
|
390
|
+
raise CustomException(
|
369
391
|
ErrorCode.INTERNAL_ERROR,
|
370
392
|
detail=str(e),
|
371
|
-
source_function="create_jwt_token",
|
393
|
+
source_function="security.create_jwt_token",
|
372
394
|
original_error=e
|
373
395
|
)
|
374
396
|
|
@@ -376,7 +398,18 @@ async def verify_jwt_token(
|
|
376
398
|
token: str,
|
377
399
|
expected_type: Optional[Literal["access", "refresh"]] = None
|
378
400
|
) -> Dict[str, Any]:
|
379
|
-
"""JWT 토큰을 검증합니다.
|
401
|
+
"""JWT 토큰을 검증합니다.
|
402
|
+
|
403
|
+
Args:
|
404
|
+
token: 검증할 JWT 토큰
|
405
|
+
expected_type: 예상되는 토큰 타입
|
406
|
+
|
407
|
+
Returns:
|
408
|
+
Dict[str, Any]: 토큰 페이로드
|
409
|
+
|
410
|
+
Raises:
|
411
|
+
CustomException: 토큰 검증 실패 시
|
412
|
+
"""
|
380
413
|
try:
|
381
414
|
settings = get_settings()
|
382
415
|
# 토큰 디코딩
|
@@ -390,25 +423,27 @@ async def verify_jwt_token(
|
|
390
423
|
|
391
424
|
# 토큰 타입 검증 (expected_type이 주어진 경우에만)
|
392
425
|
if expected_type and payload.get("token_type") != expected_type:
|
393
|
-
raise
|
394
|
-
|
395
|
-
|
426
|
+
raise CustomException(
|
427
|
+
ErrorCode.INVALID_TOKEN,
|
428
|
+
detail=f"token|{expected_type}|{payload.get('token_type')}",
|
429
|
+
source_function="security.verify_jwt_token"
|
396
430
|
)
|
397
431
|
|
398
432
|
return payload
|
399
433
|
|
400
434
|
except JWTError as e:
|
401
|
-
raise
|
402
|
-
|
403
|
-
|
435
|
+
raise CustomException(
|
436
|
+
ErrorCode.INVALID_TOKEN,
|
437
|
+
detail=token[:10] + "...",
|
438
|
+
source_function="security.verify_jwt_token",
|
404
439
|
original_error=e
|
405
440
|
)
|
406
|
-
except
|
441
|
+
except CustomException as e:
|
407
442
|
raise e
|
408
443
|
except Exception as e:
|
409
|
-
raise
|
444
|
+
raise CustomException(
|
410
445
|
ErrorCode.INTERNAL_ERROR,
|
411
446
|
detail=str(e),
|
412
|
-
source_function="verify_jwt_token",
|
447
|
+
source_function="security.verify_jwt_token",
|
413
448
|
original_error=e
|
414
449
|
)
|
aiteamutils/version.py
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
"""버전 정보"""
|
2
|
-
__version__ = "0.2.
|
2
|
+
__version__ = "0.2.33"
|
@@ -3,14 +3,14 @@ aiteamutils/base_model.py,sha256=ODEnjvUVoxQ1RPCfq8-uZTfTADIA4c7Z3E6G4EVsSX0,270
|
|
3
3
|
aiteamutils/base_repository.py,sha256=qdwQ7Sj2fUqxpDg6cWM48n_QbwPK_VUlG9zTSem8iCk,18968
|
4
4
|
aiteamutils/base_service.py,sha256=E4dHGE0DvhmRyFplh46SwKJOSF_nUL7OAsCkf_ZJF_8,24733
|
5
5
|
aiteamutils/cache.py,sha256=tr0Yn8VPYA9QHiKCUzciVlQ2J1RAwNo2K9lGMH4rY3s,1334
|
6
|
-
aiteamutils/config.py,sha256=
|
7
|
-
aiteamutils/database.py,sha256=
|
8
|
-
aiteamutils/dependencies.py,sha256=
|
6
|
+
aiteamutils/config.py,sha256=kFKMeIx1KcuEwwx4VjZdCgoTOHCkG3ySYVJ0G6cvMoA,2849
|
7
|
+
aiteamutils/database.py,sha256=CaH73g8PPNcmLCz4Xr0DBtNSrLcpRlyt0F1zO5Tigfo,33811
|
8
|
+
aiteamutils/dependencies.py,sha256=GgN8sFM7qGNmOfpLaFrhuHOgPlBVXWrEgxv29jxjEgI,4226
|
9
9
|
aiteamutils/enums.py,sha256=ipZi6k_QD5-3QV7Yzv7bnL0MjDz-vqfO9I5L77biMKs,632
|
10
10
|
aiteamutils/exceptions.py,sha256=YV-ISya4wQlHk4twvGo16I5r8h22-tXpn9wa-b3WwDM,15231
|
11
|
-
aiteamutils/security.py,sha256=
|
11
|
+
aiteamutils/security.py,sha256=nqAyypyiZ26s-eKv7c6YPDTK6HcqimFnoCr12Wtg1DY,14449
|
12
12
|
aiteamutils/validators.py,sha256=3N245cZFjgwtW_KzjESkizx5BBUDaJLbbxfNO4WOFZ0,7764
|
13
|
-
aiteamutils/version.py,sha256=
|
14
|
-
aiteamutils-0.2.
|
15
|
-
aiteamutils-0.2.
|
16
|
-
aiteamutils-0.2.
|
13
|
+
aiteamutils/version.py,sha256=0u62c8uMhBIqtJ4INrTiDbrTgFVL2CBQ_nfjWnhrldU,42
|
14
|
+
aiteamutils-0.2.33.dist-info/METADATA,sha256=DUbbkj6hQ_0C7ODwi8AuQJ1W1BYAMF8_45epV7wl27I,1718
|
15
|
+
aiteamutils-0.2.33.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
16
|
+
aiteamutils-0.2.33.dist-info/RECORD,,
|
File without changes
|