1
1
from datetime import datetime , timedelta
2
+ import hashlib
3
+ from random import randbytes
2
4
from bson .objectid import ObjectId
3
5
from fastapi import APIRouter , Request , Response , status , Depends , HTTPException
4
6
from pydantic import EmailStr
5
7
6
8
from app import oauth2
7
9
from app .database import User
8
- from app .serializers import userEntity , userResponseEntity
10
+ from app .email import Email
11
+ from app .serializers import userEntity
9
12
from .. import schemas , utils
10
13
from app .oauth2 import AuthJWT
11
14
from ..config import settings
16
19
REFRESH_TOKEN_EXPIRES_IN = settings .REFRESH_TOKEN_EXPIRES_IN
17
20
18
21
19
- @router .post ('/register' , status_code = status .HTTP_201_CREATED , response_model = schemas . UserResponse )
20
- async def create_user (payload : schemas .CreateUserSchema ):
22
+ @router .post ('/register' , status_code = status .HTTP_201_CREATED )
23
+ async def create_user (payload : schemas .CreateUserSchema , request : Request ):
21
24
# Check if user already exist
22
25
user = User .find_one ({'email' : payload .email .lower ()})
23
26
if user :
@@ -31,13 +34,29 @@ async def create_user(payload: schemas.CreateUserSchema):
31
34
payload .password = utils .hash_password (payload .password )
32
35
del payload .passwordConfirm
33
36
payload .role = 'user'
34
- payload .verified = True
37
+ payload .verified = False
35
38
payload .email = payload .email .lower ()
36
39
payload .created_at = datetime .utcnow ()
37
40
payload .updated_at = payload .created_at
41
+
38
42
result = User .insert_one (payload .dict ())
39
- new_user = userResponseEntity (User .find_one ({'_id' : result .inserted_id }))
40
- return {"status" : "success" , "user" : new_user }
43
+ new_user = User .find_one ({'_id' : result .inserted_id })
44
+ try :
45
+ token = randbytes (10 )
46
+ hashedCode = hashlib .sha256 ()
47
+ hashedCode .update (token )
48
+ verification_code = hashedCode .hexdigest ()
49
+ User .find_one_and_update ({"_id" : result .inserted_id }, {
50
+ "$set" : {"verification_code" : verification_code , "updated_at" : datetime .utcnow ()}})
51
+
52
+ url = f"{ request .url .scheme } ://{ request .client .host } :{ request .url .port } /api/auth/verifyemail/{ token .hex ()} "
53
+ await Email (userEntity (new_user ), url , [EmailStr (payload .email )]).sendVerificationCode ()
54
+ except Exception as error :
55
+ User .find_one_and_update ({"_id" : result .inserted_id }, {
56
+ "$set" : {"verification_code" : None , "updated_at" : datetime .utcnow ()}})
57
+ raise HTTPException (status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
58
+ detail = 'There was an error sending email' )
59
+ return {'status' : 'success' , 'message' : 'Verification token successfully sent to your email' }
41
60
42
61
43
62
@router .post ('/login' )
@@ -114,3 +133,19 @@ def logout(response: Response, Authorize: AuthJWT = Depends(), user_id: str = De
114
133
response .set_cookie ('logged_in' , '' , - 1 )
115
134
116
135
return {'status' : 'success' }
136
+
137
+
138
+ @router .get ('/verifyemail/{token}' )
139
+ def verify_me (token : str ):
140
+ hashedCode = hashlib .sha256 ()
141
+ hashedCode .update (bytes .fromhex (token ))
142
+ verification_code = hashedCode .hexdigest ()
143
+ result = User .find_one_and_update ({"verification_code" : verification_code }, {
144
+ "$set" : {"verification_code" : None , "verified" : True , "updated_at" : datetime .utcnow ()}}, new = True )
145
+ if not result :
146
+ raise HTTPException (
147
+ status_code = status .HTTP_403_FORBIDDEN , detail = 'Invalid verification code or account already verified' )
148
+ return {
149
+ "status" : "success" ,
150
+ "message" : "Account verified successfully"
151
+ }
0 commit comments