Skip to content

Commit

Permalink
image preview (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
codekansas authored Aug 5, 2024
1 parent 28ce71f commit a4891e9
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 7 deletions.
8 changes: 6 additions & 2 deletions frontend/src/components/listings/ListingGridCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ const ListingGridCard = (props: Props) => {
onMouseLeave={() => setHovering(false)}
onClick={() => navigate(`/item/${listingId}`)}
>
<Image />
{listing?.image_url ? (
<img src={listing.image_url} alt={listing.name} />
) : (
<Image />
)}
<div className="px-4 py-4 h-full">
<CardHeader>
<CardTitle className="text-gray-500 text-xl min-h-6">
Expand All @@ -43,7 +47,7 @@ const ListingGridCard = (props: Props) => {
)}
</CardTitle>
</CardHeader>
<CardContent className="max-h-32 overflow-hidden">
<CardContent className="text-gray-500 max-h-32 overflow-hidden">
{listing ? (
listing?.description && (
<RenderDescription description={listing?.description} />
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/gen/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,8 @@ export interface components {
description: string | null;
/** Child Ids */
child_ids: string[];
/** Image Url */
image_url: string | null;
};
/** NewListingRequest */
NewListingRequest: {
Expand Down
7 changes: 7 additions & 0 deletions store/app/crud/artifacts.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ def _crop_image(self, image: Image.Image, size: tuple[int, int]) -> io.BytesIO:
lower = upper + new_height
image_resized = image.crop((left, upper, right, lower))

# Resize the image to the desired size.
image_resized = image_resized.resize(size, resample=Image.Resampling.BICUBIC)

# Save the image to a byte stream.
image_resized.save(image_bytes, format="PNG", optimize=True, quality=settings.image.quality)
image_bytes.seek(0)
return image_bytes
Expand Down Expand Up @@ -167,6 +171,9 @@ async def remove_artifact(self, artifact: Artifact, user_id: str) -> None:
async def get_listing_artifacts(self, listing_id: str) -> list[Artifact]:
return await self._get_items_from_secondary_index("listing_id", listing_id, Artifact)

async def get_listings_artifacts(self, listing_ids: list[str]) -> list[list[Artifact]]:
return await self._get_items_from_secondary_index_batch("listing_id", listing_ids, Artifact)

async def edit_artifact(
self,
artifact_id: str,
Expand Down
44 changes: 42 additions & 2 deletions store/app/crud/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Any, AsyncContextManager, BinaryIO, Callable, Literal, Self, TypeVar, overload

import aioboto3
from boto3.dynamodb.conditions import Key
from boto3.dynamodb.conditions import Attr, Key
from botocore.exceptions import ClientError
from types_aiobotocore_dynamodb.service_resource import DynamoDBServiceResource
from types_aiobotocore_s3.service_resource import S3ServiceResource
Expand Down Expand Up @@ -226,8 +226,14 @@ async def _get_item_batch(
chunk = item_ids[i : i + chunk_size]
keys = [{"id": item_id} for item_id in chunk]
response = await self.db.batch_get_item(RequestItems={TABLE_NAME: {"Keys": keys}})

# Maps the items to their IDs to return them in the correct order.
item_ids_to_items: dict[str, T] = {}
for item in response["Responses"][TABLE_NAME]:
items.append(self._validate_item(item, item_class))
item_impl = self._validate_item(item, item_class)
item_ids_to_items[item_impl.id] = item_impl
items += [item_ids_to_items[item_id] for item_id in chunk]

return items

async def _get_items_from_secondary_index(
Expand All @@ -245,6 +251,40 @@ async def _get_items_from_secondary_index(
items = item_dict["Items"]
return [self._validate_item(item, item_class) for item in items]

async def _get_items_from_secondary_index_batch(
self,
secondary_index_name: str,
secondary_index_values: list[str],
item_class: type[T],
chunk_size: int = DEFAULT_CHUNK_SIZE,
) -> list[list[T]]:
items: list[list[T]] = []
table = await self.db.Table(TABLE_NAME)

for i in range(0, len(secondary_index_values), chunk_size):
chunk = secondary_index_values[i : i + chunk_size]
response = await table.scan(
IndexName=self.get_gsi_index_name(secondary_index_name),
FilterExpression=(Attr(secondary_index_name).is_in(chunk) & Attr("type").eq(item_class.__name__)),
)

# Maps the items to their IDs.
chunk_items = [self._validate_item(item, item_class) for item in response["Items"]]
chunk_ids_to_items: dict[str, list[T]] = {}
for item in chunk_items:
item_id = getattr(item, secondary_index_name)
if item_id in chunk_ids_to_items:
chunk_ids_to_items[item_id].append(item)
else:
chunk_ids_to_items[item_id] = [item]

print(chunk_ids_to_items)

# Adds the items to the list.
items += [chunk_ids_to_items.get(id, []) for id in chunk]

return items

@overload
async def _get_unique_item_from_secondary_index(
self,
Expand Down
18 changes: 15 additions & 3 deletions store/app/routers/listings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pydantic import BaseModel

from store.app.db import Crud
from store.app.model import Listing, User
from store.app.model import Listing, User, get_artifact_url
from store.app.routers.users import (
get_session_user_with_read_permission,
get_session_user_with_write_permission,
Expand Down Expand Up @@ -41,6 +41,7 @@ class ListingInfoResponse(BaseModel):
name: str
description: str | None
child_ids: list[str]
image_url: str | None


class GetBatchListingsResponse(BaseModel):
Expand All @@ -52,16 +53,27 @@ async def get_batch_listing_info(
crud: Annotated[Crud, Depends(Crud.get)],
ids: list[str] = Query(description="List of part ids"),
) -> GetBatchListingsResponse:
listings = await crud._get_item_batch(ids, Listing)
listings, artifacts = await asyncio.gather(
crud._get_item_batch(ids, Listing),
crud.get_listings_artifacts(ids),
)
return GetBatchListingsResponse(
listings=[
ListingInfoResponse(
id=listing.id,
name=listing.name,
description=listing.description,
child_ids=listing.child_ids,
image_url=next(
(
get_artifact_url(artifact.id, "image", "small")
for artifact in artifacts
if artifact.artifact_type == "image"
),
None,
),
)
for listing in listings
for listing, artifacts in zip(listings, artifacts)
]
)

Expand Down

0 comments on commit a4891e9

Please sign in to comment.