post comment as ap
This commit is contained in:
parent
0f9493d6c1
commit
a0225fd6ca
7 changed files with 89 additions and 117 deletions
|
@ -111,11 +111,11 @@ class PodcastEpisode(Item):
|
|||
def cover_image_url(self):
|
||||
return self.cover_url or self.program.cover_image_url
|
||||
|
||||
def get_absolute_url_with_position(self, position=None):
|
||||
def get_url_with_position(self, position=None):
|
||||
return (
|
||||
self.absolute_url
|
||||
self.url
|
||||
if position is None or position == ""
|
||||
else f"{self.absolute_url}?position={position}"
|
||||
else f"{self.url}?position={position}"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
|
|
@ -17,7 +17,7 @@ class Comment(Content):
|
|||
|
||||
@property
|
||||
def ap_object(self):
|
||||
return {
|
||||
d = {
|
||||
"id": self.absolute_url,
|
||||
"type": "Comment",
|
||||
"content": self.text,
|
||||
|
@ -27,6 +27,10 @@ class Comment(Content):
|
|||
"relatedWith": self.item.absolute_url,
|
||||
"href": self.absolute_url,
|
||||
}
|
||||
if self.metadata.get("position"):
|
||||
d["relatedWithItemPosition"] = self.metadata["position"]
|
||||
d["relatedWithItemPositionType"] = "time"
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
def update_by_ap_object(cls, owner, item, obj, post_id, visibility):
|
||||
|
@ -42,6 +46,8 @@ class Comment(Content):
|
|||
"created_time": datetime.fromisoformat(obj["published"]),
|
||||
"edited_time": datetime.fromisoformat(obj["updated"]),
|
||||
}
|
||||
if obj.get("relatedWithItemPosition"):
|
||||
d["metadata"] = {"position": obj["relatedWithItemPosition"]}
|
||||
p, _ = cls.objects.update_or_create(owner=owner, item=item, defaults=d)
|
||||
p.link_post_id(post_id)
|
||||
return p
|
||||
|
@ -65,7 +71,7 @@ class Comment(Content):
|
|||
@property
|
||||
def item_url(self):
|
||||
if self.metadata.get("position"):
|
||||
return self.item.get_absolute_url_with_position(self.metadata["position"])
|
||||
return self.item.get_url_with_position(self.metadata["position"])
|
||||
else:
|
||||
return self.item.url
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ class ShelfMember(ListMember):
|
|||
def update_by_ap_object(
|
||||
cls, owner: APIdentity, item: Identity, obj: dict, post_id: int, visibility: int
|
||||
):
|
||||
# TODO check timestamp? (update may come in with inconsistent sequence)
|
||||
if not obj:
|
||||
cls.objects.filter(owner=owner, item=item).delete()
|
||||
return
|
||||
|
|
|
@ -15,16 +15,7 @@ from .collection import (
|
|||
user_liked_collection_list,
|
||||
)
|
||||
from .common import piece_delete
|
||||
from .mark import (
|
||||
comment,
|
||||
like,
|
||||
mark,
|
||||
mark_log,
|
||||
share_comment,
|
||||
unlike,
|
||||
user_mark_list,
|
||||
wish,
|
||||
)
|
||||
from .mark import comment, like, mark, mark_log, unlike, user_mark_list, wish
|
||||
from .post import piece_replies, post_like, post_replies, post_reply, post_unlike
|
||||
from .profile import profile, user_calendar_data
|
||||
from .review import ReviewFeed, review_edit, review_retrieve, user_review_list
|
||||
|
|
|
@ -13,12 +13,7 @@ from django.utils.translation import gettext_lazy as _
|
|||
|
||||
from catalog.models import *
|
||||
from common.utils import AuthedHttpRequest, PageLinksGenerator, get_uuid_or_404
|
||||
from mastodon.api import (
|
||||
get_spoiler_text,
|
||||
get_status_id_by_url,
|
||||
get_visibility,
|
||||
post_toot,
|
||||
)
|
||||
from mastodon.api import boost_toot
|
||||
from takahe.utils import Takahe
|
||||
|
||||
from ..models import Comment, Mark, Piece, ShelfType, ShelfTypeNames, TagManager
|
||||
|
@ -168,36 +163,6 @@ def mark(request: AuthedHttpRequest, item_uuid):
|
|||
raise BadRequest()
|
||||
|
||||
|
||||
def share_comment(user, item, text, visibility, shared_link=None, position=None):
|
||||
post_error = False
|
||||
status_id = get_status_id_by_url(shared_link)
|
||||
link = (
|
||||
item.get_absolute_url_with_position(position) if position else item.absolute_url
|
||||
)
|
||||
action_label = "评论" if text else "分享"
|
||||
status = f"{action_label}{ItemCategory(item.category).label}《{item.display_title}》\n{link}\n\n{text}"
|
||||
spoiler, status = get_spoiler_text(status, item)
|
||||
try:
|
||||
response = post_toot(
|
||||
user.mastodon_site,
|
||||
status,
|
||||
get_visibility(visibility, user),
|
||||
user.mastodon_token,
|
||||
False,
|
||||
status_id,
|
||||
spoiler,
|
||||
)
|
||||
if response and response.status_code in [200, 201]:
|
||||
j = response.json()
|
||||
if "url" in j:
|
||||
shared_link = j["url"]
|
||||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
raise
|
||||
post_error = True
|
||||
return post_error, shared_link
|
||||
|
||||
|
||||
@login_required
|
||||
def mark_log(request: AuthedHttpRequest, item_uuid, log_id):
|
||||
"""
|
||||
|
@ -220,15 +185,7 @@ def comment(request: AuthedHttpRequest, item_uuid):
|
|||
item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid))
|
||||
if not item.class_name in ["podcastepisode", "tvepisode"]:
|
||||
raise BadRequest("不支持评论此类型的条目")
|
||||
# episode = None
|
||||
# if item.class_name == "tvseason":
|
||||
# try:
|
||||
# episode = int(request.POST.get("episode", 0))
|
||||
# except:
|
||||
# episode = 0
|
||||
# if episode <= 0:
|
||||
# raise BadRequest("请输入正确的集数")
|
||||
comment = Comment.objects.filter(owner=request.user, item=item).first()
|
||||
comment = Comment.objects.filter(owner=request.user.identity, item=item).first()
|
||||
if request.method == "GET":
|
||||
return render(
|
||||
request,
|
||||
|
@ -256,49 +213,22 @@ def comment(request: AuthedHttpRequest, item_uuid):
|
|||
if settings.DEBUG:
|
||||
raise
|
||||
position = None
|
||||
share_to_mastodon = bool(request.POST.get("share_to_mastodon", default=False))
|
||||
shared_link = comment.metadata.get("shared_link") if comment else None
|
||||
post_error = False
|
||||
if share_to_mastodon and request.user.mastodon_username:
|
||||
post_error, shared_link = share_comment(
|
||||
request.user, item, text, visibility, shared_link, position
|
||||
)
|
||||
Comment.objects.update_or_create(
|
||||
owner=request.user,
|
||||
item=item,
|
||||
# metadata__episode=episode,
|
||||
defaults={
|
||||
"text": text,
|
||||
"visibility": visibility,
|
||||
"metadata": {
|
||||
"shared_link": shared_link,
|
||||
"position": position,
|
||||
},
|
||||
},
|
||||
d = {"text": text, "visibility": visibility}
|
||||
if position:
|
||||
d["metadata"] = {"position": position}
|
||||
comment, _ = Comment.objects.update_or_create(
|
||||
owner=request.user.identity, item=item, defaults=d
|
||||
)
|
||||
|
||||
# if comment:
|
||||
# comment.visibility = visibility
|
||||
# comment.text = text
|
||||
# comment.metadata["position"] = position
|
||||
# comment.metadata["episode"] = episode
|
||||
# if shared_link:
|
||||
# comment.metadata["shared_link"] = shared_link
|
||||
# comment.save()
|
||||
# else:
|
||||
# comment = Comment.objects.create(
|
||||
# owner=request.user,
|
||||
# item=item,
|
||||
# text=text,
|
||||
# visibility=visibility,
|
||||
# metadata={
|
||||
# "shared_link": shared_link,
|
||||
# "position": position,
|
||||
# "episode": episode,
|
||||
# },
|
||||
# )
|
||||
if post_error:
|
||||
return render_relogin(request)
|
||||
post = Takahe.post_comment(comment, False)
|
||||
share_to_mastodon = bool(request.POST.get("share_to_mastodon", default=False))
|
||||
if post and share_to_mastodon and request.user.mastodon_username:
|
||||
boost_toot(
|
||||
request.user.mastodon_site,
|
||||
request.user.mastodon_token,
|
||||
post.url,
|
||||
)
|
||||
# if post_error:
|
||||
# return render_relogin(request)
|
||||
return HttpResponseRedirect(request.META.get("HTTP_REFERER", "/"))
|
||||
raise BadRequest()
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ _supported_ap_catalog_item_types = [
|
|||
"Album",
|
||||
"Game",
|
||||
"Podcast",
|
||||
"PodcastEpisode",
|
||||
"Performance",
|
||||
"PerformanceProduction",
|
||||
]
|
||||
|
@ -30,14 +31,12 @@ _supported_ap_journal_types = {
|
|||
}
|
||||
|
||||
|
||||
def _parse_item_links(objects):
|
||||
def _parse_items(objects):
|
||||
logger.debug(f"Parsing item links from {objects}")
|
||||
if not objects:
|
||||
return []
|
||||
objs = objects if isinstance(objects, list) else [objects]
|
||||
items = [
|
||||
obj["href"] for obj in objs if obj["type"] in _supported_ap_catalog_item_types
|
||||
]
|
||||
items = [obj for obj in objs if obj["type"] in _supported_ap_catalog_item_types]
|
||||
return items
|
||||
|
||||
|
||||
|
@ -55,8 +54,14 @@ def _parse_piece_objects(objects):
|
|||
return pieces
|
||||
|
||||
|
||||
def _get_or_create_item_by_ap_url(url):
|
||||
logger.debug(f"Fetching item by ap from {url}")
|
||||
def _get_or_create_item(item_obj):
|
||||
logger.debug(f"Fetching item by ap from {item_obj}")
|
||||
typ = item_obj["type"]
|
||||
url = item_obj["href"]
|
||||
if typ in ["TVEpisode", "PodcastEpisode"]:
|
||||
# TODO support episode item
|
||||
# match and fetch parent item first
|
||||
return None
|
||||
site = SiteManager.get_site_by_url(url)
|
||||
if not site:
|
||||
return None
|
||||
|
@ -75,13 +80,13 @@ def _get_visibility(post_visibility):
|
|||
return 0
|
||||
|
||||
|
||||
def _update_or_create_post(pk, obj):
|
||||
def post_fetched(pk, obj):
|
||||
post = Post.objects.get(pk=pk)
|
||||
owner = Takahe.get_or_create_remote_apidentity(post.author)
|
||||
if not post.type_data:
|
||||
logger.warning(f"Post {post} has no type_data")
|
||||
return
|
||||
items = _parse_item_links(post.type_data["object"]["tag"])
|
||||
items = _parse_items(post.type_data["object"]["tag"])
|
||||
pieces = _parse_piece_objects(post.type_data["object"]["relatedWith"])
|
||||
logger.info(f"Post {post} has items {items} and pieces {pieces}")
|
||||
if len(items) == 0:
|
||||
|
@ -90,20 +95,15 @@ def _update_or_create_post(pk, obj):
|
|||
elif len(items) > 1:
|
||||
logger.warning(f"Post {post} has more than one remote item")
|
||||
return
|
||||
remote_url = items[0]
|
||||
item = _get_or_create_item_by_ap_url(remote_url)
|
||||
item = _get_or_create_item(items[0])
|
||||
if not item:
|
||||
logger.warning(f"Post {post} has no local item")
|
||||
logger.warning(f"Post {post} has no local item matched or created")
|
||||
return
|
||||
for p in pieces:
|
||||
cls = _supported_ap_journal_types[p["type"]]
|
||||
cls.update_by_ap_object(owner, item, p, pk, _get_visibility(post.visibility))
|
||||
|
||||
|
||||
def post_fetched(pk, obj):
|
||||
_update_or_create_post(pk, obj)
|
||||
|
||||
|
||||
def post_deleted(pk, obj):
|
||||
Piece.objects.filter(posts__id=pk, local=False).delete()
|
||||
|
||||
|
|
|
@ -397,6 +397,50 @@ class Takahe:
|
|||
def delete_posts(post_pks):
|
||||
Post.objects.filter(pk__in=post_pks).update(state="deleted")
|
||||
|
||||
@staticmethod
|
||||
def post_comment(comment, share_as_new_post: bool) -> Post | None:
|
||||
from catalog.common import ItemCategory
|
||||
|
||||
user = comment.owner.user
|
||||
category = str(ItemCategory(comment.item.category).label)
|
||||
tags = (
|
||||
"\n" + user.preference.mastodon_append_tag.replace("[category]", category)
|
||||
if user.preference.mastodon_append_tag
|
||||
else ""
|
||||
)
|
||||
item_link = f"{settings.SITE_INFO['site_url']}/~neodb~{comment.item_url}"
|
||||
action_label = "评论" if comment.text else "分享"
|
||||
pre_conetent = f'{action_label}{category}<a href="{item_link}">《{comment.item.display_title}》</a><br>'
|
||||
content = f"{comment.text}\n{tags}"
|
||||
data = {
|
||||
"object": {
|
||||
"tag": [comment.item.ap_object_ref],
|
||||
"relatedWith": [comment.ap_object],
|
||||
}
|
||||
}
|
||||
if comment.visibility == 1:
|
||||
v = Takahe.Visibilities.followers
|
||||
elif comment.visibility == 2:
|
||||
v = Takahe.Visibilities.mentioned
|
||||
elif user.preference.mastodon_publish_public:
|
||||
v = Takahe.Visibilities.public
|
||||
else:
|
||||
v = Takahe.Visibilities.unlisted
|
||||
existing_post = None if share_as_new_post else comment.latest_post
|
||||
post = Takahe.post( # TODO post as Article?
|
||||
comment.owner.pk,
|
||||
pre_conetent,
|
||||
content,
|
||||
v,
|
||||
data,
|
||||
existing_post.pk if existing_post else None,
|
||||
comment.created_time,
|
||||
)
|
||||
if not post:
|
||||
return
|
||||
comment.link_post(post)
|
||||
return post
|
||||
|
||||
@staticmethod
|
||||
def post_review(review, share_as_new_post: bool) -> Post | None:
|
||||
from catalog.common import ItemCategory
|
||||
|
|
Loading…
Add table
Reference in a new issue