2023-08-10 11:27:31 -04:00
|
|
|
import re
|
2023-11-19 08:34:01 -05:00
|
|
|
from datetime import datetime
|
2023-08-10 11:27:31 -04:00
|
|
|
from functools import cached_property
|
|
|
|
|
2024-06-13 23:02:12 -04:00
|
|
|
from django.conf import settings
|
2023-08-10 11:27:31 -04:00
|
|
|
from django.db import models
|
|
|
|
from django.utils import timezone
|
2024-06-13 23:02:12 -04:00
|
|
|
from django.utils.translation import gettext as _
|
2023-11-19 08:34:01 -05:00
|
|
|
from markdownify import markdownify as md
|
2023-08-10 11:27:31 -04:00
|
|
|
from markdownx.models import MarkdownxField
|
|
|
|
|
|
|
|
from catalog.models import Item
|
2024-06-13 23:02:12 -04:00
|
|
|
from mastodon.api import boost_toot_later
|
2024-06-13 20:44:15 -04:00
|
|
|
from takahe.utils import Takahe
|
2023-07-20 21:59:49 -04:00
|
|
|
from users.models import APIdentity
|
2023-08-10 11:27:31 -04:00
|
|
|
|
|
|
|
from .common import Content
|
|
|
|
from .rating import Rating
|
2024-06-13 23:02:12 -04:00
|
|
|
from .renderers import render_md, render_post_with_macro, render_rating
|
|
|
|
from .shelf import ShelfManager
|
2023-08-10 11:27:31 -04:00
|
|
|
|
|
|
|
_RE_HTML_TAG = re.compile(r"<[^>]*>")
|
|
|
|
_RE_SPOILER_TAG = re.compile(r'<(div|span)\sclass="spoiler">.*</(div|span)>')
|
|
|
|
|
|
|
|
|
|
|
|
class Review(Content):
|
|
|
|
url_path = "review"
|
|
|
|
title = models.CharField(max_length=500, blank=False, null=False)
|
|
|
|
body = MarkdownxField()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def html_content(self):
|
|
|
|
return render_md(self.body)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def plain_content(self):
|
|
|
|
html = render_md(self.body)
|
|
|
|
return _RE_HTML_TAG.sub(
|
|
|
|
" ", _RE_SPOILER_TAG.sub("***", html.replace("\n", " "))
|
|
|
|
)
|
|
|
|
|
2023-11-19 00:56:39 -05:00
|
|
|
@property
|
|
|
|
def ap_object(self):
|
|
|
|
return {
|
|
|
|
"id": self.absolute_url,
|
|
|
|
"type": "Review",
|
|
|
|
"name": self.title,
|
2023-11-19 09:22:01 -05:00
|
|
|
# "content": self.html_content,
|
|
|
|
"content": self.body,
|
|
|
|
"mediaType": "text/markdown",
|
2023-11-19 00:56:39 -05:00
|
|
|
"published": self.created_time.isoformat(),
|
|
|
|
"updated": self.edited_time.isoformat(),
|
|
|
|
"attributedTo": self.owner.actor_uri,
|
2023-11-28 08:45:04 -05:00
|
|
|
"withRegardTo": self.item.absolute_url,
|
2023-11-19 00:56:39 -05:00
|
|
|
"href": self.absolute_url,
|
|
|
|
}
|
|
|
|
|
2023-11-19 08:34:01 -05:00
|
|
|
@classmethod
|
2024-06-13 20:44:15 -04:00
|
|
|
def update_by_ap_object(cls, owner, item, obj, post):
|
2023-11-20 19:11:02 -05:00
|
|
|
p = cls.objects.filter(owner=owner, item=item).first()
|
|
|
|
if p and p.edited_time >= datetime.fromisoformat(obj["updated"]):
|
|
|
|
return p # incoming ap object is older than what we have, no update needed
|
2023-11-19 09:22:01 -05:00
|
|
|
content = (
|
|
|
|
obj["content"]
|
|
|
|
if obj.get("mediaType") == "text/markdown"
|
|
|
|
else md(obj["content"])
|
|
|
|
)
|
2023-11-19 08:34:01 -05:00
|
|
|
d = {
|
|
|
|
"title": obj["name"],
|
2023-11-19 09:22:01 -05:00
|
|
|
"body": content,
|
2023-11-19 08:34:01 -05:00
|
|
|
"local": False,
|
|
|
|
"remote_id": obj["id"],
|
2024-06-13 20:44:15 -04:00
|
|
|
"visibility": Takahe.visibility_t2n(post.visibility),
|
2023-11-19 08:34:01 -05:00
|
|
|
"created_time": datetime.fromisoformat(obj["published"]),
|
|
|
|
"edited_time": datetime.fromisoformat(obj["updated"]),
|
|
|
|
}
|
|
|
|
p, _ = cls.objects.update_or_create(owner=owner, item=item, defaults=d)
|
2024-06-13 20:44:15 -04:00
|
|
|
p.link_post_id(post.id)
|
2023-11-19 08:34:01 -05:00
|
|
|
return p
|
|
|
|
|
2024-06-16 21:54:20 -04:00
|
|
|
def get_crosspost_postfix(self):
|
2024-06-13 23:02:12 -04:00
|
|
|
tags = render_post_with_macro(
|
|
|
|
self.owner.user.preference.mastodon_append_tag, self.item
|
|
|
|
)
|
|
|
|
return "\n" + tags if tags else ""
|
|
|
|
|
2024-06-16 21:54:20 -04:00
|
|
|
def get_crosspost_template(self):
|
2024-06-13 23:02:12 -04:00
|
|
|
return _(ShelfManager.get_action_template("reviewed", self.item.category))
|
|
|
|
|
|
|
|
def to_mastodon_params(self):
|
|
|
|
content = (
|
2024-06-16 21:54:20 -04:00
|
|
|
self.get_crosspost_template().format(item=self.item.display_title)
|
2024-06-13 23:02:12 -04:00
|
|
|
+ f"\n{self.title}\n{self.absolute_url} "
|
2024-06-16 21:54:20 -04:00
|
|
|
+ self.get_crosspost_postfix()
|
2024-06-13 23:02:12 -04:00
|
|
|
)
|
|
|
|
params = {"content": content}
|
|
|
|
return params
|
|
|
|
|
|
|
|
def to_post_params(self):
|
|
|
|
item_link = f"{settings.SITE_INFO['site_url']}/~neodb~{self.item.url}"
|
2024-06-15 21:54:39 -04:00
|
|
|
prepend_content = (
|
2024-06-16 21:54:20 -04:00
|
|
|
self.get_crosspost_template().format(
|
2024-06-13 23:02:12 -04:00
|
|
|
item=f'<a href="{item_link}">{self.item.display_title}</a>'
|
|
|
|
)
|
|
|
|
+ f'<br><a href="{self.absolute_url}">{self.title}</a>'
|
|
|
|
)
|
2024-06-16 21:54:20 -04:00
|
|
|
content = (
|
|
|
|
f"{render_rating(self.rating_grade, 1)}\n{self.get_crosspost_postfix()}"
|
|
|
|
)
|
2024-06-13 23:02:12 -04:00
|
|
|
return {
|
2024-06-15 21:54:39 -04:00
|
|
|
"prepend_content": prepend_content,
|
2024-06-13 23:02:12 -04:00
|
|
|
"content": content,
|
|
|
|
}
|
|
|
|
|
2023-08-10 11:27:31 -04:00
|
|
|
@cached_property
|
|
|
|
def mark(self):
|
|
|
|
from .mark import Mark
|
|
|
|
|
|
|
|
m = Mark(self.owner, self.item)
|
|
|
|
m.review = self
|
|
|
|
return m
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def rating_grade(self):
|
2023-07-20 21:59:49 -04:00
|
|
|
return Rating.get_item_rating(self.item, self.owner)
|
2023-08-10 11:27:31 -04:00
|
|
|
|
|
|
|
@classmethod
|
2023-07-20 21:59:49 -04:00
|
|
|
def update_item_review(
|
2023-08-10 11:27:31 -04:00
|
|
|
cls,
|
|
|
|
item: Item,
|
2023-07-20 21:59:49 -04:00
|
|
|
owner: APIdentity,
|
2023-08-10 11:27:31 -04:00
|
|
|
title: str | None,
|
|
|
|
body: str | None,
|
|
|
|
visibility=0,
|
|
|
|
created_time=None,
|
2023-12-27 17:29:21 -05:00
|
|
|
share_to_mastodon: bool = False,
|
2023-08-10 11:27:31 -04:00
|
|
|
):
|
2024-06-13 23:02:12 -04:00
|
|
|
review = Review.objects.filter(owner=owner, item=item).first()
|
|
|
|
delete_existing_post = False
|
|
|
|
if review is not None:
|
|
|
|
if title is None:
|
2023-08-10 11:27:31 -04:00
|
|
|
review.delete()
|
2024-06-13 23:02:12 -04:00
|
|
|
return
|
|
|
|
delete_existing_post = review.visibility != visibility
|
2023-08-10 11:27:31 -04:00
|
|
|
defaults = {
|
|
|
|
"title": title,
|
|
|
|
"body": body,
|
|
|
|
"visibility": visibility,
|
|
|
|
}
|
|
|
|
if created_time:
|
|
|
|
defaults["created_time"] = (
|
|
|
|
created_time if created_time < timezone.now() else timezone.now()
|
|
|
|
)
|
2023-11-19 00:56:39 -05:00
|
|
|
review, created = cls.objects.update_or_create(
|
2023-07-20 21:59:49 -04:00
|
|
|
item=item, owner=owner, defaults=defaults
|
2023-08-10 11:27:31 -04:00
|
|
|
)
|
2024-06-13 23:02:12 -04:00
|
|
|
review.sync_to_timeline(delete_existing=delete_existing_post)
|
|
|
|
if share_to_mastodon:
|
|
|
|
review.sync_to_mastodon(delete_existing=delete_existing_post)
|
2023-12-27 17:29:21 -05:00
|
|
|
return review
|