lib.itmens/journal/api.py

235 lines
6.8 KiB
Python
Raw Normal View History

from datetime import datetime
from typing import List
from django.http import Http404, HttpResponse
from ninja import Field, Schema
from ninja.pagination import paginate
from catalog.common.models import *
from common.api import *
2023-07-20 21:59:49 -04:00
from .models import Mark, Review, ShelfType, TagManager, q_item_in_category
class MarkSchema(Schema):
shelf_type: ShelfType
visibility: int = Field(ge=0, le=2)
item: ItemSchema
created_time: datetime
comment_text: str | None
rating_grade: int | None = Field(ge=1, le=10)
tags: list[str]
class MarkInSchema(Schema):
shelf_type: ShelfType
visibility: int = Field(ge=0, le=2)
comment_text: str = ""
rating_grade: int = Field(0, ge=0, le=10)
tags: list[str] = []
created_time: datetime | None = None
post_to_fediverse: bool = False
@api.api_operation(
["GET"],
"/me/shelf/{type}",
response={200: List[MarkSchema], 401: Result, 403: Result},
)
@paginate(PageNumberPagination)
def list_marks_on_shelf(
request, type: ShelfType, category: AvailableItemCategory | None = None
):
"""
Get holding marks on current user's shelf
Shelf's `type` should be one of `wishlist` / `progress` / `complete`;
2023-06-03 01:22:19 -04:00
`category` is optional, marks for all categories will be returned if not specified.
"""
queryset = request.user.shelf_manager.get_latest_members(
type, category
).prefetch_related("item")
return queryset
@api.api_operation(
["GET"],
"/me/shelf/item/{item_uuid}",
response={200: MarkSchema, 302: Result, 401: Result, 403: Result, 404: Result},
)
def get_mark_by_item(request, item_uuid: str, response: HttpResponse):
"""
Get holding mark on current user's shelf by item uuid
"""
item = Item.get_by_url(item_uuid)
if not item or item.is_deleted:
return 404, {"message": "Item not found"}
if item.merged_to_item:
response["Location"] = f"/api/me/shelf/item/{item.merged_to_item.uuid}"
return 302, {"message": "Item merged", "url": item.merged_to_item.api_url}
shelfmember = request.user.shelf_manager.locate_item(item)
if not shelfmember:
return 404, {"message": "Mark not found"}
return shelfmember
@api.api_operation(
["POST"],
2023-06-03 01:22:19 -04:00
"/me/shelf/item/{item_uuid}",
response={200: Result, 401: Result, 403: Result, 404: Result},
)
def mark_item(request, item_uuid: str, mark: MarkInSchema):
"""
Create or update a holding mark about an item for current user.
`shelf_type` and `visibility` are required; `created_time` is optional, default to now.
if the item is already marked, this will update the mark.
updating mark without `rating_grade`, `comment_text` or `tags` field will clear them.
"""
item = Item.get_by_url(item_uuid)
if not item or item.is_deleted or item.merged_to_item:
return 404, {"message": "Item not found"}
2023-07-20 21:59:49 -04:00
m = Mark(request.user.identity, item)
2023-12-27 17:11:34 -05:00
TagManager.tag_item(item, request.user.identity, mark.tags, mark.visibility)
m.update(
mark.shelf_type,
mark.comment_text,
mark.rating_grade,
mark.visibility,
created_time=mark.created_time,
share_to_mastodon=mark.post_to_fediverse,
)
return 200, {"message": "OK"}
@api.api_operation(
["DELETE"],
2023-06-03 01:22:19 -04:00
"/me/shelf/item/{item_uuid}",
response={200: Result, 401: Result, 403: Result, 404: Result},
)
def delete_mark(request, item_uuid: str):
"""
Remove a holding mark about an item for current user.
"""
item = Item.get_by_url(item_uuid)
if not item:
return 404, {"message": "Item not found"}
2023-12-27 17:11:34 -05:00
m = Mark(request.user.identity, item)
m.delete()
2023-06-03 11:32:49 -04:00
# skip tag deletion for now to be consistent with web behavior
2023-07-20 21:59:49 -04:00
# TagManager.tag_item(item, request.user, [], 0)
return 200, {"message": "OK"}
2023-06-03 01:22:19 -04:00
class ReviewSchema(Schema):
2023-06-03 14:13:19 -04:00
url: str
2023-06-03 01:22:19 -04:00
visibility: int = Field(ge=0, le=2)
item: ItemSchema
created_time: datetime
title: str
body: str
html_content: str
class ReviewInSchema(Schema):
visibility: int = Field(ge=0, le=2)
created_time: datetime | None = None
2023-06-03 01:22:19 -04:00
title: str
body: str
post_to_fediverse: bool = False
@api.api_operation(
["GET"],
"/me/review/",
response={200: List[ReviewSchema], 401: Result, 403: Result},
)
2023-06-03 01:22:19 -04:00
@paginate(PageNumberPagination)
def list_reviews(request, category: AvailableItemCategory | None = None):
"""
Get reviews by current user
`category` is optional, reviews for all categories will be returned if not specified.
"""
2023-07-20 21:59:49 -04:00
queryset = Review.objects.filter(owner=request.user.identity)
2023-06-03 01:22:19 -04:00
if category:
2023-07-20 21:59:49 -04:00
queryset = queryset.filter(q_item_in_category(category))
2023-06-03 01:22:19 -04:00
return queryset.prefetch_related("item")
@api.api_operation(
["GET"],
2023-06-03 01:22:19 -04:00
"/me/review/item/{item_uuid}",
response={200: ReviewSchema, 401: Result, 403: Result, 404: Result},
)
def get_review_by_item(request, item_uuid: str):
"""
Get review on current user's shelf by item uuid
"""
item = Item.get_by_url(item_uuid)
if not item:
return 404, {"message": "Item not found"}
2023-07-20 21:59:49 -04:00
review = Review.objects.filter(owner=request.user.identity, item=item).first()
2023-06-03 01:22:19 -04:00
if not review:
return 404, {"message": "Review not found"}
return review
@api.post(
"/me/review/item/{item_uuid}",
response={200: Result, 401: Result, 403: Result, 404: Result},
)
def review_item(request, item_uuid: str, review: ReviewInSchema):
"""
Create or update a review about an item for current user.
`title`, `body` (markdown formatted) and`visibility` are required;
`created_time` is optional, default to now.
if the item is already reviewed, this will update the review.
"""
item = Item.get_by_url(item_uuid)
if not item:
return 404, {"message": "Item not found"}
2023-12-27 17:29:21 -05:00
Review.update_item_review(
2023-06-03 01:22:19 -04:00
item,
2023-12-27 17:11:34 -05:00
request.user.identity,
2023-06-03 01:22:19 -04:00
review.title,
review.body,
review.visibility,
created_time=review.created_time,
2023-12-27 17:29:21 -05:00
share_to_mastodon=review.post_to_fediverse,
2023-06-03 01:22:19 -04:00
)
return 200, {"message": "OK"}
@api.api_operation(
["DELETE"],
2023-06-03 01:22:19 -04:00
"/me/review/item/{item_uuid}",
response={200: Result, 401: Result, 403: Result, 404: Result},
)
def delete_review(request, item_uuid: str):
"""
Remove a review about an item for current user.
"""
item = Item.get_by_url(item_uuid)
if not item:
return 404, {"message": "Item not found"}
2023-12-27 17:11:34 -05:00
Review.update_item_review(item, request.user.identity, None, None)
2023-06-03 01:22:19 -04:00
return 200, {"message": "OK"}
# @api.get("/me/collection/")
2023-06-03 01:22:19 -04:00
# @api.post("/me/collection/")
# @api.get("/me/collection/{uuid}")
2023-06-03 01:22:19 -04:00
# @api.put("/me/collection/{uuid}")
# @api.delete("/me/collection/{uuid}")
2023-06-03 01:22:19 -04:00
# @api.get("/me/collection/{uuid}/item/")
# @api.post("/me/collection/{uuid}/item/")
# @api.get("/me/tag/")
# @api.post("/me/tag/")
# @api.get("/me/tag/{title}")
# @api.put("/me/tag/{title}")
# @api.delete("/me/tag/{title}")