From c186d7d6edbb24a00d28ffd1104590b3689978da Mon Sep 17 00:00:00 2001 From: mein Name Date: Wed, 22 Jan 2025 22:04:32 -0500 Subject: [PATCH] api: add roles to user endpoint; add post_id to mark/review/collection/note --- catalog/{api.py => apis.py} | 30 ++++++++++++++++++++++++++---- catalog/apps.py | 2 +- journal/apis/collection.py | 2 +- journal/apis/note.py | 1 + journal/apis/review.py | 2 +- journal/apis/shelf.py | 28 +++++++++++++++++----------- users/{api.py => apis.py} | 18 ++++++++++++++---- users/apps.py | 2 +- users/models/user.py | 8 ++++++++ 9 files changed, 70 insertions(+), 23 deletions(-) rename catalog/{api.py => apis.py} (92%) rename users/{api.py => apis.py} (73%) diff --git a/catalog/api.py b/catalog/apis.py similarity index 92% rename from catalog/api.py rename to catalog/apis.py index 38f383fd..69286b14 100644 --- a/catalog/api.py +++ b/catalog/apis.py @@ -6,12 +6,34 @@ from django.http import HttpResponse from django.utils import timezone from ninja import Schema -from common.api import * +from common.api import RedirectedResult, Result, api -from .common import * -from .models import * +from .common import SiteManager +from .models import ( + Album, + AlbumSchema, + Edition, + EditionSchema, + Game, + GameSchema, + Item, + ItemSchema, + Movie, + MovieSchema, + Performance, + PerformanceProduction, + PerformanceProductionSchema, + PerformanceSchema, + Podcast, + PodcastSchema, + TVEpisode, + TVEpisodeSchema, + TVSeason, + TVSeasonSchema, + TVShow, + TVShowSchema, +) from .search.models import enqueue_fetch, get_fetch_lock, query_index -from .sites import * class SearchResult(Schema): diff --git a/catalog/apps.py b/catalog/apps.py index 3db404ba..fc96739b 100644 --- a/catalog/apps.py +++ b/catalog/apps.py @@ -7,7 +7,7 @@ class CatalogConfig(AppConfig): def ready(self): # load key modules in proper order, make sure class inject and signal works as expected - from catalog import api, models, sites # noqa + from catalog import apis, models, sites # noqa from catalog.models import init_catalog_audit_log, init_catalog_search_models from journal import models as journal_models # noqa diff --git a/journal/apis/collection.py b/journal/apis/collection.py index 37b33678..db67ff90 100644 --- a/journal/apis/collection.py +++ b/journal/apis/collection.py @@ -13,8 +13,8 @@ from ..models import Collection class CollectionSchema(Schema): uuid: str url: str - visibility: int = Field(ge=0, le=2) + post_id: int | None = Field(alias="latest_post_id") created_time: datetime title: str brief: str diff --git a/journal/apis/note.py b/journal/apis/note.py index b5c92f32..4feb59b1 100644 --- a/journal/apis/note.py +++ b/journal/apis/note.py @@ -12,6 +12,7 @@ from ..models import Note class NoteSchema(Schema): uuid: str + post_id: int | None = Field(alias="latest_post_id") item: ItemSchema title: str content: str diff --git a/journal/apis/review.py b/journal/apis/review.py index 93d6a725..3455eaaf 100644 --- a/journal/apis/review.py +++ b/journal/apis/review.py @@ -16,8 +16,8 @@ from ..models import ( class ReviewSchema(Schema): url: str - visibility: int = Field(ge=0, le=2) + post_id: int | None = Field(alias="latest_post_id") item: ItemSchema created_time: datetime title: str diff --git a/journal/apis/shelf.py b/journal/apis/shelf.py index 09e22290..a2a78d98 100644 --- a/journal/apis/shelf.py +++ b/journal/apis/shelf.py @@ -9,6 +9,7 @@ from ninja.pagination import paginate from catalog.common.models import AvailableItemCategory, Item, ItemCategory, ItemSchema from common.api import PageNumberPagination, Result, api from journal.models.common import q_owned_piece_visible_to_user +from journal.models.shelf import ShelfMember from users.models.apidentity import APIdentity from ..models import ( @@ -21,7 +22,7 @@ from ..models import ( class MarkSchema(Schema): shelf_type: ShelfType visibility: int = Field(ge=0, le=2) - + post_id: int | None = Field(alias="latest_post_id") item: ItemSchema created_time: datetime comment_text: str | None @@ -40,9 +41,9 @@ class MarkInSchema(Schema): @api.get( - "/user/{username}/shelf/{type}", - response={200: List[MarkSchema], 401: Result, 403: Result}, - tags=["mark"], + "/user/{handle}/shelf/{type}", + response={200: List[MarkSchema], 401: Result, 403: Result, 404: Result}, + tags=["shelf"], ) @paginate(PageNumberPagination) def list_marks_on_user_shelf( @@ -57,13 +58,18 @@ def list_marks_on_user_shelf( Shelf's `type` should be one of `wishlist` / `progress` / `complete` / `dropped`; `category` is optional, marks for all categories will be returned if not specified. """ - target = APIdentity.get_by_handle(handle) + try: + target = APIdentity.get_by_handle(handle) + except APIdentity.DoesNotExist: + return ShelfMember.objects.none() viewer = request.user.identity if target.is_blocking(viewer) or target.is_blocked_by(viewer): - return 403, {"message": "unavailable"} + return ShelfMember.objects.none() qv = q_owned_piece_visible_to_user(request.user, target) queryset = ( - target.shelf_manager.get_latest_members(type, ItemCategory(category)) + target.shelf_manager.get_latest_members( + type, ItemCategory(category) if category else None + ) .filter(qv) .prefetch_related("item") ) @@ -73,7 +79,7 @@ def list_marks_on_user_shelf( @api.get( "/me/shelf/{type}", response={200: List[MarkSchema], 401: Result, 403: Result}, - tags=["mark"], + tags=["shelf"], ) @paginate(PageNumberPagination) def list_marks_on_shelf( @@ -94,7 +100,7 @@ def list_marks_on_shelf( @api.get( "/me/shelf/item/{item_uuid}", response={200: MarkSchema, 302: Result, 401: Result, 403: Result, 404: Result}, - tags=["mark"], + tags=["shelf"], ) def get_mark_by_item(request, item_uuid: str, response: HttpResponse): """ @@ -115,7 +121,7 @@ def get_mark_by_item(request, item_uuid: str, response: HttpResponse): @api.post( "/me/shelf/item/{item_uuid}", response={200: Result, 401: Result, 403: Result, 404: Result}, - tags=["mark"], + tags=["shelf"], ) def mark_item(request, item_uuid: str, mark: MarkInSchema): """ @@ -147,7 +153,7 @@ def mark_item(request, item_uuid: str, mark: MarkInSchema): @api.delete( "/me/shelf/item/{item_uuid}", response={200: Result, 401: Result, 403: Result, 404: Result}, - tags=["mark"], + tags=["shelf"], ) def delete_mark(request, item_uuid: str): """ diff --git a/users/api.py b/users/apis.py similarity index 73% rename from users/api.py rename to users/apis.py index 95505cbb..da23ab8a 100644 --- a/users/api.py +++ b/users/apis.py @@ -1,8 +1,12 @@ +from typing import Literal + +from django.conf import settings from ninja import Schema from ninja.schema import Field -from common.api import * -from mastodon.models.common import SocialAccount +from common.api import NOT_FOUND, Result, api +from mastodon.models import SocialAccount +from users.models import APIdentity class ExternalAccountSchema(Schema): @@ -18,6 +22,7 @@ class UserSchema(Schema): display_name: str avatar: str username: str + roles: list[Literal["admin", "staff"]] @api.get( @@ -37,12 +42,13 @@ def me(request): "external_accounts": accts, "display_name": request.user.display_name, "avatar": request.user.avatar, + "roles": request.user.get_roles(), } @api.get( "/user/{handle}", - response={200: UserSchema, 401: Result, 403: Result}, + response={200: UserSchema, 401: Result, 403: Result, 404: Result}, tags=["user"], ) def user(request, handle: str): @@ -51,7 +57,10 @@ def user(request, handle: str): More detailed info can be fetched from Mastodon API """ - target = APIdentity.get_by_handle(handle) + try: + target = APIdentity.get_by_handle(handle) + except APIdentity.DoesNotExist: + return NOT_FOUND viewer = request.user.identity if target.is_blocking(viewer) or target.is_blocked_by(viewer): return 403, {"message": "unavailable"} @@ -62,4 +71,5 @@ def user(request, handle: str): "external_accounts": [], "display_name": target.display_name, "avatar": target.avatar, + "roles": target.user.get_roles() if target.local else [], } diff --git a/users/apps.py b/users/apps.py index 3c7ea9b8..2ba6b074 100644 --- a/users/apps.py +++ b/users/apps.py @@ -5,7 +5,7 @@ class UsersConfig(AppConfig): name = "users" def ready(self): - from . import api # noqa + from . import apis # noqa # register cron jobs from users.jobs import MastodonUserSync # noqa diff --git a/users/models/user.py b/users/models/user.py index c067aa30..a54bd158 100644 --- a/users/models/user.py +++ b/users/models/user.py @@ -171,6 +171,14 @@ class User(AbstractUser): def __str__(self): return f"{self.pk}:{self.username or ''}" + def get_roles(self): + roles = [] + if self.is_staff: + roles.append("staff") + if self.is_superuser: + roles.append("admin") + return roles + @property def registration_complete(self): return self.username is not None