lib.itmens/journal/api.py

228 lines
6.7 KiB
Python
Raw Normal View History

from datetime import datetime
from typing import List
from django.contrib.auth.decorators import login_required
from django.utils import timezone
from ninja import Field, Schema
from ninja.pagination import paginate
from ninja.security import django_auth
from oauth2_provider.decorators import protected_resource
from catalog.common.models import *
from common.api import *
2023-07-20 21:59:49 -04:00
from mastodon.api import share_review
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 | None
rating_grade: int | None = Field(ge=1, le=10)
tags: list[str] = []
created_time: datetime | None
post_to_fediverse: bool = False
2023-06-03 01:22:19 -04:00
@api.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.get(
"/me/shelf/item/{item_uuid}",
2023-06-03 01:22:19 -04:00
response={200: MarkSchema, 401: Result, 403: Result, 404: Result},
)
def get_mark_by_item(request, item_uuid: str):
"""
Get holding mark on current user's shelf by item uuid
"""
item = Item.get_by_url(item_uuid)
if not item:
return 404, {"message": "Item not found"}
shelfmember = request.user.shelf_manager.locate_item(item)
if not shelfmember:
return 404, {"message": "Mark not found"}
return shelfmember
@api.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:
return 404, {"message": "Item not found"}
2023-07-20 21:59:49 -04:00
m = Mark(request.user.identity, item)
try:
2023-07-20 21:59:49 -04:00
TagManager.tag_item(item, request.user, 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,
)
except ValueError as e:
pass # ignore sharing error
return 200, {"message": "OK"}
@api.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"}
m = Mark(request.user, 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
title: str
body: str
post_to_fediverse: bool = False
@api.get("/me/review/", response={200: List[ReviewSchema], 401: Result, 403: Result})
@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.get(
"/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-07-20 21:59:49 -04:00
Review.update_item_review(
2023-06-03 01:22:19 -04:00
item,
request.user,
review.title,
review.body,
review.visibility,
created_time=review.created_time,
)
2023-07-20 21:59:49 -04:00
if review.post_to_fediverse and request.user.mastodon_username:
share_review(review)
2023-06-03 01:22:19 -04:00
return 200, {"message": "OK"}
@api.delete(
"/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-07-20 21:59:49 -04:00
Review.update_item_review(item, request.user, 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}")