147 lines
3.6 KiB
Python
147 lines
3.6 KiB
Python
from typing import List, Literal, Union
|
|
|
|
from ninja import Field, Schema
|
|
|
|
from catalog.common.models import Item
|
|
from common.api import NOT_FOUND, Result, api
|
|
from journal.models.index import JournalIndex, JournalQueryParser
|
|
|
|
|
|
class CustomEmoji(Schema):
|
|
shortcode: str
|
|
url: str
|
|
static_url: str
|
|
visible_in_picker: bool
|
|
category: str
|
|
|
|
|
|
class AccountField(Schema):
|
|
name: str
|
|
value: str
|
|
verified_at: str | None = None
|
|
|
|
|
|
class Account(Schema):
|
|
id: str
|
|
username: str
|
|
acct: str
|
|
url: str
|
|
display_name: str
|
|
note: str
|
|
avatar: str
|
|
avatar_static: str
|
|
header: str | None = Field(...)
|
|
header_static: str | None = Field(...)
|
|
locked: bool
|
|
fields: list[AccountField]
|
|
emojis: list[CustomEmoji]
|
|
bot: bool
|
|
group: bool
|
|
discoverable: bool
|
|
indexable: bool
|
|
moved: Union[None, bool, "Account"] = None
|
|
suspended: bool = False
|
|
limited: bool = False
|
|
created_at: str
|
|
# last_status_at: str | None = Field(...)
|
|
# statuses_count: int | None
|
|
# followers_count: int | None
|
|
# following_count: int | None
|
|
# source: dict | None = None
|
|
|
|
|
|
class MediaAttachment(Schema):
|
|
id: str
|
|
type: Literal["unknown", "image", "gifv", "video", "audio"]
|
|
url: str
|
|
preview_url: str
|
|
remote_url: str | None = None
|
|
meta: dict
|
|
description: str | None = None
|
|
blurhash: str | None = None
|
|
|
|
|
|
class StatusMention(Schema):
|
|
id: str
|
|
username: str
|
|
url: str
|
|
acct: str
|
|
|
|
|
|
class StatusTag(Schema):
|
|
name: str
|
|
url: str
|
|
|
|
|
|
class Post(Schema):
|
|
id: str
|
|
uri: str
|
|
created_at: str
|
|
account: Account
|
|
content: str
|
|
visibility: Literal["public", "unlisted", "private", "direct"]
|
|
sensitive: bool
|
|
spoiler_text: str
|
|
# media_attachments: list[MediaAttachment]
|
|
mentions: list[StatusMention]
|
|
tags: list[StatusTag]
|
|
emojis: list[CustomEmoji]
|
|
reblogs_count: int
|
|
favourites_count: int
|
|
replies_count: int
|
|
url: str | None = Field(...)
|
|
in_reply_to_id: str | None = Field(...)
|
|
in_reply_to_account_id: str | None = Field(...)
|
|
# reblog: Optional["Status"] = Field(...)
|
|
# poll: Poll | None = Field(...)
|
|
# card: None = Field(...)
|
|
language: str | None = Field(...)
|
|
text: str | None = Field(...)
|
|
edited_at: str | None = None
|
|
favourited: bool = False
|
|
reblogged: bool = False
|
|
muted: bool = False
|
|
bookmarked: bool = False
|
|
pinned: bool = False
|
|
ext_neodb: dict | None = None
|
|
|
|
|
|
class PaginatedPostList(Schema):
|
|
data: List[Post]
|
|
pages: int
|
|
count: int
|
|
|
|
|
|
PostTypes = {"mark", "comment", "review", "collection"}
|
|
|
|
|
|
@api.get(
|
|
"/item/{item_uuid}/posts/",
|
|
response={200: PaginatedPostList, 401: Result, 404: Result},
|
|
tags=["catalog"],
|
|
)
|
|
def list_posts_for_item(request, item_uuid: str, type: str | None = None):
|
|
"""
|
|
Get posts for an item
|
|
|
|
`type` is optional, can be a comma separated list of "comment", "review", "collection", "mark"; default is "comment,review"
|
|
"""
|
|
item = Item.get_by_url(item_uuid)
|
|
if not item:
|
|
return NOT_FOUND
|
|
types = [t for t in (type or "").split(",") if t in PostTypes]
|
|
q = "type:" + ",".join(types or ["comment", "review"])
|
|
query = JournalQueryParser(q)
|
|
query.filter("item_id", item.pk)
|
|
query.filter("visibility", 0)
|
|
query.exclude("owner_id", request.user.identity.ignoring)
|
|
r = JournalIndex.instance().search(query)
|
|
result = {
|
|
"data": [
|
|
p.to_mastodon_json()
|
|
for p in r.posts.prefetch_related("attachments", "author")
|
|
],
|
|
"pages": r.pages,
|
|
"count": r.total,
|
|
}
|
|
return result
|