From 2405b00003d41cd905a6014659234ea7ab32854c Mon Sep 17 00:00:00 2001 From: andreztxt Date: Thu, 17 Apr 2025 11:36:37 -0500 Subject: [PATCH 1/5] init: Add initial adapter and manager files --- .../app/app/adapters/__init__.py | 0 ExternalToolService/app/app/adapters/ai.py | 0 .../app/app/adapters/payment.py | 0 .../app/app/adapters/storage.py | 0 ExternalToolService/app/app/main.py | 26 +++++++ ExternalToolService/app/app/manager.py | 12 +++ .../api/Documents-service/document_service.py | 14 ++++ .../Documents-service/src/models/document.py | 12 +++ .../src/models/document_schema.py | 20 +++++ .../src/routes/document_routes.py | 76 +++++++++++++++++++ 10 files changed, 160 insertions(+) create mode 100644 ExternalToolService/app/app/adapters/__init__.py create mode 100644 ExternalToolService/app/app/adapters/ai.py create mode 100644 ExternalToolService/app/app/adapters/payment.py create mode 100644 ExternalToolService/app/app/adapters/storage.py create mode 100644 ExternalToolService/app/app/main.py create mode 100644 ExternalToolService/app/app/manager.py create mode 100644 backend/api/Documents-service/document_service.py create mode 100644 backend/api/Documents-service/src/models/document.py create mode 100644 backend/api/Documents-service/src/models/document_schema.py create mode 100644 backend/api/Documents-service/src/routes/document_routes.py diff --git a/ExternalToolService/app/app/adapters/__init__.py b/ExternalToolService/app/app/adapters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ExternalToolService/app/app/adapters/ai.py b/ExternalToolService/app/app/adapters/ai.py new file mode 100644 index 0000000..e69de29 diff --git a/ExternalToolService/app/app/adapters/payment.py b/ExternalToolService/app/app/adapters/payment.py new file mode 100644 index 0000000..e69de29 diff --git a/ExternalToolService/app/app/adapters/storage.py b/ExternalToolService/app/app/adapters/storage.py new file mode 100644 index 0000000..e69de29 diff --git a/ExternalToolService/app/app/main.py b/ExternalToolService/app/app/main.py new file mode 100644 index 0000000..071ca75 --- /dev/null +++ b/ExternalToolService/app/app/main.py @@ -0,0 +1,26 @@ +from fastapi import FastAPI, Depends +from manager import ExternalToolManager +from adapters.ai import AIServiceAdapter +from adapters.payment import PaymentAdapter +from adapters.storage import CloudStorageAdapter + +app = FastAPI() +tool_manager = ExternalToolManager() + +def require_auth(): + return True + +@app.post("/analyze") +def analyze(data: dict, auth=Depends(require_auth)): + tool = AIServiceAdapter() + return tool_manager.use_tool(tool, data) + +@app.post("/pay") +def pay(data: dict, auth=Depends(require_auth)): + tool = PaymentAdapter() + return tool_manager.use_tool(tool, data) + +@app.get("/storage-url") +def get_storage_url(filename: str, auth=Depends(require_auth)): + tool = CloudStorageAdapter() + return tool_manager.use_tool(tool, {"filename": filename}) diff --git a/ExternalToolService/app/app/manager.py b/ExternalToolService/app/app/manager.py new file mode 100644 index 0000000..2355240 --- /dev/null +++ b/ExternalToolService/app/app/manager.py @@ -0,0 +1,12 @@ +from abc import ABC, abstractmethod +from typing import Any + +class ExternalTool(ABC): + @abstractmethod + def execute(self, data: Any) -> Any: + pass + + +class ExternalToolManager: + def use_tool(self, tool: ExternalTool, data: Any) -> Any: + return tool.execute(data) diff --git a/backend/api/Documents-service/document_service.py b/backend/api/Documents-service/document_service.py new file mode 100644 index 0000000..e0511e1 --- /dev/null +++ b/backend/api/Documents-service/document_service.py @@ -0,0 +1,14 @@ +from fastapi import FastAPI +from src.routes.document_routes import router as document_router +from database import Base, engine + +# Crear tablas +Base.metadata.create_all(bind=engine) + +app = FastAPI() + +app.include_router( + document_router, + prefix="/api/documents", + tags=["Documents"], +) \ No newline at end of file diff --git a/backend/api/Documents-service/src/models/document.py b/backend/api/Documents-service/src/models/document.py new file mode 100644 index 0000000..e5f45b3 --- /dev/null +++ b/backend/api/Documents-service/src/models/document.py @@ -0,0 +1,12 @@ +import sys +import os +from sqlalchemy import Column, Integer, String +from database import Base + +class Document(Base): + __tablename__ = "documents" + + id = Column(Integer, primary_key=True, index=True) + title = Column(String, index=True) + content = Column(String) + author = Column(String, nullable=True) diff --git a/backend/api/Documents-service/src/models/document_schema.py b/backend/api/Documents-service/src/models/document_schema.py new file mode 100644 index 0000000..6a97710 --- /dev/null +++ b/backend/api/Documents-service/src/models/document_schema.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel +from typing import Optional + +class DocumentBase(BaseModel): + title: str + content: str + author: Optional[str] = None + + + +class DocumentCreate(DocumentBase): + pass + + +class Document(DocumentBase): + id: int + + class Config: + orm_mode = True + diff --git a/backend/api/Documents-service/src/routes/document_routes.py b/backend/api/Documents-service/src/routes/document_routes.py new file mode 100644 index 0000000..0297369 --- /dev/null +++ b/backend/api/Documents-service/src/routes/document_routes.py @@ -0,0 +1,76 @@ +import os +import shutil +import requests +from fastapi import APIRouter, UploadFile, File, Depends, HTTPException, Form +from sqlalchemy.orm import Session +from datetime import datetime +from database import SessionLocal +from src.models.document import Document as DocumentModel +from src.models.document_schema import Document + +router = APIRouter() +UPLOAD_DIR = "uploads" + +if not os.path.exists(UPLOAD_DIR): + os.makedirs(UPLOAD_DIR) + + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + +def notify(action: str, doc_id: int): + try: + requests.post("http://notification-service/notify", json={ + "action": action, + "document_id": doc_id + }) + except: + print(f"No se pudo notificar la acción {action} del documento {doc_id}") + +@router.post("/", response_model=Document) +def subir_documento( + nombre: str = Form(...), + proyecto_id: int = Form(...), + archivo: UploadFile = File(...), + db: Session = Depends(get_db) +): + filename = f"{datetime.utcnow().timestamp()}_{archivo.filename}" + path = os.path.join(UPLOAD_DIR, filename) + + with open(path, "wb") as buffer: + shutil.copyfileobj(archivo.file, buffer) + + db_doc = DocumentModel( + nombre=nombre, + proyecto_id=proyecto_id, + archivo=path + ) + db.add(db_doc) + db.commit() + db.refresh(db_doc) + + notify("subido", db_doc.id) + return db_doc + +@router.get("/", response_model=list[Document]) +def listar_documentos(db: Session = Depends(get_db)): + return db.query(DocumentModel).all() + +@router.delete("/{doc_id}") +def eliminar_documento(doc_id: int, db: Session = Depends(get_db)): + doc = db.query(DocumentModel).filter(DocumentModel.id == doc_id).first() + if not doc: + raise HTTPException(status_code=404, detail="Documento no encontrado") + + if os.path.exists(doc.archivo): + os.remove(doc.archivo) + + db.delete(doc) + db.commit() + + notify("eliminado", doc_id) + return {"msg": "Documento eliminado"} From 0ca955444b97bfba88d82564141dea576409de05 Mon Sep 17 00:00:00 2001 From: andreztxt Date: Thu, 17 Apr 2025 11:39:03 -0500 Subject: [PATCH 2/5] style: Clean up code formatting by adding whitespace for improved readability --- ExternalToolService/app/app/main.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ExternalToolService/app/app/main.py b/ExternalToolService/app/app/main.py index 071ca75..25d3208 100644 --- a/ExternalToolService/app/app/main.py +++ b/ExternalToolService/app/app/main.py @@ -4,22 +4,29 @@ from adapters.payment import PaymentAdapter from adapters.storage import CloudStorageAdapter + + app = FastAPI() tool_manager = ExternalToolManager() + + def require_auth(): return True + @app.post("/analyze") def analyze(data: dict, auth=Depends(require_auth)): tool = AIServiceAdapter() return tool_manager.use_tool(tool, data) + @app.post("/pay") def pay(data: dict, auth=Depends(require_auth)): tool = PaymentAdapter() return tool_manager.use_tool(tool, data) + @app.get("/storage-url") def get_storage_url(filename: str, auth=Depends(require_auth)): tool = CloudStorageAdapter() From 3c6f5e19376da56651957bea98a62bf05277b2c0 Mon Sep 17 00:00:00 2001 From: andreztxt Date: Fri, 18 Apr 2025 23:24:35 -0500 Subject: [PATCH 3/5] init: Reintroduce ExternalTool and ExternalToolManager classes in manager.py --- ExternalToolService/app/app/adapters/ai.py | 8 ++++++ .../app/app/{ => adapters}/manager.py | 5 ++-- .../app/app/adapters/payment.py | 8 ++++++ .../app/app/adapters/storage.py | 8 ++++++ ExternalToolService/app/app/main.py | 28 +++++++++++-------- 5 files changed, 43 insertions(+), 14 deletions(-) rename ExternalToolService/app/app/{ => adapters}/manager.py (63%) diff --git a/ExternalToolService/app/app/adapters/ai.py b/ExternalToolService/app/app/adapters/ai.py index e69de29..01c832f 100644 --- a/ExternalToolService/app/app/adapters/ai.py +++ b/ExternalToolService/app/app/adapters/ai.py @@ -0,0 +1,8 @@ +from .manager import ExternalTool + + +class AIServiceAdapter(ExternalTool): + def execute(self, data): + # Lógica de IA simulada + content = data.get("content", "") + return {"summary": content[:100], "sentiment": "positive"} diff --git a/ExternalToolService/app/app/manager.py b/ExternalToolService/app/app/adapters/manager.py similarity index 63% rename from ExternalToolService/app/app/manager.py rename to ExternalToolService/app/app/adapters/manager.py index 2355240..da951f4 100644 --- a/ExternalToolService/app/app/manager.py +++ b/ExternalToolService/app/app/adapters/manager.py @@ -1,12 +1,13 @@ from abc import ABC, abstractmethod from typing import Any + class ExternalTool(ABC): @abstractmethod - def execute(self, data: Any) -> Any: + def execute(self, data: Any) -> dict: pass class ExternalToolManager: - def use_tool(self, tool: ExternalTool, data: Any) -> Any: + def use_tool(self, tool: ExternalTool, data: Any) -> dict: return tool.execute(data) diff --git a/ExternalToolService/app/app/adapters/payment.py b/ExternalToolService/app/app/adapters/payment.py index e69de29..26548e7 100644 --- a/ExternalToolService/app/app/adapters/payment.py +++ b/ExternalToolService/app/app/adapters/payment.py @@ -0,0 +1,8 @@ +from .manager import ExternalTool + + +class PaymentAdapter(ExternalTool): + def execute(self, data): + # Logica simulada de procesamiento de pago + amount = data.get("amount", 0) + return {"status": "success", "charged": amount} diff --git a/ExternalToolService/app/app/adapters/storage.py b/ExternalToolService/app/app/adapters/storage.py index e69de29..a17ad38 100644 --- a/ExternalToolService/app/app/adapters/storage.py +++ b/ExternalToolService/app/app/adapters/storage.py @@ -0,0 +1,8 @@ +from .manager import ExternalTool + + +class CloudStorageAdapter(ExternalTool): + def execute(self, data): + # Logica simulada de URL de almacenamiento + filename = data.get("filename", "file.txt") + return {"url": f"https://storage.example.com/{filename}"} diff --git a/ExternalToolService/app/app/main.py b/ExternalToolService/app/app/main.py index 25d3208..3917800 100644 --- a/ExternalToolService/app/app/main.py +++ b/ExternalToolService/app/app/main.py @@ -1,33 +1,37 @@ from fastapi import FastAPI, Depends -from manager import ExternalToolManager from adapters.ai import AIServiceAdapter from adapters.payment import PaymentAdapter from adapters.storage import CloudStorageAdapter - +from adapters.manager import ExternalToolManager +from fastapi.security import HTTPBasic, HTTPBasicCredentials app = FastAPI() -tool_manager = ExternalToolManager() - +security = HTTPBasic() -def require_auth(): - return True +def require_auth(credentials: HTTPBasicCredentials = Depends(security)): + # Aquí podés poner lógica real de autenticación + if credentials.username != "admin" or credentials.password != "123": + raise Exception("Unauthorized") @app.post("/analyze") -def analyze(data: dict, auth=Depends(require_auth)): +def analyze(data: dict, _=Depends(require_auth)): tool = AIServiceAdapter() - return tool_manager.use_tool(tool, data) + manager = ExternalToolManager() + return manager.use_tool(tool, data) @app.post("/pay") -def pay(data: dict, auth=Depends(require_auth)): +def pay(data: dict, _=Depends(require_auth)): tool = PaymentAdapter() - return tool_manager.use_tool(tool, data) + manager = ExternalToolManager() + return manager.use_tool(tool, data) @app.get("/storage-url") -def get_storage_url(filename: str, auth=Depends(require_auth)): +def get_storage_url(filename: str, _=Depends(require_auth)): tool = CloudStorageAdapter() - return tool_manager.use_tool(tool, {"filename": filename}) + manager = ExternalToolManager() + return manager.use_tool(tool, {"filename": filename}) From cc8b033f62f49155698e25cdf10b9c1eb3d51519 Mon Sep 17 00:00:00 2001 From: andreztxt Date: Sun, 20 Apr 2025 15:39:27 -0500 Subject: [PATCH 4/5] refactor: require_auth function --- ExternalToolService/app/app/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ExternalToolService/app/app/main.py b/ExternalToolService/app/app/main.py index 3917800..7dbd8d0 100644 --- a/ExternalToolService/app/app/main.py +++ b/ExternalToolService/app/app/main.py @@ -11,7 +11,6 @@ def require_auth(credentials: HTTPBasicCredentials = Depends(security)): - # Aquí podés poner lógica real de autenticación if credentials.username != "admin" or credentials.password != "123": raise Exception("Unauthorized") From 822ce3c003f40e8e96d0c37ca543f3547ac03c19 Mon Sep 17 00:00:00 2001 From: Oyhs-co Date: Mon, 21 Apr 2025 08:13:20 -0500 Subject: [PATCH 5/5] refactor(ExternalTools-service): move initial implementation of adapters and main service for ExternalTools to correct directory - se movio toda la logica del microservicio a su directorio correspondiente --- .../api/ExternalTools-service}/adapters/__init__.py | 0 .../app => backend/api/ExternalTools-service}/adapters/ai.py | 0 .../api/ExternalTools-service}/adapters/manager.py | 0 .../api/ExternalTools-service}/adapters/payment.py | 0 .../api/ExternalTools-service}/adapters/storage.py | 0 .../app/app => backend/api/ExternalTools-service}/main.py | 4 ++-- 6 files changed, 2 insertions(+), 2 deletions(-) rename {ExternalToolService/app/app => backend/api/ExternalTools-service}/adapters/__init__.py (100%) rename {ExternalToolService/app/app => backend/api/ExternalTools-service}/adapters/ai.py (100%) rename {ExternalToolService/app/app => backend/api/ExternalTools-service}/adapters/manager.py (100%) rename {ExternalToolService/app/app => backend/api/ExternalTools-service}/adapters/payment.py (100%) rename {ExternalToolService/app/app => backend/api/ExternalTools-service}/adapters/storage.py (100%) rename {ExternalToolService/app/app => backend/api/ExternalTools-service}/main.py (89%) diff --git a/ExternalToolService/app/app/adapters/__init__.py b/backend/api/ExternalTools-service/adapters/__init__.py similarity index 100% rename from ExternalToolService/app/app/adapters/__init__.py rename to backend/api/ExternalTools-service/adapters/__init__.py diff --git a/ExternalToolService/app/app/adapters/ai.py b/backend/api/ExternalTools-service/adapters/ai.py similarity index 100% rename from ExternalToolService/app/app/adapters/ai.py rename to backend/api/ExternalTools-service/adapters/ai.py diff --git a/ExternalToolService/app/app/adapters/manager.py b/backend/api/ExternalTools-service/adapters/manager.py similarity index 100% rename from ExternalToolService/app/app/adapters/manager.py rename to backend/api/ExternalTools-service/adapters/manager.py diff --git a/ExternalToolService/app/app/adapters/payment.py b/backend/api/ExternalTools-service/adapters/payment.py similarity index 100% rename from ExternalToolService/app/app/adapters/payment.py rename to backend/api/ExternalTools-service/adapters/payment.py diff --git a/ExternalToolService/app/app/adapters/storage.py b/backend/api/ExternalTools-service/adapters/storage.py similarity index 100% rename from ExternalToolService/app/app/adapters/storage.py rename to backend/api/ExternalTools-service/adapters/storage.py diff --git a/ExternalToolService/app/app/main.py b/backend/api/ExternalTools-service/main.py similarity index 89% rename from ExternalToolService/app/app/main.py rename to backend/api/ExternalTools-service/main.py index 7dbd8d0..549ab37 100644 --- a/ExternalToolService/app/app/main.py +++ b/backend/api/ExternalTools-service/main.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI, Depends +from fastapi import FastAPI, Depends, HTTPException from adapters.ai import AIServiceAdapter from adapters.payment import PaymentAdapter from adapters.storage import CloudStorageAdapter @@ -12,7 +12,7 @@ def require_auth(credentials: HTTPBasicCredentials = Depends(security)): if credentials.username != "admin" or credentials.password != "123": - raise Exception("Unauthorized") + raise HTTPException(status_code=401, detail="Unauthorized") @app.post("/analyze")