@@ -58,6 +58,55 @@ class PhoneRegistrationData(TypedDict):
5858 status : Literal ["pending_confirmation" ]
5959
6060
61+ class PhoneRegistrationSessionManager :
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 , phone : str ) -> None :
68+ phone_data : PhoneRegistrationData = {
69+ "user_id" : self ._user_id ,
70+ "phone" : phone ,
71+ "status" : "pending_confirmation" ,
72+ }
73+ self ._session [_PHONE_REGISTRATION_KEY ] = phone_data
74+ self ._session [_PHONE_CODE_KEY ] = _PHONE_CODE_VALUE_FAKE
75+ self ._session [_PHONE_PENDING_KEY ] = True
76+
77+ def validate_pending_registration (self ) -> PhoneRegistrationData :
78+ if not self ._session .get (_PHONE_PENDING_KEY ):
79+ raise PhoneRegistrationPendingNotFoundError (
80+ user_id = self ._user_id , product_name = self ._product_name
81+ )
82+
83+ phone_registration : PhoneRegistrationData | None = self ._session .get (
84+ _PHONE_REGISTRATION_KEY
85+ )
86+ if not phone_registration or phone_registration ["user_id" ] != self ._user_id :
87+ raise PhoneRegistrationSessionInvalidError (
88+ user_id = self ._user_id , product_name = self ._product_name
89+ )
90+
91+ return phone_registration
92+
93+ def regenerate_code (self ) -> None :
94+ self .validate_pending_registration ()
95+ self ._session [_PHONE_CODE_KEY ] = _PHONE_CODE_VALUE_FAKE
96+
97+ def validate_confirmation_code (self , provided_code : str ) -> None :
98+ expected_code = self ._session .get (_PHONE_CODE_KEY )
99+ if not expected_code or provided_code != expected_code :
100+ raise PhoneRegistrationCodeInvalidError (
101+ user_id = self ._user_id , product_name = self ._product_name
102+ )
103+
104+ def clear_session (self ) -> None :
105+ self ._session .pop (_PHONE_REGISTRATION_KEY , None )
106+ self ._session .pop (_PHONE_PENDING_KEY , None )
107+ self ._session .pop (_PHONE_CODE_KEY , None )
108+
109+
61110routes = web .RouteTableDef ()
62111
63112#
@@ -130,52 +179,12 @@ async def my_phone_register(request: web.Request) -> web.Response:
130179 phone_register = await parse_request_body_as (MyPhoneRegister , request )
131180
132181 session = await get_session (request )
133-
134- # Store phone registration state in session
135- phone_data : PhoneRegistrationData = {
136- "user_id" : req_ctx .user_id ,
137- "phone" : phone_register .phone ,
138- "status" : "pending_confirmation" ,
139- }
140- session [_PHONE_REGISTRATION_KEY ] = phone_data
141-
142- # NOTE: In real implementation, generate and send SMS code here
143- # For testing, we'll use a fixed code
144- session [_PHONE_CODE_KEY ] = _PHONE_CODE_VALUE_FAKE
145- session [_PHONE_PENDING_KEY ] = True
146-
147- return web .json_response (status = status .HTTP_202_ACCEPTED )
148-
149-
150- def _validate_pending_phone_registration (
151- session : Session , user_id : UserID , product_name : str
152- ) -> PhoneRegistrationData :
153- # Check if there's a pending phone registration
154- if not session .get (_PHONE_PENDING_KEY ):
155- raise PhoneRegistrationPendingNotFoundError (
156- user_id = user_id , product_name = product_name
157- )
158-
159- # Validate session belongs to current user
160- phone_registration : PhoneRegistrationData | None = session .get (
161- _PHONE_REGISTRATION_KEY
182+ phone_session_manager = PhoneRegistrationSessionManager (
183+ session , req_ctx .user_id , req_ctx .product_name
162184 )
163- if not phone_registration or phone_registration ["user_id" ] != user_id :
164- raise PhoneRegistrationSessionInvalidError (
165- user_id = user_id , product_name = product_name
166- )
167-
168- return phone_registration
169-
185+ phone_session_manager .start_registration (phone_register .phone )
170186
171- def _validate_confirmation_code (
172- session : Session , provided_code : str , * , user_id : UserID , product_name : str
173- ) -> None :
174- expected_code = session .get (_PHONE_CODE_KEY )
175- if not expected_code or provided_code != expected_code :
176- raise PhoneRegistrationCodeInvalidError (
177- user_id = user_id , product_name = product_name
178- )
187+ return web .json_response (status = status .HTTP_202_ACCEPTED )
179188
180189
181190@routes .post (f"/{ API_VTAG } /me/phone:resend" , name = "my_phone_resend" )
@@ -185,13 +194,12 @@ def _validate_confirmation_code(
185194@handle_rest_requests_exceptions
186195async def my_phone_resend (request : web .Request ) -> web .Response :
187196 req_ctx = UsersRequestContext .model_validate (request )
188- session = await get_session (request )
189-
190- _validate_pending_phone_registration (session , req_ctx .user_id , req_ctx .product_name )
191197
192- # NOTE: In real implementation, regenerate and resend SMS code here
193- # For testing, we'll use the same fixed code
194- session [_PHONE_CODE_KEY ] = _PHONE_CODE_VALUE_FAKE
198+ session = await get_session (request )
199+ phone_session_manager = PhoneRegistrationSessionManager (
200+ session , req_ctx .user_id , req_ctx .product_name
201+ )
202+ phone_session_manager .regenerate_code ()
195203
196204 return web .json_response (status = status .HTTP_202_ACCEPTED )
197205
@@ -204,30 +212,22 @@ async def my_phone_resend(request: web.Request) -> web.Response:
204212async def my_phone_confirm (request : web .Request ) -> web .Response :
205213 req_ctx = UsersRequestContext .model_validate (request )
206214 phone_confirm = await parse_request_body_as (MyPhoneConfirm , request )
207- session = await get_session (request )
208215
209- phone_registration = _validate_pending_phone_registration (
216+ session = await get_session (request )
217+ phone_session_manager = PhoneRegistrationSessionManager (
210218 session , req_ctx .user_id , req_ctx .product_name
211219 )
212220
213- _validate_confirmation_code (
214- session ,
215- phone_confirm .code ,
216- user_id = req_ctx .user_id ,
217- product_name = req_ctx .product_name ,
218- )
221+ phone_registration = phone_session_manager .validate_pending_registration ()
222+ phone_session_manager .validate_confirmation_code (phone_confirm .code )
219223
220- # Update user's phone number in the database
221224 await _users_service .update_user_phone (
222225 request .app ,
223226 user_id = req_ctx .user_id ,
224227 phone = phone_registration ["phone" ],
225228 )
226229
227- # Clear phone registration session data
228- session .pop (_PHONE_REGISTRATION_KEY , None )
229- session .pop (_PHONE_PENDING_KEY , None )
230- session .pop (_PHONE_CODE_KEY , None )
230+ phone_session_manager .clear_session ()
231231
232232 return web .json_response (status = status .HTTP_204_NO_CONTENT )
233233
@@ -256,4 +256,3 @@ async def search_users(request: web.Request) -> web.Response:
256256 )
257257
258258 return envelope_json_response ([UserGet .from_domain_model (user ) for user in found ])
259- return envelope_json_response ([UserGet .from_domain_model (user ) for user in found ])
0 commit comments