diff --git a/etebase_fastapi/collection.py b/etebase_fastapi/collection.py index 3a9ca8b..7679ed6 100644 --- a/etebase_fastapi/collection.py +++ b/etebase_fastapi/collection.py @@ -15,7 +15,7 @@ from django_etebase import models from .authentication import get_authenticated_user from .exceptions import ValidationError, transform_validation_error from .msgpack import MsgpackRoute, MsgpackResponse -from .stoken_handler import filter_by_stoken_and_limit, get_stoken_obj +from .stoken_handler import filter_by_stoken_and_limit, filter_by_stoken, get_stoken_obj, get_queryset_stoken User = get_user_model() collection_router = APIRouter(route_class=MsgpackRoute) @@ -133,6 +133,11 @@ class CollectionItemListResponse(BaseModel): done: bool +class CollectionItemBulkGetIn(BaseModel): + uid: str + etag: t.Optional[str] + + class ItemDepIn(BaseModel): etag: str uid: str @@ -417,6 +422,41 @@ def item_bulk_common(data: ItemBatchIn, user: User, stoken: t.Optional[str], uid return MsgpackResponse({}) +@collection_router.post("/{collection_uid}/item/fetch_updates/") +def fetch_updates( + collection_uid: str, + data: t.List[CollectionItemBulkGetIn], + stoken: t.Optional[str] = None, + prefetch: Prefetch = PrefetchQuery, + user: User = Depends(get_authenticated_user), +): + _, queryset = get_item_queryset(user, collection_uid) + # FIXME: make configurable? + item_limit = 200 + + if len(data) > item_limit: + raise ValidationError("too_many_items", "Request has too many items.", status_code=status.HTTP_400_BAD_REQUEST) + + queryset, stoken_rev = filter_by_stoken(stoken, queryset, models.CollectionItem.stoken_annotation) + + uids, etags = zip(*[(item.uid, item.etag) for item in data]) + revs = models.CollectionItemRevision.objects.filter(uid__in=etags, current=True) + queryset = queryset.filter(uid__in=uids).exclude(revisions__in=revs) + + new_stoken_obj = get_queryset_stoken(queryset) + new_stoken = new_stoken_obj and new_stoken_obj.uid + stoken = stoken_rev and getattr(stoken_rev, "uid", None) + new_stoken = new_stoken or stoken + + context = Context(user, prefetch) + ret = CollectionItemListResponse( + data=[CollectionItemOut.from_orm_context(item, context) for item in queryset], + stoken=new_stoken, + done=True, # we always return all the items, so it's always done + ) + return MsgpackResponse(ret) + + @collection_router.post("/{collection_uid}/item/transaction/") def item_transaction( collection_uid: str, data: ItemBatchIn, stoken: t.Optional[str] = None, user: User = Depends(get_authenticated_user) diff --git a/etebase_fastapi/stoken_handler.py b/etebase_fastapi/stoken_handler.py index fb89651..a976830 100644 --- a/etebase_fastapi/stoken_handler.py +++ b/etebase_fastapi/stoken_handler.py @@ -33,7 +33,7 @@ def filter_by_stoken( return queryset, stoken_rev -def get_queryset_stoken(queryset: list) -> t.Optional[Stoken]: +def get_queryset_stoken(queryset: t.Iterable[t.Any]) -> t.Optional[Stoken]: maxid = -1 for row in queryset: rowmaxid = getattr(row, "max_stoken") or -1