Skip to content

Commit d643539

Browse files
committed
Remove schema dependency
1 parent b4f21ad commit d643539

File tree

1 file changed

+47
-36
lines changed

1 file changed

+47
-36
lines changed
Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,83 @@
1-
from typing import ClassVar, Self
1+
import uuid
2+
from datetime import UTC, datetime, timedelta
3+
from typing import Any, ClassVar
24

3-
from pydantic import EmailStr, HttpUrl, model_validator
5+
import jwt
6+
from pydantic import EmailStr, HttpUrl
47
from sqlalchemy import Result, Select, select
58
from sqlalchemy.exc import NoResultFound
69

710
from futuramaapi.core import feature_flags, settings
811
from futuramaapi.helpers.pydantic import BaseModel
9-
from futuramaapi.mixins.pydantic import TemplateBodyMixin
1012
from futuramaapi.repositories.models import UserModel
11-
from futuramaapi.routers.rest.tokens.schemas import DecodedUserToken
1213
from futuramaapi.routers.services import BaseSessionService
1314

1415

1516
class RequestChangeUserPasswordRequest(BaseModel):
1617
email: EmailStr
1718

1819

19-
class PasswordResetBody(BaseModel, TemplateBodyMixin):
20+
class RequestChangeUserPasswordService(BaseSessionService[None]):
21+
request_data: RequestChangeUserPasswordRequest
22+
2023
expiration_time: ClassVar[int] = 15 * 60
2124

2225
@property
23-
def signature(self) -> str:
24-
return DecodedUserToken(
25-
type="access",
26-
user={
27-
"id": self.user.id,
26+
def _user_statement(self) -> Select[tuple[UserModel]]:
27+
return select(UserModel).where(UserModel.email == self.request_data.email)
28+
29+
def _get_signature(
30+
self,
31+
user: UserModel,
32+
/,
33+
*,
34+
algorithm: str = "HS256",
35+
) -> str:
36+
return jwt.encode(
37+
{
38+
"exp": datetime.now(UTC) + timedelta(seconds=self.expiration_time),
39+
"nonce": uuid.uuid4().hex,
40+
"type": "access",
41+
"user": {
42+
"id": user.id,
43+
},
2844
},
29-
).tokenize(self.expiration_time)
45+
settings.secret_key.get_secret_value(),
46+
algorithm=algorithm,
47+
)
3048

31-
@model_validator(mode="after")
32-
def build_confirmation_url(self) -> Self:
33-
self.url = HttpUrl.build(
34-
scheme=self.url.scheme,
35-
host=self.url.host,
49+
def _get_confirmation_url(self, user: UserModel, /) -> str:
50+
url: HttpUrl = HttpUrl.build(
51+
scheme="https",
52+
host=settings.trusted_host,
3653
path="passwords/change",
37-
query=f"sig={self.signature}",
54+
query=f"sig={self._get_signature(user)}",
3855
)
39-
return self
40-
56+
return str(url)
4157

42-
class RequestChangeUserPasswordService(BaseSessionService[None]):
43-
request_data: RequestChangeUserPasswordRequest
44-
45-
@property
46-
def _user_statement(self) -> Select[tuple[UserModel]]:
47-
return select(UserModel).where(UserModel.email == self.request_data.email)
58+
def _get_template_body(self, user: UserModel, /) -> dict[str, Any]:
59+
return {
60+
"user": {
61+
"id": user.id,
62+
"name": user.name,
63+
"surname": user.surname,
64+
},
65+
"url": self._get_confirmation_url(user),
66+
}
4867

4968
async def process(self, *args, **kwargs) -> None:
5069
if not feature_flags.activate_users:
5170
return
5271

5372
result: Result[tuple[UserModel]] = await self.session.execute(self._user_statement)
5473
try:
55-
user_model: UserModel = result.scalars().one()
74+
user: UserModel = result.scalars().one()
5675
except NoResultFound:
5776
return
5877

5978
await settings.email.send(
60-
[user_model.email],
79+
[user.email],
6180
"FuturamaAPI - Password Reset",
62-
PasswordResetBody.model_validate(
63-
{
64-
"user": {
65-
"id": user_model.id,
66-
"name": user_model.name,
67-
"surname": user_model.surname,
68-
},
69-
}
70-
),
81+
self._get_template_body(user),
7182
"emails/password_reset.html",
7283
)

0 commit comments

Comments
 (0)