Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(socket): join rooms and send messages in public and private room… #8

Merged
merged 1 commit into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions chatApp/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ class Settings(BaseSettings):
refresh_token_expire_days: int = Field(default=14)

# CORS settings
cors_allow_origins: list[str] = Field(default=["*"])
cors_allow_origins: list[str] | str = Field(default=["*"])
cors_allow_credentials: bool = Field(default=True)
cors_allow_methods: list[str] = Field(default=["*"])
cors_allow_headers: list[str] = Field(default=["*"])
cors_allow_methods: list[str] | str = Field(default=["*"])
cors_allow_headers: list[str] | str = Field(default=["*"])

# Trusted hosts settings
trusted_hosts: list[str] = Field(default=["127.0.0.1", "localhost"])
Expand Down
5 changes: 5 additions & 0 deletions chatApp/config/database.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from functools import lru_cache

from motor.motor_asyncio import (
AsyncIOMotorClient,
Expand Down Expand Up @@ -59,6 +60,7 @@ async def close_mongodb_connection(self) -> None:
mongo_db = MongoDB()


@lru_cache
def get_users_collection() -> AsyncIOMotorCollection:
"""
Retrieve the users collection from the MongoDB database.
Expand All @@ -72,6 +74,7 @@ def get_users_collection() -> AsyncIOMotorCollection:
return users_collection


@lru_cache
def get_messages_collection() -> AsyncIOMotorCollection:
"""
Retrieve the messages collection from the MongoDB database.
Expand All @@ -85,6 +88,7 @@ def get_messages_collection() -> AsyncIOMotorCollection:
return messages_collection


@lru_cache
def get_public_rooms_collection() -> AsyncIOMotorCollection:
"""
Retrieve the public rooms collection from the MongoDB database.
Expand All @@ -98,6 +102,7 @@ def get_public_rooms_collection() -> AsyncIOMotorCollection:
return rooms_collection


@lru_cache
def get_private_rooms_collection() -> AsyncIOMotorCollection:
"""
Retrieve the private rooms collection from the MongoDB database.
Expand Down
6 changes: 3 additions & 3 deletions chatApp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ async def shutdown_event():
)

# Include your routers for API endpoints
app.include_router(auth.router, prefix="/auth")
app.include_router(chat.router, prefix="/chat")
app.include_router(user.router, prefix="/user")
app.include_router(auth.router, prefix="/auth", tags=["auth"])
app.include_router(chat.router, prefix="/chat", tags=["chat"])
app.include_router(user.router, prefix="/user", tags=["user"])


@app.get("/")
Expand Down
42 changes: 40 additions & 2 deletions chatApp/models/message.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,55 @@
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.utils.object_id import PydanticObjectId

from .public_room import fetch_public_room_by_id


class Message(BaseModel):
user_id: PydanticObjectId
room_id: PydanticObjectId
content: str = Field(default=None)
media: str = Field(default=None)
room_type: str
content: str | None = Field(default=None)
media: str | None = Field(default=None)
created_at: datetime = Field(default_factory=lambda: datetime.now())


class MessageInDB(Message):
id: PydanticObjectId = Field(alias="_id", serialization_alias="id")


# async def insert_message(message: str):
# message_collection = get_messages_collection()
# result = await message_collection.insert_one(message.dict())
# return result.inserted_id


async def get_public_messages(
room_id: str,
) -> tuple[bool, list[Mapping[str, Any]]]:
"""
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, []

# 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

return True, messages
42 changes: 42 additions & 0 deletions chatApp/models/private_room.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pydantic import BaseModel, Field

from chatApp.config.database import get_private_rooms_collection
from chatApp.utils.object_id import PydanticObjectId


Expand All @@ -13,3 +14,44 @@ class PrivateRoom(BaseModel):

class PrivateRoomInDB(PrivateRoom):
id: PydanticObjectId = Field(alias="_id")


async def fetch_private_room_by_id(id: str):
room_collection = get_private_rooms_collection()
return await room_collection.find_one({"_id": PydanticObjectId(id)})


async def check_members_in_room(user1_id: str, user2_id: str):
rooms_collection = get_private_rooms_collection()
room = await rooms_collection.find_one(
{
"$or": [
{
"member1": PydanticObjectId(user1_id),
"member2": PydanticObjectId(user2_id),
},
{
"member1": PydanticObjectId(user2_id),
"member2": PydanticObjectId(user1_id),
},
],
}
)
return str(room["_id"]) if room is not None else None


async def join_private_room(user1_id: str, user2_id: str) -> str:
rooms_collection = get_private_rooms_collection()

room_id = await check_members_in_room(user1_id, user2_id)

if room_id is not None:
return room_id
else:
room = await rooms_collection.insert_one(
{
"member1": PydanticObjectId(user1_id),
"member2": PydanticObjectId(user2_id),
}
)
return str(room.inserted_id)
38 changes: 38 additions & 0 deletions chatApp/models/public_room.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from pydantic import BaseModel, Field

from chatApp.config.database import get_public_rooms_collection
from chatApp.utils.object_id import PydanticObjectId


Expand Down Expand Up @@ -41,3 +42,40 @@ class PublicRoom(BaseModel):

class PublicRoomInDB(PublicRoom):
id: PydanticObjectId = Field(alias="_id", serialization_alias="id")


async def fetch_public_room_by_id(id: str):
room_collection = get_public_rooms_collection()
return await room_collection.find_one({"_id": PydanticObjectId(id)})


async def join_public_room(room_id: str, user_id: str) -> bool:
rooms_collection = get_public_rooms_collection()
room = await rooms_collection.find_one({"_id": PydanticObjectId(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", [])

userObjId = PydanticObjectId(user_id)
if userObjId not in ban_list:
if userObjId not in members:
members.append(userObjId)

# Update the room in the database
result = await rooms_collection.update_one(
{"_id": PydanticObjectId(room_id)},
{"$set": {"members": members}}, # Update only members
)

if result.modified_count == 1:
return True
else:
return False # Failed to update the room in the database
return True # User is already a member
return False # User is banned
36 changes: 35 additions & 1 deletion chatApp/routes/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from chatApp.models.public_room import PublicRoom, PublicRoomInDB
from chatApp.models.user import UserInDB
from chatApp.schemas.private_room import CreatePrivateRoom
from chatApp.schemas.public_room import CreatePublicRoom
from chatApp.schemas.public_room import CreatePublicRoom, GetPulbicRoomsSchema
from chatApp.utils.object_id import PydanticObjectId, is_valid_object_id

router = APIRouter()
Expand Down Expand Up @@ -75,6 +75,40 @@ async def join_public_room(
return PublicRoomInDB(**room)


@router.get("/get-public-rooms/", response_model=Mapping[str, Any])
async def get_public_rooms(
page: int = 1,
per_page: int = 10,
):
rooms_collection: AsyncIOMotorCollection = get_public_rooms_collection()
total_count = await rooms_collection.count_documents({})
rooms = (
await rooms_collection.find(
{},
{
"_id": 1,
"name": 1,
"description": 1,
"owner": 1,
"created_at": 1,
},
)
.skip((page - 1) * per_page)
.limit(per_page)
.to_list(None)
)

data_to_return = {
"data": [GetPulbicRoomsSchema(**room) for room in rooms],
"meta": {
"total_count": total_count,
"page": page,
"per_page": per_page,
},
}
return data_to_return


@router.post(
"/create-private-room/{person_id}", response_model=PrivateRoomInDB
)
Expand Down
17 changes: 17 additions & 0 deletions chatApp/schemas/public_room.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from datetime import datetime

from pydantic import BaseModel, Field

from chatApp.utils.object_id import PydanticObjectId


class CreatePublicRoom(BaseModel):
name: str = Field(..., description="Name of the public room")
Expand All @@ -20,3 +24,16 @@ class CreatePublicRoom(BaseModel):
max_latest_messages_access: int | None = Field(
None, description="Maximum number of latest messages to access"
)


class GetPulbicRoomsSchema(BaseModel):
id: PydanticObjectId = Field(
...,
description="id of the room",
alias="_id",
serialization_alias="id",
)
owner: PydanticObjectId = Field(..., description="id of owner of the room")
name: str
description: str | None = None
created_at: datetime
Loading
Loading