@ -1,3 +1,4 @@
import bson
from fastapi import FastAPI , Depends , HTTPException , status
from fastapi import FastAPI , Depends , HTTPException , status
from fastapi . responses import JSONResponse
from fastapi . responses import JSONResponse
from fastapi . security import OAuth2PasswordBearer , OAuth2PasswordRequestForm
from fastapi . security import OAuth2PasswordBearer , OAuth2PasswordRequestForm
@ -15,7 +16,7 @@ import app.serializers as serializers # Import all serializers (detailed in __in
from app . models import User , Pin , Friend , Token , TokenData , HTTPError
from app . models import User , Pin , Friend , Token , TokenData , HTTPError
# Import all DTOs (detailed in __init__.py)
# Import all DTOs (detailed in __init__.py)
from app . dto import FriendAddDTO , FriendListDTO , UserDTO , UserRegisterDTO
from app . dto import FriendAddDTO , FriendListDTO , UserDTO , UserRegisterDTO , PinDTO
# Contains all constants
# Contains all constants
import app . config as config
import app . config as config
@ -45,13 +46,10 @@ pins_collection = db["pins"]
friends_collection = db [ " friends " ]
friends_collection = db [ " friends " ]
# Token management
# Token management
def create_access_token ( data : dict , expires_delta : Optional[ timedelta] = None ) :
def create_access_token ( data : dict , expires_delta : timedelta) :
to_encode = data . copy ( )
to_encode = data . copy ( )
if expires_delta :
expire = datetime . now ( ) + expires_delta
expire = datetime . now ( ) + expires_delta
else :
expire = datetime . now ( ) + timedelta ( minutes = 15 )
to_encode . update ( { " exp " : expire } )
to_encode . update ( { " exp " : expire } )
encoded_jwt = jwt . encode ( to_encode , config . SECRET_KEY , algorithm = config . ALGORITHM )
encoded_jwt = jwt . encode ( to_encode , config . SECRET_KEY , algorithm = config . ALGORITHM )
@ -101,7 +99,7 @@ async def register(user: UserRegisterDTO):
access_token_expires = timedelta ( minutes = config . ACCESS_TOKEN_EXPIRE_MINUTES )
access_token_expires = timedelta ( minutes = config . ACCESS_TOKEN_EXPIRE_MINUTES )
access_token = create_access_token ( data = { " sub " : user . username } , expires_delta = access_token_expires )
access_token = create_access_token ( data = { " sub " : user . username } , expires_delta = access_token_expires )
return { " access_token " : access_token , " token_type " : " bearer " , " user_id " : str ( user_id ) }
return { " access_token " : access_token , " token_type " : " bearer " , " user_id " : str ( user_id . inserted_id ) }
@app.post (
@app.post (
path = " /login " ,
path = " /login " ,
@ -122,20 +120,28 @@ async def login(form_data: OAuth2PasswordRequestForm = Depends()):
return { " access_token " : access_token , " token_type " : " bearer " , " user_id " : str ( user [ " _id " ] ) }
return { " access_token " : access_token , " token_type " : " bearer " , " user_id " : str ( user [ " _id " ] ) }
""" Is it really usefull ? idk.
@app.get (
@app.get (
path = " /logout " ,
path = " /logout " ,
responses = { 401 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } }
)
)
async def logout ( current_user : User = Depends ( get_current_user ) ) :
async def logout ( current_user : User = Depends ( get_current_user ) ) :
# TODO: find usecase / what to do ??
return { " message " : " Logged out " }
return { " message " : " Logged out " }
"""
@app.get (
@app.get (
path = " /pin/ {id} " ,
path = " /pin/ {id} " ,
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } , 422 : { " model " : HTTPError } }
)
)
async def get_pin ( id : str , current_user : User = Depends ( get_current_user ) ) :
async def get_pin ( id : str , current_user : User = Depends ( get_current_user ) ) :
pin = pins_collection . find_one ( { " _id " : ObjectId ( id ) } )
try :
pin = pins_collection . find_one ( { " _id " : ObjectId ( id ) } )
except bson . errors . InvalidId :
raise HTTPException (
status_code = status . HTTP_422_UNPROCESSABLE_ENTITY ,
detail = " The ObjectID is misformatted "
)
if pin is None :
if pin is None :
raise HTTPException ( status_code = 404 , detail = " Pin not found " )
raise HTTPException ( status_code = 404 , detail = " Pin not found " )
@ -143,10 +149,17 @@ async def get_pin(id: str, current_user: User = Depends(get_current_user)):
@app.patch (
@app.patch (
path = " /pin/ {id} " ,
path = " /pin/ {id} " ,
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } , 422 : { " model " : HTTPError } }
)
)
async def update_pin ( id : str , pin : Pin , current_user : User = Depends ( get_current_user ) ) :
async def update_pin ( id : str , pin : PinDTO , current_user : User = Depends ( get_current_user ) ) :
result = pins_collection . update_one ( { " _id " : ObjectId ( id ) } , { " $set " : pin . model_dump ( ) } )
try :
result = pins_collection . update_one ( { " _id " : ObjectId ( id ) } , { " $set " : pin . model_dump ( ) } )
except bson . errors . InvalidId :
raise HTTPException (
status_code = status . HTTP_422_UNPROCESSABLE_ENTITY ,
detail = " The ObjectID is misformatted "
)
if result . matched_count == 0 :
if result . matched_count == 0 :
raise HTTPException ( status_code = 404 , detail = " Pin not found " )
raise HTTPException ( status_code = 404 , detail = " Pin not found " )
@ -156,7 +169,7 @@ async def update_pin(id: str, pin: Pin, current_user: User = Depends(get_current
path = " /pin/add " ,
path = " /pin/add " ,
responses = { 401 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } }
)
)
async def add_pin ( pin : Pin , current_user : User = Depends ( get_current_user ) ) :
async def add_pin ( pin : Pin DTO , current_user : User = Depends ( get_current_user ) ) :
pin_id = pins_collection . insert_one ( pin . model_dump ( ) ) . inserted_id
pin_id = pins_collection . insert_one ( pin . model_dump ( ) ) . inserted_id
return { " id " : str ( pin_id ) }
return { " id " : str ( pin_id ) }
@ -175,13 +188,20 @@ def friend_not_found():
@app.get (
@app.get (
path = " /friend/ {id} " ,
path = " /friend/ {id} " ,
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } , 422 : { " model " : HTTPError } }
)
)
async def get_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
async def get_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
friend = friends_collection . find_one ( { " _id " : ObjectId ( id ) } )
try :
friend = friends_collection . find_one ( { " _id " : ObjectId ( id ) } )
except bson . errors . InvalidId :
raise HTTPException (
status_code = status . HTTP_422_UNPROCESSABLE_ENTITY ,
detail = " The ObjectID is misformatted "
)
if friend is None : friend_not_found ( )
if friend is None : friend_not_found ( )
return friend
return serializers. friend_serialize( friend )
@app.post (
@app.post (
path = " /friend/add " ,
path = " /friend/add " ,
@ -191,8 +211,6 @@ async def add_friend(friend_to_add: FriendAddDTO, current_user: User = Depends(g
# TODO: test if exists
# TODO: test if exists
friend : Friend = friend_to_add . model_dump ( )
friend : Friend = friend_to_add . model_dump ( )
print ( current_user )
if ( current_user . uid == friend [ " friend_user_id " ] ) :
if ( current_user . uid == friend [ " friend_user_id " ] ) :
raise HTTPException (
raise HTTPException (
status_code = status . HTTP_409_CONFLICT ,
status_code = status . HTTP_409_CONFLICT ,
@ -205,30 +223,51 @@ async def add_friend(friend_to_add: FriendAddDTO, current_user: User = Depends(g
@app.delete (
@app.delete (
path = " /friend/ {id} /delete " ,
path = " /friend/ {id} /delete " ,
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } , 422 : { " model " : HTTPError } }
)
)
async def delete_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
async def delete_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
result = friends_collection . delete_one ( { " _id " : ObjectId ( id ) } )
try :
result = friends_collection . delete_one ( { " _id " : ObjectId ( id ) } )
except bson . errors . InvalidId :
raise HTTPException (
status_code = status . HTTP_422_UNPROCESSABLE_ENTITY ,
detail = " The ObjectID is misformatted "
)
if result . deleted_count == 0 : friend_not_found ( )
if result . deleted_count == 0 : friend_not_found ( )
return { " message " : " Friend deleted " }
return { " message " : " Friend deleted " }
@app.patch (
@app.patch (
path = " /friend/ {id} /accept " ,
path = " /friend/ {id} /accept " ,
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } , 422 : { " model " : HTTPError } }
)
)
async def accept_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
async def accept_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
result = friends_collection . update_one ( { " _id " : ObjectId ( id ) } , { " $set " : { " status " : " accepted " } } )
try :
result = friends_collection . update_one ( { " _id " : ObjectId ( id ) } , { " $set " : { " status " : " accepted " } } )
except bson . errors . InvalidId :
raise HTTPException (
status_code = status . HTTP_422_UNPROCESSABLE_ENTITY ,
detail = " The ObjectID is misformatted "
)
if result . matched_count == 0 : friend_not_found ( )
if result . matched_count == 0 : friend_not_found ( )
return { " message " : " Friend request accepted " }
return { " message " : " Friend request accepted " }
@app.post (
@app.post (
path = " /friend/ {id} /deny " ,
path = " /friend/ {id} /deny " ,
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } }
responses = { 401 : { " model " : HTTPError } , 404 : { " model " : HTTPError } , 422 : { " model " : HTTPError } }
)
)
async def deny_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
async def deny_friend ( id : str , current_user : User = Depends ( get_current_user ) ) :
result = friends_collection . update_one ( { " _id " : ObjectId ( id ) } , { " $set " : { " status " : " denied " } } )
try :
result = friends_collection . update_one ( { " _id " : ObjectId ( id ) } , { " $set " : { " status " : " denied " } } )
except bson . errors . InvalidId :
raise HTTPException (
status_code = status . HTTP_422_UNPROCESSABLE_ENTITY ,
detail = " The ObjectID is misformatted "
)
if result . matched_count == 0 : friend_not_found ( )
if result . matched_count == 0 : friend_not_found ( )
return { " message " : " Friend request denied " }
return { " message " : " Friend request denied " }