Add thumbnail endpoint (#2468)
- Add /thumbnail collections endpoint to serve the thumbnail as an image for public collections. - Also fix uploading thumbnail images to use correct mime, if available.
This commit is contained in:
parent
13bf818914
commit
6c192df49d
@ -11,6 +11,7 @@ import os
|
||||
|
||||
import asyncio
|
||||
import pymongo
|
||||
import aiohttp
|
||||
from pymongo.collation import Collation
|
||||
from fastapi import Depends, HTTPException, Response
|
||||
from fastapi.responses import StreamingResponse
|
||||
@ -407,6 +408,34 @@ class CollectionOps:
|
||||
|
||||
return PublicCollOut.from_dict(result)
|
||||
|
||||
async def get_public_thumbnail(
|
||||
self, slug: str, org: Organization
|
||||
) -> StreamingResponse:
|
||||
"""return thumbnail of public collection, if any"""
|
||||
result = await self.get_collection_raw_by_slug(
|
||||
slug, public_or_unlisted_only=True
|
||||
)
|
||||
|
||||
thumbnail = result.get("thumbnail")
|
||||
if not thumbnail:
|
||||
raise HTTPException(status_code=404, detail="thumbnail_not_found")
|
||||
|
||||
image_file = ImageFile(**thumbnail)
|
||||
image_file_out = await image_file.get_public_image_file_out(
|
||||
org, self.storage_ops
|
||||
)
|
||||
|
||||
path = self.storage_ops.resolve_internal_access_path(image_file_out.path)
|
||||
|
||||
async def reader():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(path) as resp:
|
||||
async for chunk in resp.content.iter_chunked(4096):
|
||||
yield chunk
|
||||
|
||||
headers = {"Cache-Control": "max-age=3600, stale-while-revalidate=86400"}
|
||||
return StreamingResponse(reader(), media_type=image_file.mime, headers=headers)
|
||||
|
||||
async def list_collections(
|
||||
self,
|
||||
org: Organization,
|
||||
@ -852,6 +881,7 @@ class CollectionOps:
|
||||
file_prep.upload_name,
|
||||
stream_iter(),
|
||||
MIN_UPLOAD_PART_SIZE,
|
||||
mime=file_prep.mime,
|
||||
):
|
||||
print("Collection thumbnail stream upload failed", flush=True)
|
||||
raise HTTPException(status_code=400, detail="upload_failed")
|
||||
@ -1175,6 +1205,24 @@ def init_collections_api(
|
||||
|
||||
return await colls.download_collection(coll.id, org)
|
||||
|
||||
@app.get(
|
||||
"/public/orgs/{org_slug}/collections/{coll_slug}/thumbnail",
|
||||
tags=["collections", "public"],
|
||||
response_class=StreamingResponse,
|
||||
)
|
||||
async def get_public_thumbnail(
|
||||
org_slug: str,
|
||||
coll_slug: str,
|
||||
):
|
||||
try:
|
||||
org = await colls.orgs.get_org_by_slug(org_slug)
|
||||
# pylint: disable=broad-exception-caught
|
||||
except Exception:
|
||||
# pylint: disable=raise-missing-from
|
||||
raise HTTPException(status_code=404, detail="collection_not_found")
|
||||
|
||||
return await colls.get_public_thumbnail(coll_slug, org)
|
||||
|
||||
@app.post(
|
||||
"/orgs/{oid}/collections/{coll_id}/home-url",
|
||||
tags=["collections"],
|
||||
|
@ -382,6 +382,7 @@ class StorageOps:
|
||||
filename: str,
|
||||
file_: AsyncIterator,
|
||||
min_size: int,
|
||||
mime: Optional[str] = None,
|
||||
) -> bool:
|
||||
"""do upload to specified key using multipart chunking"""
|
||||
s3storage = self.get_org_primary_storage(org)
|
||||
@ -405,7 +406,10 @@ class StorageOps:
|
||||
key += filename
|
||||
|
||||
mup_resp = await client.create_multipart_upload(
|
||||
ACL="bucket-owner-full-control", Bucket=bucket, Key=key
|
||||
ACL="bucket-owner-full-control",
|
||||
Bucket=bucket,
|
||||
Key=key,
|
||||
ContentType=mime or "",
|
||||
)
|
||||
|
||||
upload_id = mup_resp["UploadId"]
|
||||
|
Loading…
Reference in New Issue
Block a user