Skip to content

Commit

Permalink
ref(chat): chat apis and models refactored and optimized.
Browse files Browse the repository at this point in the history
  • Loading branch information
sinasezza committed Aug 4, 2024
1 parent 801b21a commit 67135a5
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 243 deletions.
59 changes: 42 additions & 17 deletions chatApp/models/message.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from collections.abc import Mapping
from datetime import datetime
from typing import Any

from pydantic import BaseModel, Field

from chatApp.config.database import get_messages_collection
from chatApp.config.database import (
get_messages_collection,
get_private_rooms_collection,
)
from chatApp.utils.object_id import PydanticObjectId

from .public_room import fetch_public_room_by_id
Expand All @@ -29,27 +30,51 @@ class MessageInDB(Message):
# return result.inserted_id


async def get_public_messages(
room_id: str,
) -> tuple[bool, list[Mapping[str, Any]]]:
async def get_public_messages(room_id: str) -> list[MessageInDB]:
"""
Fetch public messages from a specific room.
:param room_id: The ID of the public room to fetch messages from.
:return: A tuple where the first element is a boolean indicating success,
and the second element is a list of messages (each message represented as a dictionary).
"""
messages_collection = get_messages_collection()

# Fetch the public room by ID
room = await fetch_public_room_by_id(room_id)
if room is None:
return False, []
return []

room_id_obj = PydanticObjectId(room_id)
query = {"room_id": room_id_obj, "room_type": "public"}

# Fetch the documents using the query
cursor = messages_collection.find(query)

# Convert the cursor to a list and await the result
messages = await cursor.to_list(length=None)

# Convert each document to MessageInDB
return [MessageInDB(**message) for message in messages]


async def get_private_messages(
room_id: str,
) -> list[MessageInDB]:
"""
Fetch private messages from a specific room between two users.
"""
# Fetch the private room by ID
room_collection = get_private_rooms_collection()
room_id_obj = PydanticObjectId(room_id)
room = await room_collection.find_one({"_id": room_id_obj})
if room is None:
return []

messages_collection = get_messages_collection()
query = {"room_id": room_id_obj, "room_type": "private"}

# Fetch the documents using the query
cursor = messages_collection.find(query)

# Fetch messages from the messages collection
cursor = messages_collection.find({"room_id": room_id})
messages = await cursor.to_list(
length=None
) # Await the cursor to list conversion
# Convert the cursor to a list and await the result
messages = await cursor.to_list(length=None)

return True, messages
# Convert each document to MessageInDB
return [MessageInDB(**message) for message in messages]
76 changes: 61 additions & 15 deletions chatApp/models/private_room.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from collections.abc import Mapping
from datetime import datetime
from typing import Any

from pydantic import BaseModel, Field

from chatApp.config.database import get_private_rooms_collection
from chatApp.models.message import MessageInDB, get_private_messages
from chatApp.utils.object_id import PydanticObjectId


Expand All @@ -16,14 +19,17 @@ class PrivateRoomInDB(PrivateRoom):
id: PydanticObjectId = Field(alias="_id")


async def fetch_private_room_by_id(id: str):
async def fetch_private_room_by_id(id: str) -> PrivateRoomInDB | None:
room_collection = get_private_rooms_collection()
return await room_collection.find_one({"_id": PydanticObjectId(id)})
room = await room_collection.find_one({"_id": PydanticObjectId(id)})
return PrivateRoomInDB(**room) if room else None


async def check_members_in_room(user1_id: str, user2_id: str):
async def fetch_private_room_by_members(
user1_id: str, user2_id: str
) -> PrivateRoomInDB | None:
rooms_collection = get_private_rooms_collection()
room = await rooms_collection.find_one(
room: Mapping[str, Any] | None = await rooms_collection.find_one(
{
"$or": [
{
Expand All @@ -37,21 +43,61 @@ async def check_members_in_room(user1_id: str, user2_id: str):
],
}
)
return str(room["_id"]) if room is not None else None
return PrivateRoomInDB(**room) if room else None


async def join_private_room(user1_id: str, user2_id: str) -> str:
async def check_user_in_private_room(room_id: str, user_id: str) -> bool:
room: PrivateRoomInDB | None = await fetch_private_room_by_id(room_id)
user_id_obj = PydanticObjectId(user_id)
return user_id_obj in [room.member1, room.member2] if room else False


async def get_user_private_rooms(user_id: str) -> list[PrivateRoomInDB]:
rooms_collection = get_private_rooms_collection()

# Create a query to find private rooms for the specified user
query = {
"$or": [
{"member1": PydanticObjectId(user_id)},
{"member2": PydanticObjectId(user_id)},
]
}

# Fetch the documents using the query
cursor = rooms_collection.find(query)

# Convert the cursor to a list and await the result
rooms = await cursor.to_list(length=None)

# Convert each document to PrivateRoomInDB
return [PrivateRoomInDB(**room) for room in rooms]


async def get_private_room_messages(room_id: str) -> list[MessageInDB]:
return await get_private_messages(room_id)


async def create_private_room(user1_id: str, user2_id: str) -> PrivateRoomInDB:
if user1_id == user2_id:
raise ValueError("Users cannot be the same")

rooms_collection = get_private_rooms_collection()

room_id = await check_members_in_room(user1_id, user2_id)
room = await fetch_private_room_by_members(user1_id, user2_id)

if room_id is not None:
return room_id
if room is not None:
return room
else:
room = await rooms_collection.insert_one(
{
"member1": PydanticObjectId(user1_id),
"member2": PydanticObjectId(user2_id),
}
user1_id_obj = PydanticObjectId(user1_id)
user2_id_obj = PydanticObjectId(user2_id)
new_room = PrivateRoom(
member1=user1_id_obj,
member2=user2_id_obj,
created_at=datetime.now(),
)
new_room_obj = await rooms_collection.insert_one(
new_room.model_dump(by_alias=True)
)
return PrivateRoomInDB(
**new_room.model_dump(by_alias=True), _id=new_room_obj.inserted_id
)
return str(room.inserted_id)
85 changes: 71 additions & 14 deletions chatApp/models/public_room.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from datetime import datetime
from typing import Any

from fastapi import status
from pydantic import BaseModel, Field

from chatApp.config.database import get_public_rooms_collection
from chatApp.schemas.public_room import GetPublicRoomSchema
from chatApp.utils.object_id import PydanticObjectId


Expand Down Expand Up @@ -44,25 +47,36 @@ class PublicRoomInDB(PublicRoom):
id: PydanticObjectId = Field(alias="_id", serialization_alias="id")


async def fetch_public_room_by_id(id: str):
async def fetch_all_public_rooms() -> list[GetPublicRoomSchema]:
"""Fetch all public rooms and return them as a list of GetPublicRoomSchema."""
rooms_collection = get_public_rooms_collection()
rooms = await rooms_collection.find().to_list(length=None)
return [
GetPublicRoomSchema(**room, members_count=len(room["members"]))
for room in rooms
]


async def fetch_public_room_by_id(id: str) -> PublicRoomInDB | None:
room_collection = get_public_rooms_collection()
return await room_collection.find_one({"_id": PydanticObjectId(id)})
room = await room_collection.find_one({"_id": PydanticObjectId(id)})
return PublicRoomInDB(**room) if room else None


async def join_public_room(room_id: str, user_id: str) -> bool:
async def join_public_room(
room_id: str, user_id: str
) -> tuple[bool, str | None, int]:
rooms_collection = get_public_rooms_collection()
room = await rooms_collection.find_one({"_id": PydanticObjectId(room_id)})
room: PublicRoomInDB | None = await fetch_public_room_by_id(room_id)

# Ensure room is not None
if room is None:
return False

# Define the expected structure of the room dictionary
# Adjust this according to the actual structure
ban_list: list[PydanticObjectId] = room.get("ban_list", [])
members: list[PydanticObjectId] = room.get("members", [])
return False, "room not found", status.HTTP_404_NOT_FOUND

ban_list: list[PydanticObjectId] = room.ban_list
members: list[PydanticObjectId] = room.members
userObjId = PydanticObjectId(user_id)

if userObjId not in ban_list:
if userObjId not in members:
members.append(userObjId)
Expand All @@ -74,8 +88,51 @@ async def join_public_room(room_id: str, user_id: str) -> bool:
)

if result.modified_count == 1:
return True
return True, None, status.HTTP_204_NO_CONTENT
else:
return False # Failed to update the room in the database
return True # User is already a member
return False # User is banned
return (
False,
"something went wrong, please try again",
status.HTTP_500_INTERNAL_SERVER_ERROR,
) # Failed to update the room in the database
return (
True,
None,
status.HTTP_204_NO_CONTENT,
) # User is already a member
return (
False,
"you are banned from this room",
status.HTTP_403_FORBIDDEN,
) # User is banned


async def check_user_in_public_room(room_id: str, user_id: str) -> bool:
room: PublicRoomInDB | None = await fetch_public_room_by_id(room_id)
user_id_obj = PydanticObjectId(user_id)
if room is None:
return False
if user_id_obj not in room.ban_list or user_id_obj not in room.members:
return False
return True


async def create_public_room(
owner: str, room_info: dict[str, Any]
) -> PublicRoomInDB | None:
rooms_collection = get_public_rooms_collection()

user_id_obj = PydanticObjectId(owner)
room = PublicRoom(
**room_info,
owner=user_id_obj,
created_at=datetime.now(),
members=[user_id_obj],
)

room_obj = await rooms_collection.insert_one(
room.model_dump(by_alias=True)
)
return PublicRoomInDB(
**room.model_dump(by_alias=True), _id=room_obj.inserted_id
)
Loading

0 comments on commit 67135a5

Please sign in to comment.