|
1 | | -import functools |
2 | 1 | import logging |
3 | 2 |
|
4 | 3 | from aiohttp import web |
|
12 | 11 | parse_request_body_as, |
13 | 12 | parse_request_query_parameters_as, |
14 | 13 | ) |
15 | | -from servicelib.aiohttp.typing_extension import Handler |
16 | | -from servicelib.logging_errors import create_troubleshotting_log_kwargs |
17 | 14 | from servicelib.rest_constants import RESPONSE_MODEL_POLICY |
18 | 15 |
|
19 | 16 | from .._meta import API_VTAG |
| 17 | +from ..exception_handling import ( |
| 18 | + ExceptionToHttpErrorMap, |
| 19 | + HttpErrorInfo, |
| 20 | + exception_handling_decorator, |
| 21 | + to_exceptions_handlers_map, |
| 22 | +) |
20 | 23 | from ..login.decorators import login_required |
21 | 24 | from ..security.decorators import permission_required |
22 | 25 | from ..utils_aiohttp import envelope_json_response |
23 | 26 | from . import _users_service, api |
24 | | -from ._common.constants import FMSG_MISSING_CONFIG_WITH_OEC |
25 | 27 | from ._common.schemas import PreRegisteredUserGet, UsersRequestContext |
26 | 28 | from .exceptions import ( |
27 | 29 | AlreadyPreRegisteredError, |
|
33 | 35 | _logger = logging.getLogger(__name__) |
34 | 36 |
|
35 | 37 |
|
36 | | -routes = web.RouteTableDef() |
37 | | - |
38 | | - |
39 | | -def _handle_users_exceptions(handler: Handler): |
40 | | - @functools.wraps(handler) |
41 | | - async def wrapper(request: web.Request) -> web.StreamResponse: |
42 | | - try: |
43 | | - return await handler(request) |
44 | | - |
45 | | - except UserNotFoundError as exc: |
46 | | - raise web.HTTPNotFound(reason=f"{exc}") from exc |
| 38 | +_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = { |
| 39 | + UserNotFoundError: HttpErrorInfo( |
| 40 | + status.HTTP_404_NOT_FOUND, |
| 41 | + "This user cannot be found. Either it is not registered or has enabled privacy settings.", |
| 42 | + ), |
| 43 | + UserNameDuplicateError: HttpErrorInfo( |
| 44 | + status.HTTP_409_CONFLICT, |
| 45 | + "Username '{user_name}' is already taken. " |
| 46 | + "Consider '{alternative_user_name}' instead.", |
| 47 | + ), |
| 48 | + AlreadyPreRegisteredError: HttpErrorInfo( |
| 49 | + status.HTTP_409_CONFLICT, |
| 50 | + "Found {num_found} matches for '{email}'. Cannot pre-register existing user", |
| 51 | + ), |
| 52 | + MissingGroupExtraPropertiesForProductError: HttpErrorInfo( |
| 53 | + status.HTTP_503_SERVICE_UNAVAILABLE, |
| 54 | + "The product is not ready for use until the configuration is fully completed. " |
| 55 | + "Please wait and try again. " |
| 56 | + "If this issue persists, contact support indicating this support code: {error_code}.", |
| 57 | + ), |
| 58 | +} |
| 59 | + |
| 60 | +_handle_users_exceptions = exception_handling_decorator( |
| 61 | + to_exceptions_handlers_map(_TO_HTTP_ERROR_MAP) |
| 62 | +) |
47 | 63 |
|
48 | | - except UserNameDuplicateError as exc: |
49 | | - raise web.HTTPConflict(reason=f"{exc}") from exc |
50 | 64 |
|
51 | | - except MissingGroupExtraPropertiesForProductError as exc: |
52 | | - error_code = exc.error_code() |
53 | | - user_error_msg = FMSG_MISSING_CONFIG_WITH_OEC.format(error_code=error_code) |
54 | | - _logger.exception( |
55 | | - **create_troubleshotting_log_kwargs( |
56 | | - user_error_msg, |
57 | | - error=exc, |
58 | | - error_code=error_code, |
59 | | - tip="Row in `groups_extra_properties` for this product is missing.", |
60 | | - ) |
61 | | - ) |
62 | | - raise web.HTTPServiceUnavailable(reason=user_error_msg) from exc |
| 65 | +routes = web.RouteTableDef() |
63 | 66 |
|
64 | | - return wrapper |
| 67 | +# |
| 68 | +# MY PROFILE: /me |
| 69 | +# |
65 | 70 |
|
66 | 71 |
|
67 | 72 | @routes.get(f"/{API_VTAG}/me", name="get_my_profile") |
@@ -94,6 +99,10 @@ async def update_my_profile(request: web.Request) -> web.Response: |
94 | 99 | return web.json_response(status=status.HTTP_204_NO_CONTENT) |
95 | 100 |
|
96 | 101 |
|
| 102 | +# |
| 103 | +# USERS (only POs) |
| 104 | +# |
| 105 | + |
97 | 106 | _RESPONSE_MODEL_MINIMAL_POLICY = RESPONSE_MODEL_POLICY.copy() |
98 | 107 | _RESPONSE_MODEL_MINIMAL_POLICY["exclude_none"] = True |
99 | 108 |
|
@@ -127,12 +136,9 @@ async def pre_register_user(request: web.Request) -> web.Response: |
127 | 136 | req_ctx = UsersRequestContext.model_validate(request) |
128 | 137 | pre_user_profile = await parse_request_body_as(PreRegisteredUserGet, request) |
129 | 138 |
|
130 | | - try: |
131 | | - user_profile = await _users_service.pre_register_user( |
132 | | - request.app, profile=pre_user_profile, creator_user_id=req_ctx.user_id |
133 | | - ) |
134 | | - return envelope_json_response( |
135 | | - user_profile.model_dump(**_RESPONSE_MODEL_MINIMAL_POLICY) |
136 | | - ) |
137 | | - except AlreadyPreRegisteredError as err: |
138 | | - raise web.HTTPConflict(reason=f"{err}") from err |
| 139 | + user_profile = await _users_service.pre_register_user( |
| 140 | + request.app, profile=pre_user_profile, creator_user_id=req_ctx.user_id |
| 141 | + ) |
| 142 | + return envelope_json_response( |
| 143 | + user_profile.model_dump(**_RESPONSE_MODEL_MINIMAL_POLICY) |
| 144 | + ) |
0 commit comments