Skip to content

Commit

Permalink
Merge pull request #6 from sinasezza/sinasezza
Browse files Browse the repository at this point in the history
feat(chat): private and public rooms creation and join apis added to …
  • Loading branch information
sinasezza authored Jul 29, 2024
2 parents b2b6b2e + 67d27be commit e6f6850
Show file tree
Hide file tree
Showing 17 changed files with 301 additions and 36 deletions.
4 changes: 3 additions & 1 deletion chatApp/config/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ def create_access_token(
if expires_delta:
expire = datetime.now(UTC) + expires_delta
else:
expire = datetime.now(UTC) + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
expire = datetime.now(UTC) + timedelta(
minutes=ACCESS_TOKEN_EXPIRE_MINUTES
)
to_encode.update({"exp": expire})

encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
Expand Down
4 changes: 3 additions & 1 deletion chatApp/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class Settings(BaseSettings):
upload_dir: Path = Field(default=BASE_DIR / "uploads")
max_upload_size: int = Field(default=(5 * 1024 * 1024))

model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
model_config = SettingsConfigDict(
env_file=".env", env_file_encoding="utf-8"
)

def __init__(self, **kwargs):
super().__init__(**kwargs)
Expand Down
28 changes: 23 additions & 5 deletions chatApp/config/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,12 @@ async def connect_to_mongodb(self) -> None:
# Initialize collections
self.users_collection = self.db.get_collection("users")
self.messages_collection = self.db.get_collection("messages")
self.rooms_collection = self.db.get_collection("rooms")
self.public_rooms_collection = self.db.get_collection(
"public_rooms"
)
self.private_rooms_collection = self.db.get_collection(
"private_rooms"
)

# Ping the server to validate the connection
await self.db_client.admin.command("ismaster")
Expand Down Expand Up @@ -80,14 +85,27 @@ def get_messages_collection() -> AsyncIOMotorCollection:
return messages_collection


def get_rooms_collection() -> AsyncIOMotorCollection:
def get_public_rooms_collection() -> AsyncIOMotorCollection:
"""
Retrieve the public rooms collection from the MongoDB database.
:return: The rooms collection instance.
:raises RuntimeError: If the rooms collection is not initialized.
"""
rooms_collection = mongo_db.public_rooms_collection
if rooms_collection is None:
raise RuntimeError("public rooms collection is not initialized.")
return rooms_collection


def get_private_rooms_collection() -> AsyncIOMotorCollection:
"""
Retrieve the rooms collection from the MongoDB database.
Retrieve the private rooms collection from the MongoDB database.
:return: The rooms collection instance.
:raises RuntimeError: If the rooms collection is not initialized.
"""
rooms_collection = mongo_db.rooms_collection
rooms_collection = mongo_db.private_rooms_collection
if rooms_collection is None:
raise RuntimeError("rooms collection is not initialized.")
raise RuntimeError("private rooms collection is not initialized.")
return rooms_collection
2 changes: 1 addition & 1 deletion chatApp/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ async def root() -> dict[str, str]:


# Mount socket.io app
app.mount("/", app=sio_app)
app.mount("/socket.io/", app=sio_app)


if __name__ == "__main__":
Expand Down
17 changes: 13 additions & 4 deletions chatApp/middlewares/request_limit.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
from collections import defaultdict

from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.middleware.base import (
BaseHTTPMiddleware,
RequestResponseEndpoint,
)
from starlette.types import ASGIApp

from chatApp.config.logs import logger # Import your custom logger


class RequestLimitMiddleware(BaseHTTPMiddleware):
def __init__(self, app: ASGIApp, max_requests: int = 4, window_seconds: int = 1):
def __init__(
self, app: ASGIApp, max_requests: int = 4, window_seconds: int = 1
):
super().__init__(app)
self.max_requests = max_requests
self.window_seconds = window_seconds
Expand Down Expand Up @@ -41,7 +46,9 @@ async def dispatch(

# If the count exceeds the limit, return a 429 Too Many Requests response
if count > self.max_requests:
logger.warning(f"Too many requests from {client_ip} - Count: {count}")
logger.warning(
f"Too many requests from {client_ip} - Count: {count}"
)
return Response("Too many requests", status_code=429)

# Measure start time of request processing
Expand All @@ -54,7 +61,9 @@ async def dispatch(
process_time = time.time() - start_time

# Log the request processing time
logger.info(f"Processed request from {client_ip} in {process_time:.4f} seconds")
logger.info(
f"Processed request from {client_ip} in {process_time:.4f} seconds"
)

# Add X-Process-Time header to the response
response.headers["X-Process-Time"] = str(process_time)
Expand Down
6 changes: 3 additions & 3 deletions chatApp/models/message.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import datetime

from pydantic import BaseModel, Field

Expand All @@ -10,8 +10,8 @@ class Message(BaseModel):
room_id: str | None = Field(default=None)
content: str = Field(default=None)
media: str = Field(default=None)
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
created_at: datetime = Field(default_factory=lambda: datetime.now())


class MessageInDB(Message):
id: PydanticObjectId = Field(alias="_id")
id: PydanticObjectId = Field(alias="_id", serialization_alias="id")
11 changes: 6 additions & 5 deletions chatApp/models/room.py → chatApp/models/private_room.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from datetime import datetime, timezone
from datetime import datetime

from pydantic import BaseModel, Field

from chatApp.utils.object_id import PydanticObjectId


class Room(BaseModel):
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
members: list[PydanticObjectId]
class PrivateRoom(BaseModel):
member1: PydanticObjectId
member2: PydanticObjectId
created_at: datetime = Field(default_factory=lambda: datetime.now())


class RoomInDB(Room):
class PrivateRoomInDB(PrivateRoom):
id: PydanticObjectId = Field(alias="_id")
43 changes: 43 additions & 0 deletions chatApp/models/public_room.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from datetime import datetime

from pydantic import BaseModel, Field

from chatApp.utils.object_id import PydanticObjectId


class PublicRoom(BaseModel):
owner: PydanticObjectId
name: str
description: str | None = Field(
default=None, description="Description of the room"
)
max_members: int | None = Field(
default=None, description="Maximum number of members allowed"
)
welcome_message: str | None = Field(
default=None, description="Welcome message for the room"
)
rules: str | None = Field(default=None, description="Rules for the room")
allow_file_sharing: bool = Field(
default=True, description="Allow file sharing in the room"
)
members: list[PydanticObjectId] = Field(
default_factory=list, description="List of user IDs"
)
ban_list: list[PydanticObjectId] = Field(
default_factory=list, description="List of IDs to be banned"
)
moderators: list[PydanticObjectId] = Field(
default_factory=list, description="List of moderator IDs"
)
allow_users_access_message_history: bool = Field(
True, description="Allow user to access message history"
)
max_latest_messages_access: int | None = Field(
default=None, description="Maximum number of latest messages to access"
)
created_at: datetime = Field(default_factory=lambda: datetime.now())


class PublicRoomInDB(PublicRoom):
id: PydanticObjectId = Field(alias="_id", serialization_alias="id")
8 changes: 4 additions & 4 deletions chatApp/models/user.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from datetime import datetime, timezone
from datetime import datetime

from pydantic import BaseModel, Field

Expand All @@ -11,10 +11,10 @@ class User(BaseModel):
hashed_password: str
is_active: bool = True
is_admin: bool = False
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
created_at: datetime = Field(default_factory=lambda: datetime.now())
updated_at: datetime = Field(default_factory=lambda: datetime.now())
last_login: datetime | None = None


class UserInDB(User):
id: PydanticObjectId = Field(alias="_id")
id: PydanticObjectId = Field(alias="_id", serialization_alias="id")
5 changes: 3 additions & 2 deletions chatApp/routes/auth.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# auth.py
from collections.abc import Mapping
from datetime import timedelta
from datetime import datetime, timedelta
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status
Expand Down Expand Up @@ -35,6 +34,8 @@ async def register_user(user: UserCreateSchema) -> UserInDB:
user_dict = user.model_dump(exclude={"password"})
user_dict["hashed_password"] = hashed_password

user_dict["created_at"] = datetime.now()

# Insert user into the database
await users_collection.insert_one(user_dict)

Expand Down
Loading

0 comments on commit e6f6850

Please sign in to comment.