Add API support for get_document_by_id

This commit is contained in:
jetli 2024-10-19 20:56:19 +00:00
parent c25252ceda
commit 378ae41b39
14 changed files with 154 additions and 49 deletions

5
.gitignore vendored
View File

@ -1 +1,6 @@
.venv/
*__pycache__*
.vscode
/deploy/.*
*.log
*.pyc

View File

@ -1,5 +1,5 @@
# Dockerfile for Python Service
FROM python:3.11-slim
FROM python:3.10-slim
# Set the working directory inside the container
WORKDIR /app
@ -16,4 +16,4 @@ EXPOSE 8005
# Run the application using the start script
CMD ["uvicorn", "webapi.main:app", "--reload", "--port=8003", "--host=0.0.0.0"]
CMD ["uvicorn", "app.central_storage.webapi.main:app", "--reload", "--port=8005", "--host=0.0.0.0"]

View File

@ -92,6 +92,9 @@ class AzureBlobManager:
app_settings.AZURE_STORAGE_DOCUMENT_API_ENDPOINT,
credential=app_settings.AZURE_STORAGE_DOCUMENT_API_KEY,
) as blob_service_client:
# user_delegation_key = await blob_service_client.get_user_delegation_key(
# key_start_time=key_start_time, key_expiry_time=key_expiry_time
# )
blob_client = blob_service_client.get_blob_client(
container=container_name, blob=file_name
)

View File

@ -1,3 +1,13 @@
fastapi==0.114.0
fastapi-jwt==0.2.0
pika==1.3.2
fastapi
uvicorn
pydantic==2.9.2
loguru==0.7.2
uvicorn==0.23.2
beanie==1.21.0
aio-pika
pydantic-settings
python-jose
azure-storage-blob==12.22.0
azure-identity
azure-core[aio]

View File

@ -2,12 +2,12 @@ import logging
from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from webapi.providers import common
from webapi.providers import logger
from webapi.providers import router
from webapi.providers import database
from webapi.providers import scheduler
from webapi.providers import exception_handler
from app.central_storage.webapi.providers import common
from app.central_storage.webapi.providers import logger
from app.central_storage.webapi.providers import router
from app.central_storage.webapi.providers import database
from app.central_storage.webapi.providers import scheduler
from app.central_storage.webapi.providers import exception_handler
from .freeleaps_app import FreeleapsApp
@ -49,11 +49,7 @@ def customize_openapi_security(app: FastAPI) -> None:
# Add security scheme to components
openapi_schema["components"]["securitySchemes"] = {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
"bearerAuth": {"type": "http", "scheme": "bearer", "bearerFormat": "JWT"}
}
# Add security requirement globally

View File

@ -1,15 +1,14 @@
from webapi.bootstrap.application import create_app
from webapi.config.site_settings import site_settings
from app.central_storage.webapi.bootstrap.application import create_app
from app.central_storage.webapi.config.site_settings import site_settings
from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware
from strawberry.fastapi import GraphQLRouter
from strawberry.fastapi.handlers import GraphQLTransportWSHandler, GraphQLWSHandler
import uvicorn
from typing import Any
app = create_app()
@app.get("/", status_code=301)
async def root():
"""
@ -19,12 +18,16 @@ async def root():
if __name__ == "__main__":
uvicorn.run(app="main:app", host=site_settings.SERVER_HOST, port=site_settings.SERVER_PORT)
uvicorn.run(
app="main:app", host=site_settings.SERVER_HOST, port=site_settings.SERVER_PORT
)
def get_context() -> Any:
# Define your context function. This is where you can set up authentication, database connections, etc.
return {}
def get_root_value() -> Any:
# Define your root value function. This can be used to customize the root value for GraphQL operations.
return {}
return {}

View File

@ -1,5 +1,5 @@
from fastapi.middleware.cors import CORSMiddleware
from webapi.config.site_settings import site_settings
from app.central_storage.webapi.config.site_settings import site_settings
def register(app):

View File

@ -1,11 +1,12 @@
from webapi.config.site_settings import site_settings
from infra.config.app_settings import app_settings
from beanie import init_beanie
from motor.motor_asyncio import AsyncIOMotorClient
from app.central_storage.backend.models.models import DocumentDoc
def register(app):
app.debug = site_settings.DEBUG
app.title = site_settings.NAME
app.debug = "mongo_debug"
app.title = "mongo_name"
@app.on_event("startup")
async def start_database():
@ -13,5 +14,12 @@ def register(app):
async def initiate_database():
#init your database here
pass
client = AsyncIOMotorClient(
app_settings.MONGODB_URI,
serverSelectionTimeoutMS=60000,
minPoolSize=5, # Minimum number of connections in the pool
maxPoolSize=20, # Maximum number of connections in the pool
)
await init_beanie(
database=client[app_settings.MONGODB_NAME], document_models=[DocumentDoc]
)

View File

@ -1,7 +1,7 @@
import logging
import sys
from loguru import logger
from common.config.log_settings import log_settings
from app.central_storage.common.config.log_settings import log_settings
def register(app=None):
@ -21,15 +21,8 @@ def register(app=None):
logging.getLogger(name).propagate = True
# configure loguru
logger.add(
sink=sys.stdout
)
logger.add(
sink=file_path,
level=level,
retention=retention,
rotation=rotation
)
logger.add(sink=sys.stdout)
logger.add(sink=file_path, level=level, retention=retention, rotation=rotation)
logger.disable("pika.adapters")
logger.disable("pika.connection")

View File

@ -1,4 +1,4 @@
from webapi.routes import api_router
from app.central_storage.webapi.routes import api_router
from starlette import routing

View File

@ -1,5 +1,7 @@
from fastapi import APIRouter
from .get_document_by_id import router as doc_router
api_router = APIRouter()
api_router.include_router(doc_router, tags=["attachment"])
websocket_router = APIRouter()

View File

@ -1,11 +1,11 @@
from fastapi import APIRouter, Security, HTTPException
from fastapi import APIRouter, HTTPException, Request
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from fastapi_jwt import JwtAuthorizationCredentials
from backend.infra.authentication.auth import access_security
from infra.token.token_manager import TokenManager
from app.central_storage.backend.application.document_app import DocumentHub
router = APIRouter()
token_manager = TokenManager()
# Web API
@ -19,9 +19,32 @@ router = APIRouter()
)
async def get_document_by_id(
document_id: str,
credentials: JwtAuthorizationCredentials = Security(access_security),
request: Request,
):
user_id = credentials["id"]
# Extract the Authorization header
auth_header = request.headers.get("Authorization")
if not auth_header:
raise HTTPException(status_code=401, detail="Authorization header missing")
# Ensure the header starts with 'Bearer'
if not auth_header.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid authorization header")
token = auth_header.split(" ")[1]
try:
# Decode the token using the TokenManager
credentials = token_manager.decode_token(token)
except Exception as e:
raise HTTPException(
status_code=401, detail=f"Invalid or expired token: {str(e)}"
)
# Get the user_id from the decoded token
user_id = credentials.get("id")
if not user_id:
raise HTTPException(status_code=401, detail="Invalid token payload")
# Fetch the document using DocumentHub
document = await DocumentHub(user_id).get_document_by_id(document_id)

View File

@ -1,15 +1,18 @@
import os
from pydantic_settings import BaseSettings
class AppSettings():
NAME: str = "myapp"
class AppSettings(BaseSettings):
JWT_SECRET_KEY: str = ""
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
REFRESH_TOKEN_EXPIRE_DAYS: int = 30
MONGODB_NAME: str = "freeleaps2"
MONGODB_URI: str = (
"mongodb+srv://freeadmin:0eMV0bt8oyaknA0m@freeleaps2.zmsmpos.mongodb.net/?retryWrites=true&w=majority"
)
class Config:
env_file = ".myapp.env"
env_file_encoding = "utf-8"
APPLICATION_ACTIVITY_LOG: str = "myapp-application-activity"
USER_ACTIVITY_LOG: str = "myapp-user-activity"
BUSINESS_METRIC_LOG: str = "myapp-business-metrics"
app_settings = AppSettings()

View File

@ -0,0 +1,59 @@
# application/auth/token/token_manager.py
from datetime import datetime, timedelta, timezone
from typing import Dict
from jose import jwt
from infra.config.app_settings import app_settings
class TokenManager:
def __init__(self):
self.secret_key = app_settings.JWT_SECRET_KEY
self.algorithm = "HS256"
self.access_token_expire_minutes = app_settings.ACCESS_TOKEN_EXPIRE_MINUTES
self.refresh_token_expire_days = app_settings.REFRESH_TOKEN_EXPIRE_DAYS
def create_access_token(self, subject: Dict[str, str]) -> str:
"""
Generates an access token with a short expiration time.
Args:
subject (Dict[str, str]): A dictionary containing user information like 'id' and 'role'.
Returns:
str: Encoded JWT access token.
"""
expire = datetime.now(timezone.utc) + timedelta(
minutes=self.access_token_expire_minutes
)
to_encode = subject.copy()
to_encode.update({"exp": expire})
return jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
def create_refresh_token(self, subject: Dict[str, str]) -> str:
"""
Generates a refresh token with a longer expiration time.
Args:
subject (Dict[str, str]): A dictionary containing user information like 'id' and 'role'.
Returns:
str: Encoded JWT refresh token.
"""
expire = datetime.now(timezone.utc) + timedelta(
days=self.refresh_token_expire_days
)
to_encode = subject.copy()
to_encode.update({"exp": expire})
return jwt.encode(to_encode, self.secret_key, algorithm=self.algorithm)
def decode_token(self, token: str) -> Dict:
"""
Decodes a JWT token and returns the payload.
Args:
token (str): Encoded JWT token.
Returns:
Dict: Decoded token payload.
Raises:
JWTError: If the token is invalid or expired.
"""
return jwt.decode(token, self.secret_key, algorithms=[self.algorithm])