Rewrite sync pymongo to async motor

This commit is contained in:
IgorVolochay
2026-08-20 13:40:38 +03:00
parent 3e87607886
commit 122209bdf4
3 changed files with 327 additions and 290 deletions
+126 -115
View File
@@ -6,8 +6,8 @@ import asyncio
from dotenv import load_dotenv from dotenv import load_dotenv
from fastapi import FastAPI, Depends, Response, status from fastapi import FastAPI, Depends, Response, status
from schemas.api_schemas import * from schemas.api_schemas import BaseResponse, AddUserBody, AddCardBody, SelectChoice, ReactionCard, AddCommentBody
from schemas.base_schemas import * from schemas.base_schemas import Card
from mongo_worker import MongoWorker from mongo_worker import MongoWorker
from tools.base_moderation import moderate_text from tools.base_moderation import moderate_text
@@ -15,177 +15,188 @@ from tools.base_moderation import moderate_text
load_dotenv() load_dotenv()
disable_docs = os.getenv("DISABLE_DOCS", "true").lower() == "true" disable_docs = os.getenv("DISABLE_DOCS", "true").lower() == "true"
app: FastAPI = FastAPI(title="This OR That", app: FastAPI = FastAPI(
summary="OpenAPI schema for \"This OR That\" project!", title="This OR That",
version="0.1", summary="OpenAPI schema for \"This OR That\" project!",
contact={"GitHub": "https://github.com/IgorVolochay/thisORthat"}, version="0.1",
docs_url=None if disable_docs else "/docs", contact={"GitHub": "https://github.com/IgorVolochay/thisORthat"},
redoc_url=None if disable_docs else "/redoc", docs_url=None if disable_docs else "/docs",
openapi_url=None if disable_docs else "/openapi.json") redoc_url=None if disable_docs else "/redoc",
openapi_url=None if disable_docs else "/openapi.json",
)
mongo_worker = MongoWorker() mongo_worker = MongoWorker()
@app.on_event("startup")
async def startup_event():
await mongo_worker.create_indexes()
@app.get("/check_user", status_code=200) @app.get("/check_user", status_code=200)
async def check_user(user_id: NonNegativeInt, async def check_user(
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: user_id: int,
result = mongo.check_user(user_id) mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
result = await mongo.check_user(user_id)
return BaseResponse(result=result) return BaseResponse(result=result)
@app.get("/get_user", status_code=200) @app.get("/get_user", status_code=200)
async def get_user(user_id: NonNegativeInt, async def get_user(
response: Response, user_id: int,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
if mongo.check_user(user_id): mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
result = mongo.get_user(user_id) if await mongo.check_user(user_id):
result = await mongo.get_user(user_id)
return BaseResponse(result=result) return BaseResponse(result=result)
else: response.status_code = status.HTTP_404_NOT_FOUND
response.status_code = status.HTTP_404_NOT_FOUND return BaseResponse(result="User doesn't exist", error=True)
return BaseResponse(result="User doesn't exist", error=True)
@app.post("/add_user", status_code=201) @app.post("/add_user", status_code=201)
async def add_user(new_user: AddUserBody, async def add_user(
response: Response, new_user: AddUserBody,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
if not mongo.check_user(new_user.user_id): mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
result = mongo.add_user(new_user.user_id, if not await mongo.check_user(new_user.user_id):
new_user.username, result = await mongo.add_user(
new_user.first_name, new_user.user_id,
new_user.last_name, new_user.username,
new_user.photo_url) new_user.first_name,
new_user.last_name,
new_user.photo_url,
)
return BaseResponse(result=result) return BaseResponse(result=result)
else: response.status_code = status.HTTP_409_CONFLICT
response.status_code = status.HTTP_409_CONFLICT return BaseResponse(result="User already exist", error=True)
return BaseResponse(result="User already exist", error=True)
@app.get("/get_card", status_code=200) @app.get("/get_card", status_code=200)
async def get_card(card_id: NonNegativeInt, async def get_card(
response: Response, card_id: int,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
card = mongo.get_card(card_id) mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
card = await mongo.get_card(card_id)
if card: if card:
return BaseResponse(result=card) return BaseResponse(result=card)
else: response.status_code = status.HTTP_404_NOT_FOUND
response.status_code = status.HTTP_404_NOT_FOUND return BaseResponse(result="There is no card with this card_id", error=True)
return BaseResponse(result="There is no card with this card_id", error=True)
@app.get("/get_random_cards", status_code=200) @app.get("/get_random_cards", status_code=200)
async def get_random_cards(user_id: NonNegativeInt, async def get_random_cards(
response: Response, user_id: int,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
cards_visited = mongo.get_visited_cards(user_id) mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
cards_visited = await mongo.get_visited_cards(user_id)
if cards_visited.error: if cards_visited.error:
response.status_code = status.HTTP_401_UNAUTHORIZED
return cards_visited
elif not cards_visited.result.cards_visited:
random_cards = mongo.get_random_cards(10, True)
if random_cards:
return BaseResponse(result=random_cards)
else:
response.status_code = status.HTTP_404_NOT_FOUND
return BaseResponse(result="No active cards", error=True)
result: list[Card] = list()
trys = 3
while len(result) < 10 and trys != 0:
random_cards = mongo.get_random_cards(10, True)
if not random_cards:
response.status_code = status.HTTP_404_NOT_FOUND
return BaseResponse(result="No active cards", error=True)
filtered_cards, filtered_cards_id = mongo.filter_cards(random_cards, cards_visited.result.cards_visited)
trys -= 1
if not filtered_cards:
continue
else:
result.extend(filtered_cards)
cards_visited.result.cards_visited.update(filtered_cards_id)
if not result:
response.status_code = status.HTTP_404_NOT_FOUND response.status_code = status.HTTP_404_NOT_FOUND
return BaseResponse(result="No active cards fo this user", error=True) return cards_visited
else:
return BaseResponse(result=result) # Передаём exclude_ids напрямую в запрос — один round-trip к БД вместо цикла
exclude_ids = cards_visited.result.cards_visited or None
random_cards = await mongo.get_random_cards(10, True, exclude_ids=exclude_ids)
if not random_cards:
response.status_code = status.HTTP_404_NOT_FOUND
return BaseResponse(result="No active cards for this user", error=True)
return BaseResponse(result=random_cards)
@app.post("/add_card", status_code=201) @app.post("/add_card", status_code=201)
async def add_card(new_card: AddCardBody, async def add_card(
response: Response, new_card: AddCardBody,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
if moderate_text(new_card.choice_A) and moderate_text(new_card.choice_B): if moderate_text(new_card.choice_A) and moderate_text(new_card.choice_B):
card = mongo.add_card_by_api(new_card.choice_A, card = await mongo.add_card_by_api(new_card.choice_A, new_card.choice_B, new_card.author_id)
new_card.choice_B,
new_card.author_id)
return BaseResponse(result=card) return BaseResponse(result=card)
else: response.status_code = status.HTTP_400_BAD_REQUEST
response.status_code = status.HTTP_400_BAD_REQUEST return BaseResponse(result="Card has not passed base moderation", error=True)
return BaseResponse(result="Card has not passed base moderation", error=True)
@app.patch("/select_choice", status_code=200) @app.patch("/select_choice", status_code=200)
async def select_choice(choice_data: SelectChoice, async def select_choice(
response: Response, choice_data: SelectChoice,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
check_visited = mongo.get_visited_cards(choice_data.user_id) mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
check_visited = await mongo.get_visited_cards(choice_data.user_id)
if check_visited.error: if check_visited.error:
response.status_code = status.HTTP_404_NOT_FOUND response.status_code = status.HTTP_404_NOT_FOUND
return check_visited return check_visited
elif not check_visited.error and choice_data.card_id in check_visited.result.cards_visited: if choice_data.card_id in check_visited.result.cards_visited:
response.status_code = status.HTTP_403_FORBIDDEN response.status_code = status.HTTP_403_FORBIDDEN
return BaseResponse(result="Card already visited!", error=True) return BaseResponse(result="Card already visited!", error=True)
else:
select_choice_result = mongo.select_choice(choice_data.card_id, choice_data.choice) select_choice_result = await mongo.select_choice(choice_data.card_id, choice_data.choice)
if select_choice_result.error: if select_choice_result.error:
response.status_code = status.HTTP_404_NOT_FOUND response.status_code = status.HTTP_404_NOT_FOUND
return select_choice_result return select_choice_result
else:
update_visited_result = mongo.update_visited_cards(choice_data.user_id, choice_data.card_id) await mongo.update_visited_cards(choice_data.user_id, choice_data.card_id)
return BaseResponse(result="Select choice complite!") return BaseResponse(result="Select choice complete!")
@app.patch("/like_card", status_code=200) @app.patch("/like_card", status_code=200)
async def like_card(like_data: ReactionCard, async def like_card(
response: Response, like_data: ReactionCard,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
result = mongo.like_card(like_data.card_id, like_data.user_id) mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
result = await mongo.like_card(like_data.card_id, like_data.user_id)
if not result.error and result.result: if not result.error and result.result:
return BaseResponse(result="Added like to card") return BaseResponse(result="Added like to card")
else: response.status_code = status.HTTP_404_NOT_FOUND
response.status_code = status.HTTP_404_NOT_FOUND return result
return result
@app.patch("/dislike_card", status_code=200) @app.patch("/dislike_card", status_code=200)
async def dislike_card(dislike_data: ReactionCard, async def dislike_card(
response: Response, dislike_data: ReactionCard,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
result = mongo.dislike_card(dislike_data.card_id, dislike_data.user_id) mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
result = await mongo.dislike_card(dislike_data.card_id, dislike_data.user_id)
if not result.error and result.result: if not result.error and result.result:
return BaseResponse(result="Added dislike to card") return BaseResponse(result="Added dislike to card")
else: response.status_code = status.HTTP_404_NOT_FOUND
response.status_code = status.HTTP_404_NOT_FOUND return result
return result
@app.post("/comment", status_code=201) @app.post("/comment", status_code=201)
async def comment(comment_info: AddCommentBody, async def comment(
response: Response, comment_info: AddCommentBody,
mongo: MongoWorker = Depends(lambda: mongo_worker)) -> BaseResponse: response: Response,
mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
if not moderate_text(comment_info.comment_text): if not moderate_text(comment_info.comment_text):
response.status_code = status.HTTP_400_BAD_REQUEST response.status_code = status.HTTP_400_BAD_REQUEST
return BaseResponse(result="Comment has not passed base moderation", error=True) return BaseResponse(result="Comment has not passed base moderation", error=True)
result = mongo.add_comment(comment_info.author_id, comment_info.card_id, comment_info.comment_text) result = await mongo.add_comment(comment_info.author_id, comment_info.card_id, comment_info.comment_text)
if result.error and result.result in ["User doesn't exist", "Card doesn't exist"]: if result.error and result.result in ["User doesn't exist", "Card doesn't exist"]:
response.status_code = status.HTTP_404_NOT_FOUND response.status_code = status.HTTP_404_NOT_FOUND
return result return result
elif result.error: if result.error:
response.status_code = status.HTTP_400_BAD_REQUEST response.status_code = status.HTTP_400_BAD_REQUEST
return result return result
else: return result
@app.get("/get_comments", status_code=200)
async def get_comments(
card_id: int,
response: Response,
mongo: MongoWorker = Depends(lambda: mongo_worker),) -> BaseResponse:
result = await mongo.get_comments(card_id)
if result.error:
response.status_code = status.HTTP_404_NOT_FOUND
return result return result
return result
async def main(): async def main():
config = uvicorn.Config("main:app", port=5000, log_level="debug") config = uvicorn.Config("main:app", host="0.0.0.0", port=5000, log_level="info")
server = uvicorn.Server(config) server = uvicorn.Server(config)
await server.serve() await server.serve()
if __name__ == "__main__": if __name__ == "__main__":
asyncio.run(main()) asyncio.run(main())
+185 -159
View File
@@ -1,22 +1,31 @@
import os import os
import logging
import pymongo import motor.motor_asyncio
from datetime import datetime from datetime import datetime
from dotenv import load_dotenv from dotenv import load_dotenv
from typing import Optional from typing import Optional
from pymongo import ReturnDocument
from schemas.base_schemas import * from schemas.base_schemas import User, Visited, Card, Comment
from schemas.api_schemas import * from schemas.api_schemas import BaseResponse
logger = logging.getLogger(__name__)
class MongoWorker: class MongoWorker:
def __init__(self): def __init__(self):
load_dotenv() load_dotenv()
self.client = pymongo.MongoClient(host = os.getenv('MONGO_HOST'), self.client = motor.motor_asyncio.AsyncIOMotorClient(
port = int(os.getenv('MONGO_PORT')), host=os.getenv('MONGO_HOST'),
username = os.getenv('MONGO_USER'), port=int(os.getenv('MONGO_PORT', 27017)),
password = os.getenv('MONGO_PASS')) username=os.getenv('MONGO_USER'),
password=os.getenv('MONGO_PASS'),
serverSelectionTimeoutMS=5000,
connectTimeoutMS=5000,
)
self.db = self.client["data"] self.db = self.client["data"]
self.users_data = self.db["users"] self.users_data = self.db["users"]
self.visited_data = self.db["visited"] self.visited_data = self.db["visited"]
@@ -24,191 +33,208 @@ class MongoWorker:
self.game_data = self.db["cards"] self.game_data = self.db["cards"]
self.comments_data = self.db["comments"] self.comments_data = self.db["comments"]
async def create_indexes(self) -> None:
def check_user(self, user_id: int) -> bool: """Создаёт индексы при старте приложения."""
if self.users_data.find_one({"user_id": user_id}): await self.users_data.create_index("user_id", unique=True)
return True await self.game_data.create_index("card_id", unique=True)
else: await self.game_data.create_index("active_status")
return False await self.visited_data.create_index("user_id", unique=True)
await self.comments_data.create_index("comment_id", unique=True)
def add_user(self, user_id: int, username: str, first_name: str, last_name: str, photo_url: str) -> User: logger.info("MongoDB indexes created.")
new_user = User(user_id=user_id,
username=username,
first_name=first_name,
last_name=last_name,
photo_url=photo_url,
registration_date=datetime.now().isoformat())
try:
self.users_data.insert_one(new_user.model_dump())
return new_user
except Exception as exception:
return new_user
def get_user(self, user_id: int) -> User:
return User.model_validate(self.users_data.find_one({"user_id": user_id}))
def get_and_update_counter(self, counter_name: str) -> int: async def check_user(self, user_id: int) -> bool:
counter = self.counters.find_one_and_update( document = await self.users_data.find_one({"user_id": user_id}, {"_id": 1})
return document is not None
async def add_user(
self, user_id: int, username: str, first_name: str, last_name: str, photo_url: str) -> User:
new_user = User(
user_id=user_id,
username=username,
first_name=first_name,
last_name=last_name,
photo_url=photo_url,
registration_date=datetime.now().isoformat(),
)
await self.users_data.insert_one(new_user.model_dump())
return new_user
async def get_user(self, user_id: int) -> User:
document = await self.users_data.find_one({"user_id": user_id})
return User.model_validate(document)
async def get_and_update_counter(self, counter_name: str) -> int:
"""Атомарно инкрементирует счётчик и возвращает новое значение."""
counter = await self.counters.find_one_and_update(
{"counter_name": counter_name}, {"counter_name": counter_name},
{"$inc": {"counter": 1}}, {"$inc": {"counter": 1}},
upsert=True, upsert=True,
return_document=True) return_document=ReturnDocument.AFTER,
)
return counter["counter"] return counter["counter"]
def get_visited_cards(self, user_id: int) -> BaseResponse: async def get_visited_cards(self, user_id: int) -> BaseResponse:
document = self.visited_data.find_one({"user_id": user_id}) document = await self.visited_data.find_one({"user_id": user_id})
if not document: if not document:
check_user = self.check_user(user_id) if await self.check_user(user_id):
if check_user: return BaseResponse(result=Visited(user_id=user_id, cards_visited=set()))
return BaseResponse(result=Visited(user_id=user_id, return BaseResponse(result="User doesn't exist", error=True)
cards_visited=set())) return BaseResponse(result=Visited.model_validate(document))
else:
return BaseResponse(result="User doesn't exist", error=True) async def update_visited_cards(self, user_id: int, visited_card_id: int) -> Visited:
else: updated = await self.visited_data.find_one_and_update(
return BaseResponse(result=Visited.model_validate(document)) {"user_id": user_id},
{"$addToSet": {"cards_visited": visited_card_id}},
upsert=True,
return_document=ReturnDocument.AFTER,
)
return Visited.model_validate(updated)
async def get_card(self, card_id: int) -> Optional[Card]:
document = await self.game_data.find_one({"card_id": card_id})
if document:
return Card.model_validate(document)
return None
async def get_random_cards(self, amount: int,active_status: bool,exclude_ids: Optional[set[int]] = None,) -> Optional[list[Card]]:
"""Возвращает случайные карточки, исключая уже просмотренные (одним запросом)."""
match_filter: dict = {"active_status": active_status}
if exclude_ids:
match_filter["card_id"] = {"$nin": list(exclude_ids)}
pipeline = [
{"$match": match_filter},
{"$sample": {"size": amount}},
]
raw_items = await self.game_data.aggregate(pipeline).to_list(length=amount)
if raw_items:
return [Card.model_validate(item) for item in raw_items]
return None
def filter_cards(self, random_cards: list[Card], cards_visited: set) -> tuple[list[Card], list[int]]: def filter_cards(self, random_cards: list[Card], cards_visited: set) -> tuple[list[Card], list[int]]:
filtered_cards = [card for card in random_cards if card.card_id not in cards_visited] filtered_cards = [card for card in random_cards if card.card_id not in cards_visited]
filtered_cards_id = [filtered_card.card_id for filtered_card in filtered_cards] filtered_cards_id = [card.card_id for card in filtered_cards]
return filtered_cards, filtered_cards_id return filtered_cards, filtered_cards_id
def update_visited_cards(self, user_id: int, visited_card_id: int) -> Visited: async def add_card_by_api(self, choice_A: str, choice_B: str, author_id: int) -> Card:
update_visited = self.visited_data.find_one_and_update({"user_id": user_id}, new_card = Card(
{"$addToSet": {"cards_visited": visited_card_id}}, card_id=await self.get_and_update_counter(counter_name="card"),
upsert=True, choice_A=choice_A,
return_document=True) choice_B=choice_B,
return Visited.model_validate(update_visited) author_id=author_id,
creation_date=datetime.now().isoformat(),
)
await self.game_data.insert_one(new_card.model_dump())
return new_card
async def add_card_by_base_model(self, new_card: Card) -> Optional[Card]:
def add_card_by_api(self, choice_A: str, choice_B: str, author_id: int) -> Card: new_card.card_id = await self.get_and_update_counter(counter_name="card")
new_card = Card(card_id=self.get_and_update_counter(counter_name="card"),
choice_A=choice_A,
choice_B=choice_B,
author_id=author_id,
creation_date=datetime.now().isoformat())
try: try:
self.game_data.insert_one(new_card.model_dump()) await self.game_data.insert_one(new_card.model_dump())
return new_card
except Exception as exception:
print(exception)
return new_card return new_card
except Exception as exc:
logger.error("Failed to insert card: %s", exc)
raise
def add_card_by_base_model(self, new_card: Card) -> Optional[Card]: async def select_choice(self, card_id: int, choice: str) -> BaseResponse:
new_card.card_id = self.get_and_update_counter(counter_name="card")
try:
self.game_data.insert_one(new_card.model_dump())
return new_card
except Exception as exception:
print(exception)
return new_card
def get_card(self, card_id: int) -> Optional[Card]:
document = self.game_data.find_one({"card_id": card_id})
if document:
return Card.model_validate(document)
else:
return None
def get_random_cards(self, amount: int, active_status: bool) -> Optional[list[Card]]:
pipeline = [{"$match": {"active_status": active_status}},
{"$sample": {"size": amount}}]
raw_items = list(self.game_data.aggregate(pipeline))
if raw_items:
validated_items = [Card.model_validate(item) for item in raw_items]
return validated_items
else:
return None
def select_choice(self, card_id: int, choice: str) -> BaseResponse:
if choice == "A": if choice == "A":
count_choice = "count_choice_A" count_field = "count_choice_A"
elif choice == "B": elif choice == "B":
count_choice = "count_choice_B" count_field = "count_choice_B"
else: else:
return BaseResponse(result="Wrong choice", error=True) return BaseResponse(result="Wrong choice", error=True)
result = self.game_data.find_one_and_update({"card_id": card_id}, result = await self.game_data.find_one_and_update(
{"$inc": {"count_total": 1, count_choice: 1}}) {"card_id": card_id},
{"$inc": {"count_total": 1, count_field: 1}},
)
if not result: if not result:
return BaseResponse(result="Card doesn't exist", error=True) return BaseResponse(result="Card doesn't exist", error=True)
else: return BaseResponse(result=True, error=False)
return BaseResponse(result=result, error=False)
def check_user_reactions(self, user_id: int, card_id: int) -> BaseResponse:
user_info: User = self.get_user(user_id)
liked_card_ids: list = user_info.liked_card_ids
disliked_card_ids: list = user_info.disliked_card_ids
if card_id in liked_card_ids: async def check_user_reactions(self, user_id: int, card_id: int) -> BaseResponse:
user_info: User = await self.get_user(user_id)
if card_id in user_info.liked_card_ids:
return BaseResponse(result="Card already liked", error=True) return BaseResponse(result="Card already liked", error=True)
elif card_id in disliked_card_ids: if card_id in user_info.disliked_card_ids:
return BaseResponse(result="Card already disliked", error=True) return BaseResponse(result="Card already disliked", error=True)
else: return BaseResponse(result="No reactions", error=False)
return BaseResponse(result="No reactions", error=False)
def like_card(self, card_id: int, user_id: int) -> BaseResponse: async def like_card(self, card_id: int, user_id: int) -> BaseResponse:
if self.check_user(user_id): if not await self.check_user(user_id):
user_reaction = self.check_user_reactions(user_id, card_id)
if user_reaction.error:
return user_reaction
update_card_info = self.game_data.find_one_and_update({"card_id": card_id},
{"$inc": {"count_likes": 1}})
if not update_card_info:
return BaseResponse(result="Card doesn't exist", error=True)
add_card_to_user = self.users_data.update_one({'user_id': user_id},
{'$push': {'liked_card_ids': card_id}})
if not add_card_to_user:
return BaseResponse(result="User doesn't exist", error=True)
else:
return BaseResponse(result=True, error=False)
else:
return BaseResponse(result="User doesn't exist", error=True) return BaseResponse(result="User doesn't exist", error=True)
def dislike_card(self, card_id: int, user_id: int) -> BaseResponse: user_reaction = await self.check_user_reactions(user_id, card_id)
if self.check_user(user_id): if user_reaction.error:
user_reaction = self.check_user_reactions(user_id, card_id) return user_reaction
if user_reaction.error:
return user_reaction
update_card_info = self.game_data.find_one_and_update({"card_id": card_id},
{"$inc": {"count_dislikes": 1}})
if not update_card_info:
return BaseResponse(result="Card doesn't exist", error=True)
add_card_to_user = self.users_data.update_one({'user_id': user_id}, updated_card = await self.game_data.find_one_and_update(
{'$push': {'disliked_card_ids': card_id}}) {"card_id": card_id},
if not add_card_to_user: {"$inc": {"count_likes": 1}},
return BaseResponse(result="User doesn't exist", error=True) )
else: if not updated_card:
return BaseResponse(result=True, error=False) return BaseResponse(result="Card doesn't exist", error=True)
else:
await self.users_data.update_one(
{"user_id": user_id},
{"$push": {"liked_card_ids": card_id}},
)
return BaseResponse(result=True, error=False)
async def dislike_card(self, card_id: int, user_id: int) -> BaseResponse:
if not await self.check_user(user_id):
return BaseResponse(result="User doesn't exist", error=True) return BaseResponse(result="User doesn't exist", error=True)
def add_comment(self, user_id: int, card_id: int, comment_text: str) -> BaseResponse: user_reaction = await self.check_user_reactions(user_id, card_id)
if self.check_user(user_id): if user_reaction.error:
if self.get_card(card_id): return user_reaction
new_comment = Comment(comment_id=self.get_and_update_counter(counter_name="comment"),
author_id=user_id, updated_card = await self.game_data.find_one_and_update(
card_id=card_id, {"card_id": card_id},
commet_text=comment_text, {"$inc": {"count_dislikes": 1}},
creation_date=datetime.now().isoformat()) )
result = self.comments_data.insert_one(new_comment.model_dump()) if not updated_card:
if result: return BaseResponse(result="Card doesn't exist", error=True)
update_user_comments = self.users_data.find_one_and_update({"user_id": user_id},
{"$addToSet": {"comments_ids": new_comment.comment_id}}) await self.users_data.update_one(
if update_user_comments: {"user_id": user_id},
return BaseResponse(result=new_comment) {"$push": {"disliked_card_ids": card_id}},
else: )
return BaseResponse(result="Difficulty adding comment_id to user", error=True) return BaseResponse(result=True, error=False)
else:
return BaseResponse(result="Add comment error", error=True)
else: async def add_comment(self, user_id: int, card_id: int, comment_text: str) -> BaseResponse:
return BaseResponse(result="Card doesn't exist", error=True) if not await self.check_user(user_id):
else:
return BaseResponse(result="User doesn't exist", error=True) return BaseResponse(result="User doesn't exist", error=True)
if not await self.get_card(card_id):
return BaseResponse(result="Card doesn't exist", error=True)
new_comment = Comment(
comment_id=await self.get_and_update_counter(counter_name="comment"),
author_id=user_id,
card_id=card_id,
commet_text=comment_text,
creation_date=datetime.now().isoformat(),
)
await self.comments_data.insert_one(new_comment.model_dump())
updated_user = await self.users_data.find_one_and_update(
{"user_id": user_id},
{"$addToSet": {"comments_ids": new_comment.comment_id}},
return_document=ReturnDocument.AFTER,
)
if not updated_user:
return BaseResponse(result="Difficulty adding comment_id to user", error=True)
return BaseResponse(result=new_comment)
async def get_comments(self, card_id: int) -> BaseResponse:
comments = await self.comments_data.find({"card_id": card_id}).sort("creation_date", -1).to_list(length=None)
comments = [Comment.model_validate(comment) for comment in comments]
return BaseResponse(result=comments)
+1 -1
View File
@@ -1,4 +1,4 @@
fastapi==0.115.7 fastapi==0.115.7
pymongo==4.10.1 motor==3.7.0
python-dotenv==1.0.1 python-dotenv==1.0.1
uvicorn==0.34.0 uvicorn==0.34.0