You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
5.7 KiB
149 lines
5.7 KiB
from bson import ObjectId
|
|
import bson
|
|
from fastapi import APIRouter, HTTPException, status
|
|
from fastapi.params import Depends
|
|
import pymongo
|
|
|
|
from app.dto import FriendAddDTO
|
|
from app.models import HTTPError, User, Friend
|
|
from .utils import friend_not_found, get_current_user, objectid_misformatted
|
|
import app.config as config
|
|
|
|
# Best workaround found for _id typed as ObjectId (creating Exception bcause JSON doesn't support custom types countrary to BSON, used by Mongo)
|
|
# also allows to create DTOs at the time, but not at it's best (project structure is chaotic FTM :s)
|
|
import app.serializers as serializers # Import all serializers (detailed in __init__.py)
|
|
|
|
# Database setup
|
|
client = pymongo.MongoClient(config.MONGODB_URL, username=config.MONGODB_USERNAME, password=config.MONGODB_PASSWORD)
|
|
db = client[config.MONGODB_DATABASE]
|
|
|
|
friends_collection = db["friends"]
|
|
users_collection = db["users"]
|
|
pin_permissions_collection = db["pin_permissions"]
|
|
|
|
friends_router = APIRouter(
|
|
prefix="/friend",
|
|
tags=["Friends"]
|
|
)
|
|
|
|
@friends_router.get(
|
|
path="/{id}",
|
|
responses={401: {"model": HTTPError}, 404: {"model": HTTPError}, 422: {"model": HTTPError}}
|
|
)
|
|
async def get_friend(id: str, current_user: User = Depends(get_current_user)):
|
|
try:
|
|
friend = friends_collection.find_one({"_id": ObjectId(id)})
|
|
except bson.errors.InvalidId:
|
|
objectid_misformatted()
|
|
|
|
if friend is None: friend_not_found()
|
|
|
|
return serializers.friend_serialize(friend,False if friend['user_id']==current_user.uid else True)
|
|
|
|
@friends_router.post(
|
|
path="/add",
|
|
responses={401: {"model": HTTPError}, 409: {"model": HTTPError}}
|
|
)
|
|
async def add_friend(friend_to_add: FriendAddDTO, current_user: User = Depends(get_current_user)):
|
|
friend: Friend = friend_to_add.model_dump()
|
|
|
|
if(current_user.uid == friend["friend_user_id"]):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Cannot add yourself as a friend"
|
|
)
|
|
|
|
# Test if already friends
|
|
if friends_collection.find_one({"user_id": current_user.uid, "friend_user_id": friend["friend_user_id"]}) is not None:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_409_CONFLICT,
|
|
detail="Friend already exists"
|
|
)
|
|
|
|
# Test if user exists
|
|
if not users_collection.find_one({"_id": ObjectId(friend["friend_user_id"])}):
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail="User not found"
|
|
)
|
|
|
|
friend["user_id"] = current_user.uid
|
|
friend["status"] = "pending"
|
|
friend_id = friends_collection.insert_one(friend).inserted_id
|
|
return {"id": str(friend_id)}
|
|
|
|
@friends_router.delete(
|
|
path="/{id}/delete",
|
|
responses={401: {"model": HTTPError}, 404: {"model": HTTPError}, 422: {"model": HTTPError}}
|
|
)
|
|
async def delete_friend(id: str, current_user: User = Depends(get_current_user)):
|
|
try:
|
|
# Récupérer l'ami avant de le supprimer pour avoir son ID
|
|
friend = friends_collection.find_one({"_id": ObjectId(id)})
|
|
if friend is None:
|
|
friend_not_found()
|
|
|
|
# Déterminer l'ID de l'autre utilisateur
|
|
other_user_id = friend["friend_user_id"] if friend["user_id"] == current_user.uid else friend["user_id"]
|
|
|
|
# Supprimer l'ami
|
|
friends_collection.delete_one({"_id": ObjectId(id)})
|
|
|
|
# Supprimer toutes les permissions de partage de pins entre les deux utilisateurs
|
|
pin_permissions_collection.delete_many({
|
|
"$or": [
|
|
# Pins que l'utilisateur courant a partagés avec l'ami
|
|
{"user_id": other_user_id, "pin_id": {"$in": [pin["_id"] for pin in db["pins"].find({"user_id": current_user.uid})]}},
|
|
# Pins que l'ami a partagés avec l'utilisateur courant
|
|
{"user_id": current_user.uid, "pin_id": {"$in": [pin["_id"] for pin in db["pins"].find({"user_id": other_user_id})]}}
|
|
]
|
|
})
|
|
|
|
return {"message": "Friend and associated pin shares deleted"}
|
|
|
|
except bson.errors.InvalidId:
|
|
objectid_misformatted()
|
|
|
|
@friends_router.patch(
|
|
path="/{id}/accept",
|
|
responses={401: {"model": HTTPError}, 404: {"model": HTTPError}, 422: {"model": HTTPError}}
|
|
)
|
|
async def accept_friend(id: str, current_user: User = Depends(get_current_user)):
|
|
try:
|
|
check_friend = friends_collection.find_one({"_id": ObjectId(id)})
|
|
if check_friend is None: friend_not_found()
|
|
|
|
if check_friend["status"] != "pending":
|
|
raise HTTPException(
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
detail="Friend request already accepted"
|
|
)
|
|
|
|
friends_collection.update_one({"_id": ObjectId(id)}, {"$set": {"status": "accepted"}})
|
|
except bson.errors.InvalidId:
|
|
objectid_misformatted()
|
|
|
|
return {"message": "Friend request accepted"}
|
|
|
|
@friends_router.delete(
|
|
path="/{id}/deny",
|
|
responses={401: {"model": HTTPError}, 404: {"model": HTTPError}, 422: {"model": HTTPError}}
|
|
)
|
|
async def deny_friend(id: str, current_user: User = Depends(get_current_user)):
|
|
try:
|
|
result = friends_collection.delete_one({"_id": ObjectId(id)})
|
|
except bson.errors.InvalidId:
|
|
objectid_misformatted()
|
|
|
|
if result.matched_count == 0: friend_not_found()
|
|
|
|
return {"message": "Friend request denied"}
|
|
|
|
@friends_router.get(
|
|
path="s",
|
|
response_model=list[Friend],
|
|
responses={401: {"model": HTTPError}}
|
|
)
|
|
async def list_friends(current_user: User = Depends(get_current_user)):
|
|
return serializers.friends_serialize(friends_collection.find({"user_id": current_user.uid}).to_list(), friends_collection.find({"friend_user_id": current_user.uid}).to_list())
|