Skip to content

Commit c73e391

Browse files
committed
rest exceptions
1 parent 57ad4d6 commit c73e391

File tree

7 files changed

+39
-125
lines changed

7 files changed

+39
-125
lines changed
Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +0,0 @@
1-
""" webserver's login subsystem
2-
3-
4-
This sub-package is based on aiohttp-login https://github.com/imbolc/aiohttp-login
5-
"""
Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,2 @@
1-
from typing import Any
2-
3-
from aiohttp import web
4-
from models_library.products import ProductName
5-
from models_library.users import UserID
6-
from pydantic import PositiveInt
7-
from servicelib.aiohttp import observer
8-
from simcore_postgres_database.models.users import UserRole
9-
10-
from ..db.models import ConfirmationAction, UserStatus
11-
from .constants import (
12-
MSG_ACTIVATION_REQUIRED,
13-
MSG_USER_BANNED,
14-
MSG_USER_DELETED,
15-
MSG_USER_EXPIRED,
16-
)
17-
18-
19-
def _to_names(enum_cls, names) -> list[str]:
20-
"""ensures names are in enum be retrieving each of them"""
21-
return [getattr(enum_cls, att).name for att in names.split()]
22-
23-
24-
CONFIRMATION_PENDING, ACTIVE, BANNED, EXPIRED, DELETED = (
25-
UserStatus.CONFIRMATION_PENDING.name,
26-
UserStatus.ACTIVE.name,
27-
UserStatus.BANNED.name,
28-
UserStatus.EXPIRED.name,
29-
UserStatus.DELETED.name,
30-
)
31-
_EXPECTED_ENUMS = 5
32-
assert len(UserStatus) == _EXPECTED_ENUMS # nosec
33-
34-
35-
ANONYMOUS, GUEST, USER, TESTER = _to_names(UserRole, "ANONYMOUS GUEST USER TESTER")
36-
37-
REGISTRATION, RESET_PASSWORD, CHANGE_EMAIL = _to_names(
38-
ConfirmationAction, "REGISTRATION RESET_PASSWORD CHANGE_EMAIL"
39-
)
40-
41-
42-
def validate_user_status(*, user: dict, support_email: str):
43-
"""
44-
45-
Raises:
46-
web.HTTPUnauthorized
47-
"""
48-
assert "role" in user # nosec
49-
50-
user_status: str = user["status"]
51-
52-
if user_status == DELETED:
53-
raise web.HTTPUnauthorized(
54-
text=MSG_USER_DELETED.format(support_email=support_email),
55-
) # 401
56-
57-
if user_status == BANNED or user["role"] == ANONYMOUS:
58-
raise web.HTTPUnauthorized(
59-
text=MSG_USER_BANNED.format(support_email=support_email),
60-
) # 401
61-
62-
if user_status == EXPIRED:
63-
raise web.HTTPUnauthorized(
64-
text=MSG_USER_EXPIRED.format(support_email=support_email),
65-
) # 401
66-
67-
if user_status == CONFIRMATION_PENDING:
68-
raise web.HTTPUnauthorized(
69-
text=MSG_ACTIVATION_REQUIRED,
70-
) # 401
71-
72-
assert user_status == ACTIVE # nosec
73-
74-
75-
async def notify_user_confirmation(
76-
app: web.Application,
77-
user_id: UserID,
78-
product_name: ProductName,
79-
extra_credits_in_usd: PositiveInt | None,
80-
):
81-
"""Broadcast that user with 'user_id' has login for the first-time in 'product_name'"""
82-
# NOTE: Follow up in https://github.com/ITISFoundation/osparc-simcore/issues/4822
83-
await observer.emit(
84-
app,
85-
"SIGNAL_ON_USER_CONFIRMATION",
86-
user_id=user_id,
87-
product_name=product_name,
88-
extra_credits_in_usd=extra_credits_in_usd,
89-
)
90-
91-
92-
async def notify_user_logout(
93-
app: web.Application, user_id: UserID, client_session_id: Any | None = None
94-
):
95-
"""Broadcasts logout of 'user_id' in 'client_session_id'.
96-
97-
If 'client_session_id' is None, then all sessions are considered
98-
99-
Listeners (e.g. sockets) will trigger logout mechanisms
100-
"""
101-
await observer.emit(
102-
app,
103-
"SIGNAL_USER_LOGOUT",
104-
user_id,
105-
client_session_id,
106-
app,
107-
)
108-
109-
1101
def get_user_name_from_email(email: str) -> str:
1112
return email.split("@")[0]

services/web/server/src/simcore_service_webserver/login/plugin.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
)
1212
from settings_library.email import SMTPSettings
1313
from settings_library.postgres import PostgresSettings
14+
from simcore_service_webserver.login_account.plugin import setup_login_account
1415

1516
from ..constants import (
1617
APP_PUBLIC_CONFIG_PER_PRODUCT,
@@ -147,6 +148,7 @@ def setup_login(app: web.Application):
147148

148149
app.router.add_routes(auth.routes)
149150
setup_login_auth(app)
151+
setup_login_account(app)
150152

151153
app.router.add_routes(confirmation.routes)
152154
app.router.add_routes(registration.routes)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from ....exception_handling import (
2+
ExceptionToHttpErrorMap,
3+
exception_handling_decorator,
4+
to_exceptions_handlers_map,
5+
)
6+
from ....login._controller.rest._rest_exceptions import (
7+
_TO_HTTP_ERROR_MAP as LOGIN_TO_HTTP_ERROR_MAP,
8+
)
9+
10+
_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = {**LOGIN_TO_HTTP_ERROR_MAP}
11+
12+
13+
handle_rest_requests_exceptions = exception_handling_decorator(
14+
to_exceptions_handlers_map(_TO_HTTP_ERROR_MAP)
15+
)

services/web/server/src/simcore_service_webserver/login_account/_controller/rest/preregistration.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@
1313
from servicelib.utils import fire_and_forget_task
1414

1515
from ...._meta import API_VTAG
16-
from ....login._controller.rest._rest_exceptions import handle_rest_requests_exceptions
17-
from ....login._login_service import notify_user_logout
16+
from ....login import login_service
1817
from ....login.constants import (
1918
CAPTCHA_SESSION_KEY,
2019
MSG_LOGGED_OUT,
2120
MSG_WRONG_CAPTCHA__INVALID,
2221
)
23-
from ....login.settings import LoginSettingsForProduct, get_plugin_settings
22+
from ....login.settings import get_plugin_settings
2423
from ....login.web_utils import flash_response
2524
from ....login_auth.decorators import login_required
2625
from ....models import AuthenticatedRequestContext
@@ -34,13 +33,11 @@
3433
from ....utils import MINUTE
3534
from ....utils_rate_limiting import global_rate_limit_route
3635
from ... import _preregistration_service
36+
from ._rest_exceptions import handle_rest_requests_exceptions
3737

3838
_logger = logging.getLogger(__name__)
3939

4040

41-
routes = web.RouteTableDef()
42-
43-
4441
def _get_ipinfo(request: web.Request) -> dict[str, Any]:
4542
# NOTE: Traefik is also configured to transmit the original IP.
4643
x_real_ip = request.headers.get("X-Real-IP", None)
@@ -56,6 +53,9 @@ def _get_ipinfo(request: web.Request) -> dict[str, Any]:
5653
}
5754

5855

56+
routes = web.RouteTableDef()
57+
58+
5959
@routes.post(
6060
f"/{API_VTAG}/auth/request-account",
6161
name="request_product_account",
@@ -104,9 +104,7 @@ async def unregister_account(request: web.Request):
104104
body = await parse_request_body_as(UnregisterCheck, request)
105105

106106
product: Product = products_web.get_current_product(request)
107-
settings: LoginSettingsForProduct = get_plugin_settings(
108-
request.app, product_name=product.name
109-
)
107+
settings = get_plugin_settings(request.app, product_name=product.name)
110108

111109
# checks before deleting
112110
credentials = await users_service.get_user_credentials(
@@ -130,7 +128,7 @@ async def unregister_account(request: web.Request):
130128
await users_service.set_user_as_deleted(request.app, user_id=req_ctx.user_id)
131129

132130
# logout
133-
await notify_user_logout(
131+
await login_service.notify_user_logout(
134132
request.app, user_id=req_ctx.user_id, client_session_id=None
135133
)
136134
response = flash_response(MSG_LOGGED_OUT, "INFO")

services/web/server/src/simcore_service_webserver/login_account/_preregistration_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ async def create_captcha() -> tuple[str, bytes]:
128128

129129

130130
async def create_pre_registration(
131-
app: web.Application, profile: PreRegisteredUserGet, product_name: ProductName
131+
app: web.Application, *, profile: PreRegisteredUserGet, product_name: ProductName
132132
):
133133

134134
await _users_service.pre_register_user(
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import logging
2+
3+
from aiohttp import web
4+
from servicelib.aiohttp.application_setup import ensure_single_setup
5+
6+
from ._controller.rest import preregistration as _controller_rest_preregistration
7+
8+
_logger = logging.getLogger(__name__)
9+
10+
11+
@ensure_single_setup(__name__, logger=_logger)
12+
def setup_login_account(app: web.Application):
13+
app.add_routes(_controller_rest_preregistration.routes)

0 commit comments

Comments
 (0)