From 4811b8cd7b8fb483589bf353f812e487a7a240d2 Mon Sep 17 00:00:00 2001 From: ablogo Date: Sun, 28 Dec 2025 22:14:14 -0600 Subject: [PATCH] Remove chat service and models --- .env | 2 +- README.md | 10 +- src/dependency_injection/containers.py | 2 +- src/main.py | 5 +- src/models/friends_model.py | 20 --- src/models/message_model.py | 25 ---- src/routers/chat_router.py | 132 ----------------- src/services/chat_service.py | 187 ------------------------- 8 files changed, 9 insertions(+), 374 deletions(-) delete mode 100644 src/models/friends_model.py delete mode 100644 src/models/message_model.py delete mode 100644 src/routers/chat_router.py delete mode 100644 src/services/chat_service.py diff --git a/.env b/.env index ce2dcad..d1ad8de 100644 --- a/.env +++ b/.env @@ -10,4 +10,4 @@ LOG_LEVEL=DEBUG JWT_SECRET_KEY= JWT_ALGORITHM=HS256 JWT_EXPIRE_MINUTES=15 -CORS_ALLOWED_HOSTS="http://localhost:8081" \ No newline at end of file +CORS_ALLOWED_HOSTS="http://localhost:8081,http://localhost:8082" \ No newline at end of file diff --git a/README.md b/README.md index c81f151..dbd1ac0 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ It is a microservice for user administration and authenication, using JWT tokens - Python 3.12+ - FastApi 0.124+ +> [!IMPORTANT] +> It is necessary to complete the configuration file(.env), and create the PEM files and place them in the root folder + ## Installing 1. Create a virtual environment ```bash @@ -35,9 +38,9 @@ Use the private key file to extract the public key in PEM format ```bash openssl rsa -in private_key.pem -pubout -out public_key.pem ``` -5. Set configurations files (.env) for different purposes (mongodb, JWT, CORS, logs) +5. Set configuration file (.env) -The microservice uses mongoDB as its database, so the connection string and other configurations must be included in the configuration file +The microservice uses mongoDB as its database, so the connection string and other configurations (mongodb, JWT, CORS, logs) must be included 6. Run local development server ```bash @@ -63,8 +66,5 @@ docker pull ghcr.io/ablogo/authfastapi:latest docker run -p 8000:80 --env-file .env auth-service:latest ``` -> [!IMPORTANT] -> It is necessary to complete the configuration file(.env), and create the PEM files and place them in the root folder - > [!NOTE] > Since the project is used for learning, it does not strictly follow the concept of microservices, where each microservice should have its own realm of responsability diff --git a/src/dependency_injection/containers.py b/src/dependency_injection/containers.py index 5e517d2..8857c41 100644 --- a/src/dependency_injection/containers.py +++ b/src/dependency_injection/containers.py @@ -16,7 +16,7 @@ class Container(containers.DeclarativeContainer): "src.routers.users_router", "src.routers.admin.users_router", "src.services.user_service", - "src.services.chat_service", + "src.services.login_service", "src.services.jwt_service", "src.routers.products_router" ]) diff --git a/src/main.py b/src/main.py index caf71ec..74bae34 100644 --- a/src/main.py +++ b/src/main.py @@ -4,7 +4,7 @@ from dotenv import load_dotenv import os -from src.routers import auth_router, products_router, users_router, chat_router +from src.routers import auth_router, products_router, users_router from src.routers.admin import users_router as admin_user_router from src.middlewares.jwt_middleware import JWTMiddleware from src.middlewares.http_middleware import HttpMiddleware @@ -34,14 +34,13 @@ async def shutdown(): allow_origins = origins, allow_methods = ["*"], allow_headers = ["*"]) -app.add_middleware(HttpMiddleware) +#app.add_middleware(HttpMiddleware) #app.add_middleware(JWTMiddleware, secret_key= SECRET_KEY, algorithm= ALGORITHM) app.include_router(auth_router.router) app.include_router(users_router.router) app.include_router(products_router.router) app.include_router(admin_user_router.router) -app.include_router(chat_router.router) #Root route @app.get("/") diff --git a/src/models/friends_model.py b/src/models/friends_model.py deleted file mode 100644 index 3cd5014..0000000 --- a/src/models/friends_model.py +++ /dev/null @@ -1,20 +0,0 @@ -from datetime import datetime -from typing import List, Optional -from pydantic import AfterValidator, BaseModel, PlainValidator, Field - -from src.models.pydantic_objects import PyObjectId - -class Contact(BaseModel): - name: str - email: str - last_message: Optional[str] = None - last_message_time: Optional[int] = None - has_conversation: bool = False - created_at: datetime - -class Contacts(BaseModel): - id: Optional[PyObjectId] = Field(default= None, validation_alias="_id", serialization_alias="_id") - email: str - contacts: List[Contact] = list() - created_at: datetime - updated_at: Optional[datetime] = None \ No newline at end of file diff --git a/src/models/message_model.py b/src/models/message_model.py deleted file mode 100644 index 9ebd896..0000000 --- a/src/models/message_model.py +++ /dev/null @@ -1,25 +0,0 @@ -from datetime import datetime, timezone -from typing import Annotated, Optional -from bson import ObjectId -from pydantic import BaseModel, Field -from time import time - -from src.models.pydantic_objects import PyObjectId - -def set_id(value) -> ObjectId: - if value is None: - return ObjectId() - return value - - -class Message(BaseModel): - #id: Annotated[Optional[PyObjectId], PlainValidator(set_id), Field(validate_default=True)] = Field(default=None, validation_alias="_id") - sender: str - receiver: str - message: str - created_at: int = int(time() * 1000) - sended: Optional[bool] = False - #updated_at: Optional[datetime] = None - -class MessagesSended(BaseModel): - ids: list[str] \ No newline at end of file diff --git a/src/routers/chat_router.py b/src/routers/chat_router.py deleted file mode 100644 index 720937f..0000000 --- a/src/routers/chat_router.py +++ /dev/null @@ -1,132 +0,0 @@ -from typing import Annotated -from fastapi import APIRouter, Depends, status -from dependency_injector.wiring import Provide, inject -from fastapi.responses import Response -import json - -from src.logging.mongo_logging import MongoLogger -from src.middlewares.auth_jwt import JWTCustom -from src.models.user_model import User -from src.models.message_model import Message, MessagesSended -from src.dependency_injection.containers import Container -from src.services.mongodb_service import MongoAsyncService -import src.services.chat_service as chatSvc - -oauth2_scheme = JWTCustom(tokenUrl="/auth/sign-in") -router = APIRouter(tags=["chat"], prefix="/chat") -log_dependency = Annotated[MongoLogger, Depends(Provide[Container.logging])] - -@router.get("/get-contacts") -@inject -async def get_contacts(email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - contacts = await chatSvc.get_contacts(email) - except Exception as e: - log.logger.error(e) - finally: - if contacts: - return Response(json.dumps(contacts, default=lambda x: getattr(x, '__dict__', str(x))), status.HTTP_200_OK, media_type="application/json") - else: - return Response(status_code= status.HTTP_404_NOT_FOUND) - -@router.post("/save-message") -@inject -async def save_message(msg: Message, email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - result = await chatSvc.save_message(msg) - status_code = status.HTTP_400_BAD_REQUEST - if result: - status_code = status.HTTP_200_OK - except Exception as e: - log.logger.error(e) - finally: - return Response(status_code= status_code) - -@router.get("/get-messages") -@inject -async def get_messages(email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - messages = await chatSvc.get_messages(email) - except Exception as e: - log.logger.error(e) - finally: - if messages: - return Response(json.dumps(messages, default=lambda x: getattr(x, '__dict__', str(x))), status.HTTP_200_OK, media_type="application/json") - else: - return Response(status_code= status.HTTP_404_NOT_FOUND) - -@router.post("/change-status") -@inject -async def change_status(user_status: bool, email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - result = await chatSvc.change_status(user_status, email) - status_code = status.HTTP_400_BAD_REQUEST - if result: - status_code = status.HTTP_200_OK - except Exception as e: - log.logger.error(e) - finally: - return Response(status_code= status_code) - -@router.post("/change-conversation-status") -@inject -async def change_conversation_status(conversation_status: bool, email_friend, email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - result = await chatSvc.change_status_conversation(conversation_status, email, email_friend) - status_code = status.HTTP_400_BAD_REQUEST - if result: - status_code = status.HTTP_200_OK - except Exception as e: - log.logger.error(e) - finally: - return Response(status_code= status_code) - -@router.post("/mark-as-sended") -@inject -async def mark_messages(ids: MessagesSended, email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - status_code = status.HTTP_404_NOT_FOUND - friends = await chatSvc.mark_messages_as_sent(email, ids) - if friends: - status_code = status.HTTP_200_OK - except Exception as e: - log.logger.error(e) - finally: - return Response(json.dumps(friends), status_code) - -@router.post("/add-friend") -@inject -async def add_friend(name: str, email_friend: str, email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - result = await chatSvc.add_friend(name, email, email_friend) - status_code = status.HTTP_400_BAD_REQUEST - if result: - status_code = status.HTTP_200_OK - except Exception as e: - log.logger.error(e) - finally: - return Response(status_code= status_code) - -@router.delete("/remove-friend") -@inject -async def remove_friend(email_friend: str, email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - result = await chatSvc.remove_friend(email, email_friend) - status_code = status.HTTP_400_BAD_REQUEST - if result: - status_code = status.HTTP_200_OK - except Exception as e: - log.logger.error(e) - finally: - return Response(status_code= status_code) - -@router.post("/generate-keys") -@inject -async def generate_keys(email: Annotated[str, Depends(oauth2_scheme)], log: log_dependency): - try: - result = await chatSvc.generate_keys(email) - return result - except Exception as e: - log.logger.error(e) - finally: - return Response(result, 200) \ No newline at end of file diff --git a/src/services/chat_service.py b/src/services/chat_service.py deleted file mode 100644 index 8222399..0000000 --- a/src/services/chat_service.py +++ /dev/null @@ -1,187 +0,0 @@ -from datetime import datetime -from dependency_injector.wiring import Provide, inject -from dotenv import load_dotenv -import os - -from src.services.user_service import get_user -from src.services.crypto_service import CryptoService -from src.services.mongodb_service import MongoAsyncService -from src.models.friends_model import Contacts, Contact -from src.models.message_model import Message, MessagesSended -from src.logging.mongo_logging import MongoLogger -from src.dependency_injection.containers import Container - -load_dotenv() -crypto_service: CryptoService = Provide[Container.crypto_service] -db_dependency: MongoAsyncService = Provide[Container.database_client] -logger: MongoLogger = Provide[Container.logging] -users_collection = str(os.environ["DB_USERS_COLLECTION"]) -users_contacts_collection = str(os.environ["DB_USERS_CONTACTS_COLLECTION"]) -users_messages_collection = str(os.environ["DB_USERS_MESSAGES_COLLECTION"]) - - -@inject -async def get_contacts(email: str, db = db_dependency, log = logger) -> list[Contact] | None: - try: - contacts = None - if (contacts_db := await db.database[users_contacts_collection].find_one({'email': email})) is not None: - model = Contacts(**contacts_db) - contacts = model.contacts - except Exception as e: - log.logger.error(e) - finally: - return contacts - -@inject -async def get_messages(email: str, db = db_dependency, log = logger) -> list[Message] | None: - try: - messages = None - if (msg_db := await db.database[users_messages_collection].find({ 'receiver': email, 'sended': False }).to_list()) is not None: - messages = [Message(**x) for x in msg_db] - - except Exception as e: - log.logger.error(e) - finally: - return messages - -@inject -async def mark_messages_as_sent(email: str, ids: MessagesSended, db = db_dependency, log = logger) -> bool: - try: - result = False - - query_filter = {"email": email, "created_at": { '$in': ids } } - update_op = {"$set" : {"sended" : True }} - op_result = await db.database[users_messages_collection].update_many(query_filter, update_op) - - if op_result.modified_count > 0: - result = True - - except Exception as e: - log.logger.error(e) - finally: - return result - -@inject -async def add_friend(name: str, email_user: str, email_friend: str, db = db_dependency, log = logger): - try: - result = False - - user = await get_user(email_user, db.database) - friend = await get_user(email_friend, db.database) - - if (friends_db := await db.database[users_contacts_collection].find_one({'email': email_user })) is None: - contact = Contact(name= name, email=email_friend, created_at= datetime.now()) - friends = Contacts( - id = user.id if user != None else None, - email = email_user, - contacts = list([contact]), - created_at= datetime.now()) - op_result = await db.database[users_contacts_collection].insert_one(friends.model_dump()) - - if op_result.inserted_id is not None: - result = True - else: - f = Contacts(**friends_db) - exist = next((x for x in f.contacts if x.email == email_friend), None) - if not exist: - query_filter = {"email": email_user} - update_op = {"$push": { "contacts": Contact(name= name, email= email_friend, created_at= datetime.now()).model_dump() }} - updated_result = await db.database[users_contacts_collection].update_one(query_filter, update_op) - - if updated_result.modified_count > 0: - result = True - else: - result = True - except Exception as e: - log.logger.error(e) - finally: - return result - -@inject -async def change_status(status: bool, email: str, db = db_dependency, log = logger) -> bool: - try: - result = False - user_db = await db.database[users_collection].find_one({'email': email}) - - if user_db != None: - query_filter = {"email": email} - update_op = {"$set" : {"online" : status }} - op_result = await db.database[users_collection].update_one(query_filter, update_op) - - if op_result.modified_count > 0: - result = True - - except Exception as e: - log.logger.error(e) - finally: - return result - -@inject -async def change_status_conversation(status: bool, email: str, email_friend: str, db = db_dependency, log = logger) -> bool: - try: - result = False - user_db = await db.database[users_contacts_collection].find_one({'email': email}) - - if user_db != None: - query_filter = { - "email": email, - "contacts.email": email_friend - } - update_op = {"$set": {"contacts.$[elem].has_conversation": status }} - nested_filter = [{ "elem.email": email_friend }] - op_result = await db.database[users_contacts_collection].update_one(query_filter, update_op, array_filters= nested_filter) - - if op_result.modified_count > 0: - result = True - - except Exception as e: - log.logger.error(e) - finally: - return result - -@inject -async def remove_friend(email_user: str, email_friend: str, db = db_dependency, log = logger) -> bool: - try: - result = False - query_filter = { "email": email_user } - update_op = {"$pull": { "contacts": { "email": email_friend } }} - operation_result = await db.database[users_contacts_collection].update_one(query_filter, update_op) - - if operation_result.modified_count > 0: - result = True - - except Exception as e: - log.logger.error(e) - finally: - return result - -@inject -async def save_message(msg: Message, db = db_dependency, log = logger): - try: - op_result = await db.database[users_messages_collection].insert_one(msg.model_dump()) - result = False - if op_result.inserted_id != None: - result = True - except Exception as e: - log.logger.error(e) - finally: - return result - -@inject -async def generate_keys(email: str, db = db_dependency, log = logger) -> bool: - try: - result = False - user_db = await db.database[users_messages_collection].find_one({'email': email}) - - if user_db != None: - query_filter = {"email": email} - update_op = {"$set" : {"disabled" : False }} - op_result = await db.database[users_messages_collection].update_one(query_filter, update_op) - - if op_result.modified_count > 0: - result = True - - except Exception as e: - log.logger.error(e) - finally: - return result