csrd-utils 0.3.57__tar.gz → 0.3.58__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 (115) hide show
  1. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/PKG-INFO +1 -1
  2. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/pyproject.toml +1 -1
  3. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/auth_view.py +40 -14
  4. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/users_view.py +40 -14
  5. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/.gitignore +0 -0
  6. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/README.md +0 -0
  7. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/__init__.py +0 -0
  8. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/__main__.py +0 -0
  9. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/audit.py +0 -0
  10. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/augmentor.py +0 -0
  11. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/cluster.py +0 -0
  12. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/doctor.py +0 -0
  13. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/conftest.fragment.py +0 -0
  14. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/docker-compose.fragment.yaml +0 -0
  15. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/manifest.yaml +0 -0
  16. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/requirements.fragment +0 -0
  17. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/settings.fragment.py +0 -0
  18. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/src/app/cache.py +0 -0
  19. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/caching/tests/test_cache.py +0 -0
  20. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/logging/conftest.fragment.py +0 -0
  21. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/logging/manifest.yaml +0 -0
  22. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/logging/requirements.fragment +0 -0
  23. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/logging/settings.fragment.py +0 -0
  24. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/logging/src/app/middleware/logging.py +0 -0
  25. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/logging/tests/test_logging_middleware.py +0 -0
  26. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/conftest.fragment.py +0 -0
  27. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/docker-compose.fragment.yaml +0 -0
  28. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/manifest.yaml +0 -0
  29. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/requirements.fragment +0 -0
  30. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/settings.fragment.py +0 -0
  31. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/src/app/middleware/metrics.py +0 -0
  32. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/metrics/tests/test_metrics_middleware.py +0 -0
  33. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/tracing/conftest.fragment.py +0 -0
  34. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/tracing/manifest.yaml +0 -0
  35. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/tracing/requirements.fragment +0 -0
  36. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/tracing/settings.fragment.py +0 -0
  37. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/tracing/src/app/middleware/tracing.py +0 -0
  38. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/tracing/tests/test_tracing_middleware.py +0 -0
  39. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/conftest.fragment.py +0 -0
  40. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/docker-compose.fragment.yaml +0 -0
  41. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/manifest.yaml +0 -0
  42. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/requirements.fragment +0 -0
  43. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/settings.fragment.py +0 -0
  44. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/src/app/workers/__init__.py +0 -0
  45. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/src/app/workers/celery_app.py +0 -0
  46. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/src/app/workers/tasks.py +0 -0
  47. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/features/workers/tests/test_workers.py +0 -0
  48. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/fragments.py +0 -0
  49. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/generator.py +0 -0
  50. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/resources.py +0 -0
  51. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/README.md +0 -0
  52. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/cookiecutter.json +0 -0
  53. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/hooks/post_gen_project.py +0 -0
  54. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.cookiecutterignore +0 -0
  55. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  56. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  57. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  58. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  59. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/cache.py +0 -0
  60. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/__init__.py +0 -0
  61. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/delegates/upstreams.py +0 -0
  62. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  63. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/delegates.py +0 -0
  64. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/item_repository.py +0 -0
  65. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/dependencies/worker_broker.py +0 -0
  66. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/docker-compose.yml +0 -0
  67. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/__init__.py +0 -0
  68. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/middleware/logging.py +0 -0
  69. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  70. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/repositories/item_repository.py +0 -0
  71. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  72. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  73. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/__init__.py +0 -0
  74. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/__init__.py +0 -0
  75. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/acceptance/test_logging_middleware.py +0 -0
  76. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/conftest.py +0 -0
  77. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/test_items.py +0 -0
  78. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/__init__.py +0 -0
  79. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_cache.py +0 -0
  80. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_database_settings.py +0 -0
  81. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_delegates.py +0 -0
  82. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_settings_contracts.py +0 -0
  83. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/tests/unit/test_worker_broker.py +0 -0
  84. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  85. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  86. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  87. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/views/unversioned/items_view.py +0 -0
  88. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/__init__.py +0 -0
  89. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/cookiecutter-service/{{cookiecutter.__service_name_snake}}/workers/tasks.py +0 -0
  90. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/cookiecutter.json +0 -0
  91. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  92. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  93. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  94. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  95. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  96. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  97. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/repositories/token_repository.py +0 -0
  98. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  99. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  100. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  101. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  102. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-auth-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
  103. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/cookiecutter.json +0 -0
  104. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/.dockerignore +0 -0
  105. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/Dockerfile +0 -0
  106. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/README.md +0 -0
  107. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/__init__.py +0 -0
  108. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/dependencies/__init__.py +0 -0
  109. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/__init__.py +0 -0
  110. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/repositories/user_repository.py +0 -0
  111. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/requirements.txt +0 -0
  112. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/settings.py +0 -0
  113. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/__init__.py +0 -0
  114. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/__init__.py +0 -0
  115. {csrd_utils-0.3.57 → csrd_utils-0.3.58}/src/csrd_utils/templates/platform-identity-service/{{cookiecutter.__service_name_snake}}/views/unversioned/health_view.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: csrd-utils
3
- Version: 0.3.57
3
+ Version: 0.3.58
4
4
  Summary: CLI utilities for csrd service generation and feature augmentation
5
5
  Project-URL: Repository, https://github.com/csrd-api/fastapi-common
6
6
  Project-URL: Documentation, https://github.com/csrd-api/fastapi-common/tree/main/packages/utils
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "csrd-utils"
3
- version = "0.3.57"
3
+ version = "0.3.58"
4
4
  description = "CLI utilities for csrd service generation and feature augmentation"
5
5
  license = { text = "MIT" }
6
6
  requires-python = ">=3.12"
@@ -22,6 +22,30 @@ class VerifyRequest(BaseModel):
22
22
  token: str
23
23
 
24
24
 
25
+ class TokenResponse(BaseModel):
26
+ """JWT token issuance response."""
27
+
28
+ access_token: str
29
+ token_type: str
30
+ expires_in: int
31
+
32
+
33
+ class VerifyClaims(BaseModel):
34
+ """JWT claim fields returned by verify endpoint."""
35
+
36
+ sub: str
37
+ user_name: str
38
+ authorities: list[str]
39
+ roles: list[str]
40
+
41
+
42
+ class TokenVerifyResponse(BaseModel):
43
+ """Token verification response."""
44
+
45
+ valid: bool
46
+ claims: VerifyClaims
47
+
48
+
25
49
  def _make_verifier() -> JWTAuthenticator:
26
50
  return JWTAuthenticator(
27
51
  key=StaticKeyProvider(settings.jwt_secret),
@@ -57,10 +81,10 @@ async def _validate_credentials(username: str, password: str) -> list[str]:
57
81
  return list(user.get("roles", []))
58
82
 
59
83
 
60
- @router.post("/token")
84
+ @router.post("/token", response_model=TokenResponse)
61
85
  async def issue_token(
62
86
  payload: TokenRequest, token_repo: TokenRepositoryDep
63
- ) -> dict[str, str | int | list[str]]:
87
+ ) -> TokenResponse:
64
88
  roles = await _validate_credentials(payload.username, payload.password)
65
89
 
66
90
  now = datetime.now(UTC)
@@ -75,19 +99,21 @@ async def issue_token(
75
99
  }
76
100
  token = jwt.encode(claims, settings.jwt_secret, algorithm=settings.jwt_algorithm)
77
101
  await token_repo.record_issued_token(token=token, subject=payload.username)
78
- return {"access_token": token, "token_type": "bearer", "expires_in": settings.jwt_ttl_seconds}
102
+ return TokenResponse(
103
+ access_token=token, token_type="bearer", expires_in=settings.jwt_ttl_seconds
104
+ )
79
105
 
80
106
 
81
- @router.post("/verify")
82
- async def verify_token(request: Request, payload: VerifyRequest) -> dict[str, object]:
107
+ @router.post("/verify", response_model=TokenVerifyResponse)
108
+ async def verify_token(request: Request, payload: VerifyRequest) -> TokenVerifyResponse:
83
109
  verifier = _make_verifier()
84
110
  claims = await verifier(request, payload.token)
85
- return {
86
- "valid": True,
87
- "claims": {
88
- "sub": claims.sub,
89
- "user_name": claims.user_name,
90
- "authorities": claims.authorities,
91
- "roles": claims.authorities,
92
- },
93
- }
111
+ return TokenVerifyResponse(
112
+ valid=True,
113
+ claims=VerifyClaims(
114
+ sub=claims.sub,
115
+ user_name=claims.user_name,
116
+ authorities=claims.authorities,
117
+ roles=claims.authorities,
118
+ ),
119
+ )
@@ -20,21 +20,43 @@ class AssignRoleRequest(BaseModel):
20
20
  role: str
21
21
 
22
22
 
23
- @router.get("/users/{user_id}")
24
- async def get_user(user_id: str, repo: UserRepositoryDep) -> dict[str, str]:
23
+ class UserInfo(BaseModel):
24
+ """User information."""
25
+
26
+ id: str
27
+ username: str
28
+ created_at: str
29
+
30
+
31
+ class UserRolesResponse(BaseModel):
32
+ """User roles response."""
33
+
34
+ user_id: str
35
+ roles: list[str]
36
+
37
+
38
+ class VerifyCredentialsResponse(BaseModel):
39
+ """Credentials verification response."""
40
+
41
+ valid: bool
42
+ user: UserInfo
43
+
44
+
45
+ @router.get("/users/{user_id}", response_model=UserInfo)
46
+ async def get_user(user_id: str, repo: UserRepositoryDep) -> UserInfo:
25
47
  user = await repo.get_user(user_id)
26
48
  if user is None:
27
49
  raise HTTPException(status_code=404, detail="user not found")
28
- return user
50
+ return UserInfo(**user)
29
51
 
30
52
 
31
- @router.get("/users/{user_id}/roles")
32
- async def get_user_roles(user_id: str, repo: UserRepositoryDep) -> dict[str, object]:
53
+ @router.get("/users/{user_id}/roles", response_model=UserRolesResponse)
54
+ async def get_user_roles(user_id: str, repo: UserRepositoryDep) -> UserRolesResponse:
33
55
  user = await repo.get_user(user_id)
34
56
  if user is None:
35
57
  raise HTTPException(status_code=404, detail="user not found")
36
58
  roles = await repo.get_roles(user_id)
37
- return {"user_id": user_id, "roles": roles}
59
+ return UserRolesResponse(user_id=user_id, roles=roles)
38
60
 
39
61
 
40
62
  @router.post("/users/{user_id}/roles", status_code=204)
@@ -45,19 +67,23 @@ async def assign_role(user_id: str, payload: AssignRoleRequest, repo: UserReposi
45
67
  await repo.assign_role(user_id, payload.role)
46
68
 
47
69
 
48
- @router.post("/verify-credentials")
70
+ @router.post("/verify-credentials", response_model=VerifyCredentialsResponse)
49
71
  async def verify_credentials(
50
72
  repo: UserRepositoryDep, payload: VerifyCredentialsRequest
51
- ) -> dict[str, object]:
52
- user = await repo.verify_credentials(payload.username, payload.password)
53
- if user is None:
73
+ ) -> VerifyCredentialsResponse:
74
+ user_data = await repo.verify_credentials(payload.username, payload.password)
75
+ if user_data is None:
54
76
  raise HTTPException(status_code=401, detail="invalid credentials")
55
- return {"valid": True, "user": user}
77
+ return VerifyCredentialsResponse(
78
+ valid=True,
79
+ user=UserInfo(**user_data),
80
+ )
56
81
 
57
82
 
58
- @router.post("/signup")
59
- async def create_user(repo: UserRepositoryDep, payload: SignupRequest) -> dict[str, str]:
83
+ @router.post("/signup", response_model=UserInfo)
84
+ async def create_user(repo: UserRepositoryDep, payload: SignupRequest) -> UserInfo:
60
85
  try:
61
- return await repo.signup(payload.username, payload.password)
86
+ user_data = await repo.signup(payload.username, payload.password)
87
+ return UserInfo(**user_data)
62
88
  except ValueError as exc:
63
89
  raise HTTPException(status_code=409, detail=str(exc)) from exc
File without changes
File without changes