from typing import List from ninja import Field, Schema from ninja.pagination import paginate from catalog.common.models import Item, ItemSchema from common.api import PageNumberPagination, Result, api from ..models import Tag class TagSchema(Schema): uuid: str title: str visibility: int = Field(ge=0, le=2) class TagInSchema(Schema): title: str visibility: int = Field(ge=0, le=2) class TagItemSchema(Schema): item: ItemSchema class TagItemInSchema(Schema): item_uuid: str @api.get( "/me/tag/", response={200: List[TagSchema], 401: Result, 403: Result}, tags=["tag"], ) @paginate(PageNumberPagination) def list_tags(request, title: str | None = None): """ Get tags created by current user `title` is optional, all tags will be returned if not specified. """ queryset = Tag.objects.filter(owner=request.user.identity) if title: queryset = queryset.filter(title=Tag.cleanup_title(title)) return queryset @api.get( "/me/tag/{tag_uuid}", response={200: TagSchema, 401: Result, 403: Result, 404: Result}, tags=["tag"], ) def get_tag(request, tag_uuid: str): """ Get tags by its uuid """ tag = Tag.get_by_url(tag_uuid) if not tag: return 404, {"message": "Tag not found"} if tag.owner != request.user.identity: return 403, {"message": "Not owner"} return tag @api.post( "/me/tag/", response={200: TagSchema, 401: Result, 403: Result, 404: Result}, tags=["tag"], ) def create_tag(request, t_in: TagInSchema): """ Create tag. `title` is required, `visibility` can only be 0 or 2; if tag with same title exists, existing tag will be returned. """ title = Tag.cleanup_title(t_in.title) visibility = 2 if t_in.visibility else 0 tag, created = Tag.objects.get_or_create( owner=request.user.identity, title=title, defaults={"visibility": visibility}, ) if not created: tag.visibility = visibility tag.save() return tag @api.put( "/me/tag/{tag_uuid}", response={200: TagSchema, 401: Result, 403: Result, 404: Result, 409: Result}, tags=["tag"], ) def update_tag(request, tag_uuid: str, t_in: TagInSchema): """ Update tag. rename tag with an existing title will return HTTP 409 error """ tag = Tag.get_by_url(tag_uuid) if not tag: return 404, {"message": "Tag not found"} if tag.owner != request.user.identity: return 403, {"message": "Not owner"} title = Tag.cleanup_title(tag.title) visibility = 2 if t_in.visibility else 0 if title != tag.title: try: tag.title = title tag.visibility = visibility tag.save() except Exception: return 409, {"message": "Tag with same title exists"} return tag @api.delete( "/me/tag/{tag_uuid}", response={200: Result, 401: Result, 403: Result, 404: Result}, tags=["tag"], ) def delete_tag(request, tag_uuid: str): """ Remove a tag. """ tag = Tag.get_by_url(tag_uuid) if not tag: return 404, {"message": "Tag not found"} if tag.owner != request.user.identity: return 403, {"message": "Not owner"} tag.delete() return 200, {"message": "OK"} @api.get( "/me/tag/{tag_uuid}/item/", response={200: List[TagItemSchema], 401: Result, 403: Result, 404: Result}, tags=["tag"], ) @paginate(PageNumberPagination) def tag_list_items(request, tag_uuid: str): """ Get items in a tag tags """ tag = Tag.get_by_url(tag_uuid) if not tag: return 404, {"message": "Tag not found"} if tag.owner != request.user.identity: return 403, {"message": "Not owner"} return tag.members.all() @api.post( "/me/tag/{tag_uuid}/item/", response={200: Result, 401: Result, 403: Result, 404: Result}, tags=["tag"], ) def tag_add_item(request, tag_uuid: str, tag_item: TagItemInSchema): """ Add an item to tag """ tag = Tag.get_by_url(tag_uuid) if not tag: return 404, {"message": "Tag not found"} if tag.owner != request.user.identity: return 403, {"message": "Not owner"} if not tag_item.item_uuid: return 404, {"message": "Item not found"} item = Item.get_by_url(tag_item.item_uuid) if not item: return 404, {"message": "Item not found"} tag.append_item(item) return 200, {"message": "OK"} @api.delete( "/me/tag/{tag_uuid}/item/{item_uuid}", response={200: Result, 401: Result, 403: Result, 404: Result}, tags=["tag"], ) def tag_delete_item(request, tag_uuid: str, item_uuid: str): """ Remove an item from tag """ tag = Tag.get_by_url(tag_uuid) if not tag: return 404, {"message": "Tag not found"} if tag.owner != request.user.identity: return 403, {"message": "Not owner"} item = Item.get_by_url(item_uuid) if not item: return 404, {"message": "Item not found"} tag.remove_item(item) return 200, {"message": "OK"}