Skip to content

Commit 6764706

Browse files
committed
split
1 parent cbea6dd commit 6764706

File tree

3 files changed

+83
-75
lines changed

3 files changed

+83
-75
lines changed

services/web/server/src/simcore_service_webserver/users/_controller/rest/users_rest.py

Lines changed: 1 addition & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import logging
22
from contextlib import suppress
3-
from typing import Literal, TypedDict
43

54
from aiohttp import web
6-
from aiohttp_session import Session
75
from models_library.api_schemas_webserver.users import (
86
MyPhoneConfirm,
97
MyPhoneRegister,
@@ -12,7 +10,6 @@
1210
UserGet,
1311
UsersSearch,
1412
)
15-
from models_library.users import UserID
1613
from servicelib.aiohttp import status
1714
from servicelib.aiohttp.requests_validation import (
1815
parse_request_body_as,
@@ -31,80 +28,17 @@
3128
from ....session.api import get_session
3229
from ....utils_aiohttp import envelope_json_response
3330
from ... import _users_service
34-
from ...exceptions import (
35-
PhoneRegistrationCodeInvalidError,
36-
PhoneRegistrationPendingNotFoundError,
37-
PhoneRegistrationSessionInvalidError,
38-
)
31+
from ..._users_web import RegistrationSessionManager
3932
from ._rest_exceptions import handle_rest_requests_exceptions
4033
from ._rest_schemas import UsersRequestContext
4134

4235
_logger = logging.getLogger(__name__)
4336

44-
# Registration session keys
45-
_REGISTRATION_KEY = "registration"
46-
_REGISTRATION_PENDING_KEY = "registration_pending"
47-
_REGISTRATION_CODE_KEY = "registration_code"
4837
_REGISTRATION_CODE_VALUE_FAKE = (
4938
"123456" # NOTE: temporary fake while developing registration feature
5039
)
5140

5241

53-
class RegistrationData(TypedDict):
54-
"""Registration session data structure."""
55-
56-
user_id: UserID
57-
data: str
58-
status: Literal["pending_confirmation"]
59-
60-
61-
class RegistrationSessionManager:
62-
def __init__(self, session: Session, user_id: UserID, product_name: str):
63-
self._session = session
64-
self._user_id = user_id
65-
self._product_name = product_name
66-
67-
def start_registration(self, data: str, code: str) -> None:
68-
registration_data: RegistrationData = {
69-
"user_id": self._user_id,
70-
"data": data, # keep data
71-
"status": "pending_confirmation",
72-
}
73-
self._session[_REGISTRATION_KEY] = registration_data
74-
self._session[_REGISTRATION_CODE_KEY] = code
75-
self._session[_REGISTRATION_PENDING_KEY] = True
76-
77-
def validate_pending_registration(self) -> RegistrationData:
78-
if not self._session.get(_REGISTRATION_PENDING_KEY):
79-
raise PhoneRegistrationPendingNotFoundError(
80-
user_id=self._user_id, product_name=self._product_name
81-
)
82-
83-
registration: RegistrationData | None = self._session.get(_REGISTRATION_KEY)
84-
if not registration or registration["user_id"] != self._user_id:
85-
raise PhoneRegistrationSessionInvalidError(
86-
user_id=self._user_id, product_name=self._product_name
87-
)
88-
89-
return registration
90-
91-
def regenerate_code(self, new_code: str) -> None:
92-
self.validate_pending_registration()
93-
self._session[_REGISTRATION_CODE_KEY] = new_code
94-
95-
def validate_confirmation_code(self, provided_code: str) -> None:
96-
expected_code = self._session.get(_REGISTRATION_CODE_KEY)
97-
if not expected_code or provided_code != expected_code:
98-
raise PhoneRegistrationCodeInvalidError(
99-
user_id=self._user_id, product_name=self._product_name
100-
)
101-
102-
def clear_session(self) -> None:
103-
self._session.pop(_REGISTRATION_KEY, None)
104-
self._session.pop(_REGISTRATION_PENDING_KEY, None)
105-
self._session.pop(_REGISTRATION_CODE_KEY, None)
106-
107-
10842
routes = web.RouteTableDef()
10943

11044
#
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import logging
2+
from typing import Literal, TypedDict
3+
4+
from aiohttp_session import Session
5+
from models_library.users import UserID
6+
from servicelib.aiohttp import status
7+
8+
from .exceptions import (
9+
PhoneRegistrationCodeInvalidError,
10+
PhoneRegistrationPendingNotFoundError,
11+
PhoneRegistrationSessionInvalidError,
12+
)
13+
14+
_logger = logging.getLogger(__name__)
15+
16+
# Registration session keys
17+
_REGISTRATION_KEY = "registration"
18+
_REGISTRATION_PENDING_KEY = "registration_pending"
19+
_REGISTRATION_CODE_KEY = "registration_code"
20+
21+
22+
class RegistrationData(TypedDict):
23+
"""Registration session data structure."""
24+
25+
user_id: UserID
26+
data: str
27+
status: Literal["pending_confirmation"]
28+
29+
30+
class RegistrationSessionManager:
31+
def __init__(self, session: Session, user_id: UserID, product_name: str):
32+
self._session = session
33+
self._user_id = user_id
34+
self._product_name = product_name
35+
36+
def start_registration(self, data: str, code: str) -> None:
37+
registration_data: RegistrationData = {
38+
"user_id": self._user_id,
39+
"data": data, # keep data
40+
"status": "pending_confirmation",
41+
}
42+
self._session[_REGISTRATION_KEY] = registration_data
43+
self._session[_REGISTRATION_CODE_KEY] = code
44+
self._session[_REGISTRATION_PENDING_KEY] = True
45+
46+
def validate_pending_registration(self) -> RegistrationData:
47+
if not self._session.get(_REGISTRATION_PENDING_KEY):
48+
raise PhoneRegistrationPendingNotFoundError(
49+
user_id=self._user_id, product_name=self._product_name
50+
)
51+
52+
registration: RegistrationData | None = self._session.get(_REGISTRATION_KEY)
53+
if not registration or registration["user_id"] != self._user_id:
54+
raise PhoneRegistrationSessionInvalidError(
55+
user_id=self._user_id, product_name=self._product_name
56+
)
57+
58+
return registration
59+
60+
def regenerate_code(self, new_code: str) -> None:
61+
self.validate_pending_registration()
62+
self._session[_REGISTRATION_CODE_KEY] = new_code
63+
64+
def validate_confirmation_code(self, provided_code: str) -> None:
65+
expected_code = self._session.get(_REGISTRATION_CODE_KEY)
66+
if not expected_code or provided_code != expected_code:
67+
raise PhoneRegistrationCodeInvalidError(
68+
user_id=self._user_id, product_name=self._product_name
69+
)
70+
71+
def clear_session(self) -> None:
72+
self._session.pop(_REGISTRATION_KEY, None)
73+
self._session.pop(_REGISTRATION_PENDING_KEY, None)
74+
self._session.pop(_REGISTRATION_CODE_KEY, None)

services/web/server/tests/unit/with_dbs/03/test_users_rest_profiles.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
get_frontend_user_preferences_aggregation,
3838
)
3939
from simcore_service_webserver.users._controller.rest.users_rest import (
40-
_PHONE_CODE_VALUE_FAKE,
40+
_REGISTRATION_CODE_VALUE_FAKE,
4141
)
4242
from sqlalchemy.exc import OperationalError as SQLAlchemyOperationalError
4343
from sqlalchemy.ext.asyncio import AsyncConnection
@@ -630,7 +630,7 @@ async def test_phone_registration_basic_workflow(
630630
resp = await client.post(
631631
f"{url}",
632632
json={
633-
"code": _PHONE_CODE_VALUE_FAKE,
633+
"code": _REGISTRATION_CODE_VALUE_FAKE,
634634
},
635635
)
636636
await assert_status(resp, status.HTTP_204_NO_CONTENT)
@@ -686,7 +686,7 @@ async def test_phone_registration_workflow(
686686
resp = await client.post(
687687
f"{url}",
688688
json={
689-
"code": _PHONE_CODE_VALUE_FAKE,
689+
"code": _REGISTRATION_CODE_VALUE_FAKE,
690690
},
691691
)
692692
await assert_status(resp, status.HTTP_204_NO_CONTENT)
@@ -739,7 +739,7 @@ async def test_phone_registration_with_resend(
739739
resp = await client.post(
740740
f"{url}",
741741
json={
742-
"code": _PHONE_CODE_VALUE_FAKE,
742+
"code": _REGISTRATION_CODE_VALUE_FAKE,
743743
},
744744
)
745745
await assert_status(resp, status.HTTP_204_NO_CONTENT)
@@ -779,7 +779,7 @@ async def test_phone_registration_change_existing_phone(
779779
resp = await client.post(
780780
f"{url}",
781781
json={
782-
"code": _PHONE_CODE_VALUE_FAKE,
782+
"code": _REGISTRATION_CODE_VALUE_FAKE,
783783
},
784784
)
785785
await assert_status(resp, status.HTTP_204_NO_CONTENT)
@@ -799,7 +799,7 @@ async def test_phone_registration_change_existing_phone(
799799
resp = await client.post(
800800
f"{url}",
801801
json={
802-
"code": _PHONE_CODE_VALUE_FAKE,
802+
"code": _REGISTRATION_CODE_VALUE_FAKE,
803803
},
804804
)
805805
await assert_status(resp, status.HTTP_204_NO_CONTENT)
@@ -848,7 +848,7 @@ async def test_phone_confirm_without_pending_registration(
848848
resp = await client.post(
849849
f"{url}",
850850
json={
851-
"code": _PHONE_CODE_VALUE_FAKE,
851+
"code": _REGISTRATION_CODE_VALUE_FAKE,
852852
},
853853
)
854854
await assert_status(resp, status.HTTP_400_BAD_REQUEST)
@@ -1044,7 +1044,7 @@ async def test_phone_confirm_access_rights(
10441044
resp = await client.post(
10451045
f"{url}",
10461046
json={
1047-
"code": _PHONE_CODE_VALUE_FAKE,
1047+
"code": _REGISTRATION_CODE_VALUE_FAKE,
10481048
},
10491049
)
10501050
await assert_status(resp, expected)

0 commit comments

Comments
 (0)