attachment
Gitea Actions Demo / build_and_push (push) Successful in 27m21s
Details
Gitea Actions Demo / build_and_push (push) Successful in 27m21s
Details
This commit is contained in:
parent
9dfdb6ec29
commit
ee7739b875
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import flask_login
|
import flask_login
|
||||||
from flask import Response, redirect, render_template, request, url_for
|
from flask import Response, redirect, render_template, request, url_for
|
||||||
from flask_admin import Admin, AdminIndexView, expose
|
from flask_admin import Admin, AdminIndexView, expose
|
||||||
|
|
@ -40,14 +39,14 @@ async def get_file(raw_path: str):
|
||||||
cache_ctrl = "public, max-age=864000" # 10 дней
|
cache_ctrl = "public, max-age=864000" # 10 дней
|
||||||
last_mod = attach[0].created_at.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
last_mod = attach[0].created_at.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
body,
|
body,
|
||||||
mimetype=attach[0].content_type,
|
mimetype=attach[0].content_type,
|
||||||
headers={
|
headers={
|
||||||
"Cache-Control": cache_ctrl,
|
"Cache-Control": cache_ctrl,
|
||||||
"Last-Modified": last_mod,
|
"Last-Modified": last_mod,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@login_manager.user_loader
|
@login_manager.user_loader
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ app.config["SQLALCHEMY_DATABASE_URI"] = (
|
||||||
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
|
app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
|
||||||
"pool_recycle": 600,
|
"pool_recycle": 600,
|
||||||
"pool_pre_ping": True,
|
"pool_pre_ping": True,
|
||||||
"pool_size": 5,
|
"pool_size": 30,
|
||||||
}
|
}
|
||||||
app.config["SECRET_KEY"] = cnf.admin_secret_key
|
app.config["SECRET_KEY"] = cnf.admin_secret_key
|
||||||
app.config["SQLALCHEMY_ECHO"] = True
|
app.config["SQLALCHEMY_ECHO"] = True
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class AttachmentView(ModelView):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _list_thumbnail(view, _context, model, _name):
|
def _list_thumbnail(view, _context, model, _name):
|
||||||
data = ""
|
data = ""
|
||||||
data += f'<img src="/admin/attachment/{model.path}.original.jpg" width="100" />'
|
data += f'<img src="/attachments{model.path}.original.jpg" width="100" />'
|
||||||
|
|
||||||
return Markup(data)
|
return Markup(data)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class AsyncDB(AbstractDB):
|
||||||
# self.engine.execution_options(stream_results=True)
|
# self.engine.execution_options(stream_results=True)
|
||||||
if self.engine is None:
|
if self.engine is None:
|
||||||
raise ConnectError
|
raise ConnectError
|
||||||
session = asyncio.async_sessionmaker(self.engine, expire_on_commit=False)
|
session = asyncio.async_sessionmaker(self.engine, expire_on_commit=True)
|
||||||
if session is None:
|
if session is None:
|
||||||
raise ConnectError
|
raise ConnectError
|
||||||
self.async_session = session
|
self.async_session = session
|
||||||
|
|
@ -35,13 +35,10 @@ class AsyncDB(AbstractDB):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def session(self):
|
def session(self):
|
||||||
return asyncio.async_sessionmaker(self.engine, expire_on_commit=False)
|
return asyncio.async_sessionmaker(self.engine, expire_on_commit=True)
|
||||||
|
|
||||||
def new_session(self):
|
|
||||||
return asyncio.async_sessionmaker(self.engine, expire_on_commit=False)()
|
|
||||||
|
|
||||||
def session_master(self):
|
def session_master(self):
|
||||||
return self.new_session()
|
return self.async_session()
|
||||||
|
|
||||||
def session_slave(self):
|
def session_slave(self):
|
||||||
return self.new_session()
|
return self.async_session()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
|
from server.infra.web.attachments import AtachmentController
|
||||||
from server.infra.web.description import DescriptionController
|
from server.infra.web.description import DescriptionController
|
||||||
from server.infra.web.recognizer import BreedsController
|
from server.infra.web.recognizer import BreedsController
|
||||||
from server.infra.web.seo import SeoController
|
from server.infra.web.seo import SeoController
|
||||||
from server.infra.web.vote import VoteController
|
from server.infra.web.vote import VoteController
|
||||||
|
|
||||||
__all__ = ("DescriptionController", "SeoController", "BreedsController", "VoteController")
|
__all__ = ("DescriptionController", "SeoController", "BreedsController", "VoteController", "AtachmentController")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import inject
|
||||||
|
from litestar import Controller, get
|
||||||
|
from litestar.exceptions import HTTPException
|
||||||
|
from litestar.response import Response
|
||||||
|
|
||||||
|
from server.modules.attachments import AtachmentService
|
||||||
|
|
||||||
|
|
||||||
|
class AtachmentController(Controller):
|
||||||
|
|
||||||
|
@get("/attachments/{raw_path:path}", media_type="image/jpeg")
|
||||||
|
async def get_file(self, raw_path: str) -> Response:
|
||||||
|
attach_service: AtachmentService = inject.instance(AtachmentService)
|
||||||
|
|
||||||
|
attach_path = attach_service.path_from_url(raw_path)
|
||||||
|
# Query within session scope
|
||||||
|
attach = await attach_service.get_info_bypath(session=None, path=[attach_path])
|
||||||
|
if not attach:
|
||||||
|
raise HTTPException(status_code=404, detail="Attachment not found")
|
||||||
|
|
||||||
|
# Get file data (assuming async)
|
||||||
|
body = await attach_service.get_data(attach_path)
|
||||||
|
|
||||||
|
# Extract metadata within session scope
|
||||||
|
content_type = attach[0].content_type
|
||||||
|
last_mod = attach[0].created_at.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
||||||
|
|
||||||
|
return Response(
|
||||||
|
content=body,
|
||||||
|
media_type=content_type,
|
||||||
|
headers={
|
||||||
|
"Cache-Control": "public, max-age=864000",
|
||||||
|
"Last-Modified": last_mod,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
@ -12,7 +12,7 @@ from litestar.template.config import TemplateConfig
|
||||||
|
|
||||||
from server.config import get_app_config
|
from server.config import get_app_config
|
||||||
from server.infra.db import AsyncDB
|
from server.infra.db import AsyncDB
|
||||||
from server.infra.web import BreedsController, DescriptionController, SeoController, VoteController
|
from server.infra.web import AtachmentController, BreedsController, DescriptionController, SeoController, VoteController
|
||||||
from server.modules.attachments import AtachmentService, DBAttachmentRepository, S3StorageDriver
|
from server.modules.attachments import AtachmentService, DBAttachmentRepository, S3StorageDriver
|
||||||
from server.modules.descriptions import CharactersService, PGCharactersRepository
|
from server.modules.descriptions import CharactersService, PGCharactersRepository
|
||||||
from server.modules.rate import PGVoteRepository, VotesService
|
from server.modules.rate import PGVoteRepository, VotesService
|
||||||
|
|
@ -45,6 +45,7 @@ app = Litestar(
|
||||||
DescriptionController,
|
DescriptionController,
|
||||||
SeoController,
|
SeoController,
|
||||||
VoteController,
|
VoteController,
|
||||||
|
AtachmentController,
|
||||||
create_static_files_router(path="/static", directories=["server/static"]),
|
create_static_files_router(path="/static", directories=["server/static"]),
|
||||||
],
|
],
|
||||||
template_config=TemplateConfig(
|
template_config=TemplateConfig(
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ class AtachmentService:
|
||||||
if ".original" not in url:
|
if ".original" not in url:
|
||||||
raise ValueError(f"wrong url: {url}")
|
raise ValueError(f"wrong url: {url}")
|
||||||
parts = url.split(".original")[0]
|
parts = url.split(".original")[0]
|
||||||
return f"/{parts}"
|
return parts
|
||||||
|
|
||||||
def url(self, attachment_id: str, content_type: str | None = None) -> str:
|
def url(self, attachment_id: str, content_type: str | None = None) -> str:
|
||||||
return f"{self._cnf.app_public_url}/api/v0/attachment/{attachment_id}.original.{self.extension(content_type)}"
|
return f"{self._cnf.app_public_url}/api/v0/attachment/{attachment_id}.original.{self.extension(content_type)}"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue