2024-06-09 02:53:56 +00:00
|
|
|
import typing as t
|
|
|
|
|
2020-12-27 16:38:18 +00:00
|
|
|
from django.conf import settings
|
|
|
|
|
|
|
|
# Not at the top of the file because we first need to setup django
|
2024-06-09 00:41:01 +00:00
|
|
|
from fastapi import FastAPI, Request, status
|
|
|
|
from fastapi.exceptions import RequestValidationError
|
2020-12-28 08:57:40 +00:00
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
|
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
2022-03-20 12:21:09 +00:00
|
|
|
from fastapi.staticfiles import StaticFiles
|
2020-12-23 21:29:08 +00:00
|
|
|
|
2020-12-27 13:45:29 +00:00
|
|
|
from .exceptions import CustomHttpException
|
2020-12-23 21:29:08 +00:00
|
|
|
from .msgpack import MsgpackResponse
|
2020-12-29 13:42:41 +00:00
|
|
|
from .routers.authentication import authentication_router
|
|
|
|
from .routers.collection import collection_router, item_router
|
|
|
|
from .routers.invitation import invitation_incoming_router, invitation_outgoing_router
|
2024-06-08 21:51:44 +00:00
|
|
|
from .routers.member import member_router
|
2021-01-04 08:02:47 +00:00
|
|
|
from .routers.websocket import websocket_router
|
2020-12-23 21:29:08 +00:00
|
|
|
|
2020-12-28 15:09:20 +00:00
|
|
|
|
2020-12-29 08:12:36 +00:00
|
|
|
def create_application(prefix="", middlewares=[]):
|
2020-12-29 07:46:20 +00:00
|
|
|
app = FastAPI(
|
|
|
|
title="Etebase",
|
|
|
|
description="The Etebase server API documentation",
|
|
|
|
externalDocs={
|
|
|
|
"url": "https://docs.etebase.com",
|
|
|
|
"description": "Docs about the API specifications and clients.",
|
2024-06-08 21:51:44 +00:00
|
|
|
},
|
2020-12-29 07:46:20 +00:00
|
|
|
# FIXME: version="2.5.0",
|
|
|
|
)
|
2024-06-08 21:56:36 +00:00
|
|
|
VERSION = "v1" # noqa: N806
|
|
|
|
BASE_PATH = f"{prefix}/api/{VERSION}" # noqa: N806
|
|
|
|
COLLECTION_UID_MARKER = "{collection_uid}" # noqa: N806
|
2020-12-28 12:47:41 +00:00
|
|
|
app.include_router(authentication_router, prefix=f"{BASE_PATH}/authentication", tags=["authentication"])
|
|
|
|
app.include_router(collection_router, prefix=f"{BASE_PATH}/collection", tags=["collection"])
|
|
|
|
app.include_router(item_router, prefix=f"{BASE_PATH}/collection/{COLLECTION_UID_MARKER}", tags=["item"])
|
|
|
|
app.include_router(member_router, prefix=f"{BASE_PATH}/collection/{COLLECTION_UID_MARKER}", tags=["member"])
|
2020-12-28 15:09:20 +00:00
|
|
|
app.include_router(
|
|
|
|
invitation_incoming_router, prefix=f"{BASE_PATH}/invitation/incoming", tags=["incoming invitation"]
|
|
|
|
)
|
|
|
|
app.include_router(
|
|
|
|
invitation_outgoing_router, prefix=f"{BASE_PATH}/invitation/outgoing", tags=["outgoing invitation"]
|
|
|
|
)
|
2021-01-04 08:02:47 +00:00
|
|
|
app.include_router(websocket_router, prefix=f"{BASE_PATH}/ws", tags=["websocket"])
|
2020-12-28 12:47:41 +00:00
|
|
|
|
|
|
|
if settings.DEBUG:
|
2022-05-08 12:54:25 +00:00
|
|
|
from .routers.test_reset_view import test_reset_view_router
|
2020-12-28 12:47:41 +00:00
|
|
|
|
|
|
|
app.include_router(test_reset_view_router, prefix=f"{BASE_PATH}/test/authentication")
|
|
|
|
|
|
|
|
app.add_middleware(
|
2020-12-28 15:09:20 +00:00
|
|
|
CORSMiddleware,
|
|
|
|
allow_origin_regex="https?://.*",
|
|
|
|
allow_credentials=True,
|
|
|
|
allow_methods=["*"],
|
|
|
|
allow_headers=["*"],
|
2020-12-28 12:47:41 +00:00
|
|
|
)
|
|
|
|
app.add_middleware(TrustedHostMiddleware, allowed_hosts=settings.ALLOWED_HOSTS)
|
|
|
|
|
2020-12-29 08:12:36 +00:00
|
|
|
for middleware in middlewares:
|
|
|
|
app.add_middleware(middleware)
|
|
|
|
|
2021-01-04 08:02:47 +00:00
|
|
|
@app.on_event("startup")
|
|
|
|
async def on_startup() -> None:
|
|
|
|
from .redis import redisw
|
|
|
|
|
|
|
|
await redisw.setup()
|
|
|
|
|
|
|
|
@app.on_event("shutdown")
|
|
|
|
async def on_shutdown():
|
|
|
|
from .redis import redisw
|
|
|
|
|
|
|
|
await redisw.close()
|
|
|
|
|
2020-12-28 12:47:41 +00:00
|
|
|
@app.exception_handler(CustomHttpException)
|
|
|
|
async def custom_exception_handler(request: Request, exc: CustomHttpException):
|
|
|
|
return MsgpackResponse(status_code=exc.status_code, content=exc.as_dict)
|
2020-12-28 15:09:20 +00:00
|
|
|
|
2024-06-09 00:41:01 +00:00
|
|
|
@app.exception_handler(RequestValidationError)
|
|
|
|
async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
2024-06-09 02:53:56 +00:00
|
|
|
from pydantic import TypeAdapter
|
|
|
|
|
|
|
|
errors = TypeAdapter(t.Dict[str, t.Any])
|
2024-06-09 00:41:01 +00:00
|
|
|
return MsgpackResponse(
|
|
|
|
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
2024-06-09 02:53:56 +00:00
|
|
|
content=errors.dump_python({"detail": exc.errors()}),
|
2024-06-09 00:41:01 +00:00
|
|
|
)
|
|
|
|
|
2022-03-20 12:21:09 +00:00
|
|
|
app.mount(settings.STATIC_URL, StaticFiles(directory=settings.STATIC_ROOT), name="static")
|
|
|
|
|
2020-12-28 12:47:41 +00:00
|
|
|
return app
|