163 lines
6.0 KiB
Python
163 lines
6.0 KiB
Python
from datetime import timedelta
|
|
from typing import Optional
|
|
|
|
from fastapi import FastAPI, APIRouter, Depends, Security
|
|
from fastapi_jwt import JwtAuthorizationCredentials, JwtAccessBearerCookie, JwtRefreshBearerCookie
|
|
from sqlalchemy import select
|
|
from starlette.background import BackgroundTasks
|
|
from starlette.middleware.cors import CORSMiddleware
|
|
from starlette.responses import RedirectResponse, Response
|
|
from starlette.staticfiles import StaticFiles
|
|
from strawberry.fastapi import GraphQLRouter
|
|
from config import APP_SECRET_KEY, GRAPHIQL, APP_DEBUG, ALLOW_CORS_ORIGINS
|
|
from database import models, async_session
|
|
from endpoints.login import LoginEndpoint, LoginInput, RefreshEndpoint, LogoutEndpoint
|
|
from endpoints.photo_editor_preview import PhotoEditorEndpoint
|
|
from endpoints.registration import RegistrationInput, RegistrationEndpoint
|
|
from graphql_schema.schema import schema, GraphQLContext
|
|
|
|
|
|
class App:
|
|
api_router = APIRouter(dependencies=[])
|
|
access_security = JwtAccessBearerCookie(
|
|
secret_key=APP_SECRET_KEY,
|
|
auto_error=False,
|
|
access_expires_delta=timedelta(minutes=20),
|
|
)
|
|
refresh_security = JwtRefreshBearerCookie(
|
|
secret_key=APP_SECRET_KEY,
|
|
auto_error=True,
|
|
refresh_expires_delta=timedelta(days=30),
|
|
)
|
|
|
|
def create_app(self):
|
|
app = FastAPI()
|
|
|
|
self.setup_exception_handlers(app)
|
|
self.setup_middleware(app)
|
|
self.setup_static_paths(app)
|
|
self.setup_routes(app)
|
|
|
|
return app
|
|
|
|
@staticmethod
|
|
def setup_exception_handlers(app: FastAPI):
|
|
pass
|
|
|
|
@staticmethod
|
|
def setup_middleware(app: FastAPI):
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=ALLOW_CORS_ORIGINS,
|
|
allow_credentials=True,
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
@staticmethod
|
|
def setup_static_paths(app: FastAPI):
|
|
app.mount("/uploads", StaticFiles(directory="/app/uploads"), name="uploads")
|
|
app.mount("/static", StaticFiles(directory="/app/static"), name="static")
|
|
|
|
def setup_graphql_endpoint(self, app: FastAPI):
|
|
async def setup_graphql_context(credentials: JwtAuthorizationCredentials = Security(self.access_security)):
|
|
user_id = credentials['id'] if credentials else None
|
|
organization_ids = set()
|
|
|
|
if user_id:
|
|
async with async_session() as db:
|
|
organization_ids = set((await db.scalars(
|
|
select(models.user_is_in_organization.c.organization_id)
|
|
.filter(models.user_is_in_organization.c.user_id == user_id)
|
|
)).all())
|
|
|
|
return GraphQLContext(
|
|
user_id=user_id,
|
|
organization_ids=organization_ids,
|
|
jwt_auth_credentials=credentials,
|
|
jwt=self.access_security,
|
|
background_tasks=Depends(BackgroundTasks)
|
|
)
|
|
|
|
graphql_app = GraphQLRouter(
|
|
schema,
|
|
graphiql=GRAPHIQL,
|
|
debug=APP_DEBUG,
|
|
context_getter=setup_graphql_context
|
|
)
|
|
app.include_router(graphql_app, prefix="/graphql")
|
|
|
|
def setup_routes(self, app: FastAPI):
|
|
self.setup_graphql_endpoint(app)
|
|
|
|
if APP_DEBUG:
|
|
@self.api_router.get("/graphql/autologin")
|
|
async def autologin():
|
|
access_token = self.access_security.create_access_token(subject={"id": 6, "name": "Franta Vomacka"})
|
|
|
|
response = RedirectResponse(url="/graphql")
|
|
self.access_security.set_access_cookie(response, access_token, expires_delta=timedelta(days=14))
|
|
|
|
return response
|
|
|
|
@self.api_router.post("/refresh")
|
|
async def refresh(
|
|
resp: Response,
|
|
credentials: JwtAuthorizationCredentials = Security(self.refresh_security)
|
|
):
|
|
return await RefreshEndpoint(
|
|
access_token=self.access_security,
|
|
refresh_token=self.refresh_security
|
|
).on_post(resp, credentials)
|
|
|
|
@self.api_router.post("/login")
|
|
async def login(resp: Response, user: LoginInput):
|
|
return await LoginEndpoint(
|
|
access_token=self.access_security,
|
|
refresh_token=self.refresh_security
|
|
).on_post(user, resp)
|
|
|
|
@self.api_router.post("/logout")
|
|
async def logout(resp: Response):
|
|
return await LogoutEndpoint(
|
|
access_token=self.access_security,
|
|
refresh_token=self.refresh_security
|
|
).on_post(resp)
|
|
|
|
@self.api_router.get("/photo/editor-preview/{photo_id}")
|
|
async def photo_editor_preview(
|
|
photo_id: int,
|
|
brightness: Optional[float] = None,
|
|
contrast: Optional[float] = None,
|
|
saturation: Optional[float] = None,
|
|
sharpness: Optional[float] = None,
|
|
rotate: Optional[float] = None,
|
|
crop_left: Optional[float] = None,
|
|
crop_top: Optional[float] = None,
|
|
crop_width: Optional[float] = None,
|
|
crop_height: Optional[float] = None,
|
|
):
|
|
return await PhotoEditorEndpoint(
|
|
access_token=self.access_security,
|
|
refresh_token=self.refresh_security
|
|
).show_preview(
|
|
photo_id=photo_id,
|
|
logged_user_id=0,
|
|
saturation=saturation,
|
|
brightness=brightness,
|
|
contrast=contrast,
|
|
sharpness=sharpness,
|
|
crop_top=crop_top,
|
|
crop_left=crop_left,
|
|
crop_height=crop_height,
|
|
crop_width=crop_width,
|
|
rotate=rotate,
|
|
)
|
|
|
|
@self.api_router.post("/registration", status_code=201)
|
|
async def registration(user: RegistrationInput):
|
|
return await RegistrationEndpoint().on_post(user)
|
|
|
|
# musi byt na konci
|
|
app.include_router(self.api_router)
|