2023-08-10 11:27:31 -04:00
|
|
|
import re
|
|
|
|
import uuid
|
|
|
|
from functools import cached_property
|
|
|
|
|
|
|
|
import django.dispatch
|
|
|
|
from django.conf import settings
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
from django.core.exceptions import PermissionDenied
|
|
|
|
from django.core.validators import MaxValueValidator, MinValueValidator, RegexValidator
|
|
|
|
from django.db import connection, models
|
|
|
|
from django.db.models import Avg, Count, Q
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils.baseconv import base62
|
|
|
|
from django.utils.translation import gettext_lazy as _
|
2023-07-20 21:59:49 -04:00
|
|
|
from loguru import logger
|
2023-08-10 11:27:31 -04:00
|
|
|
from markdownx.models import MarkdownxField
|
|
|
|
from polymorphic.models import PolymorphicModel
|
|
|
|
|
|
|
|
from catalog.collection.models import Collection as CatalogCollection
|
|
|
|
from catalog.common import jsondata
|
|
|
|
from catalog.common.models import Item, ItemCategory
|
|
|
|
from catalog.common.utils import DEFAULT_ITEM_COVER, piece_cover_path
|
|
|
|
from catalog.models import *
|
2023-07-20 21:59:49 -04:00
|
|
|
from takahe.utils import Takahe
|
|
|
|
from users.models import APIdentity
|
2023-08-10 11:27:31 -04:00
|
|
|
|
|
|
|
from .comment import Comment
|
|
|
|
from .rating import Rating
|
|
|
|
from .review import Review
|
|
|
|
from .shelf import Shelf, ShelfLogEntry, ShelfManager, ShelfMember, ShelfType
|
|
|
|
|
|
|
|
|
|
|
|
class Mark:
|
|
|
|
"""
|
|
|
|
Holding Mark for an item on an shelf,
|
|
|
|
which is a combo object of ShelfMember, Comment, Rating and Tags.
|
|
|
|
it mimics previous mark behaviour.
|
|
|
|
"""
|
|
|
|
|
2023-07-20 21:59:49 -04:00
|
|
|
def __init__(self, owner: APIdentity, item: Item):
|
|
|
|
self.owner = owner
|
2023-08-10 11:27:31 -04:00
|
|
|
self.item = item
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def shelfmember(self) -> ShelfMember:
|
|
|
|
return self.owner.shelf_manager.locate_item(self.item)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def id(self) -> int | None:
|
|
|
|
return self.shelfmember.id if self.shelfmember else None
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def shelf(self) -> Shelf | None:
|
|
|
|
return self.shelfmember.parent if self.shelfmember else None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def shelf_type(self) -> ShelfType | None:
|
|
|
|
return self.shelfmember.parent.shelf_type if self.shelfmember else None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def action_label(self) -> str:
|
2023-07-20 21:59:49 -04:00
|
|
|
if self.shelfmember and self.shelf_type:
|
2023-08-10 11:27:31 -04:00
|
|
|
return ShelfManager.get_action_label(self.shelf_type, self.item.category)
|
|
|
|
if self.comment:
|
|
|
|
return ShelfManager.get_action_label(
|
|
|
|
ShelfType.PROGRESS, self.comment.item.category
|
|
|
|
)
|
|
|
|
return ""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def shelf_label(self) -> str | None:
|
|
|
|
return (
|
|
|
|
ShelfManager.get_label(self.shelf_type, self.item.category)
|
2023-07-20 21:59:49 -04:00
|
|
|
if self.shelf_type
|
2023-08-10 11:27:31 -04:00
|
|
|
else None
|
|
|
|
)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def created_time(self):
|
|
|
|
return self.shelfmember.created_time if self.shelfmember else None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def metadata(self) -> dict | None:
|
|
|
|
return self.shelfmember.metadata if self.shelfmember else None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def visibility(self) -> int:
|
2023-07-20 21:59:49 -04:00
|
|
|
if self.shelfmember:
|
|
|
|
return self.shelfmember.visibility
|
|
|
|
else:
|
|
|
|
logger.warning(f"no shelfmember for mark {self.owner}, {self.item}")
|
|
|
|
return 2
|
2023-08-10 11:27:31 -04:00
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def tags(self) -> list[str]:
|
|
|
|
return self.owner.tag_manager.get_item_tags(self.item)
|
|
|
|
|
2023-07-20 21:59:49 -04:00
|
|
|
@cached_property
|
|
|
|
def rating(self):
|
|
|
|
return Rating.objects.filter(owner=self.owner, item=self.item).first()
|
|
|
|
|
2023-08-10 11:27:31 -04:00
|
|
|
@cached_property
|
|
|
|
def rating_grade(self) -> int | None:
|
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
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def comment(self) -> Comment | None:
|
|
|
|
return Comment.objects.filter(owner=self.owner, item=self.item).first()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def comment_text(self) -> str | None:
|
|
|
|
return (self.comment.text or None) if self.comment else None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def comment_html(self) -> str | None:
|
|
|
|
return self.comment.html if self.comment else None
|
|
|
|
|
|
|
|
@cached_property
|
|
|
|
def review(self) -> Review | None:
|
|
|
|
return Review.objects.filter(owner=self.owner, item=self.item).first()
|
|
|
|
|
|
|
|
def update(
|
|
|
|
self,
|
2023-07-20 21:59:49 -04:00
|
|
|
shelf_type,
|
|
|
|
comment_text,
|
|
|
|
rating_grade,
|
|
|
|
visibility,
|
2023-08-10 11:27:31 -04:00
|
|
|
metadata=None,
|
|
|
|
created_time=None,
|
|
|
|
share_to_mastodon=False,
|
|
|
|
):
|
2023-07-20 21:59:49 -04:00
|
|
|
post_to_feed = shelf_type is not None and (
|
|
|
|
shelf_type != self.shelf_type
|
|
|
|
or comment_text != self.comment_text
|
|
|
|
or rating_grade != self.rating_grade
|
2023-08-10 11:27:31 -04:00
|
|
|
)
|
2023-07-20 21:59:49 -04:00
|
|
|
if shelf_type is None:
|
|
|
|
Takahe.delete_mark(self)
|
2023-08-10 11:27:31 -04:00
|
|
|
if created_time and created_time >= timezone.now():
|
|
|
|
created_time = None
|
2023-07-20 21:59:49 -04:00
|
|
|
post_as_new = shelf_type != self.shelf_type
|
2023-08-10 11:27:31 -04:00
|
|
|
original_visibility = self.visibility
|
|
|
|
if shelf_type != self.shelf_type or visibility != original_visibility:
|
|
|
|
self.shelfmember = self.owner.shelf_manager.move_item(
|
|
|
|
self.item,
|
|
|
|
shelf_type,
|
|
|
|
visibility=visibility,
|
|
|
|
metadata=metadata,
|
|
|
|
)
|
2023-07-20 21:59:49 -04:00
|
|
|
if self.shelfmember and created_time:
|
2023-08-10 11:27:31 -04:00
|
|
|
# if it's an update(not delete) and created_time is specified,
|
|
|
|
# update the timestamp of the shelfmember and log
|
|
|
|
log = ShelfLogEntry.objects.filter(
|
|
|
|
owner=self.owner,
|
|
|
|
item=self.item,
|
|
|
|
timestamp=self.shelfmember.created_time,
|
|
|
|
).first()
|
|
|
|
self.shelfmember.created_time = created_time
|
|
|
|
self.shelfmember.save(update_fields=["created_time"])
|
|
|
|
if log:
|
|
|
|
log.timestamp = created_time
|
|
|
|
log.save(update_fields=["timestamp"])
|
|
|
|
else:
|
|
|
|
ShelfLogEntry.objects.create(
|
|
|
|
owner=self.owner,
|
|
|
|
shelf_type=shelf_type,
|
|
|
|
item=self.item,
|
|
|
|
metadata=self.metadata,
|
|
|
|
timestamp=created_time,
|
|
|
|
)
|
|
|
|
if comment_text != self.comment_text or visibility != original_visibility:
|
2023-07-20 21:59:49 -04:00
|
|
|
self.comment = Comment.comment_item(
|
2023-08-10 11:27:31 -04:00
|
|
|
self.item,
|
|
|
|
self.owner,
|
|
|
|
comment_text,
|
|
|
|
visibility,
|
|
|
|
self.shelfmember.created_time if self.shelfmember else None,
|
|
|
|
)
|
|
|
|
if rating_grade != self.rating_grade or visibility != original_visibility:
|
2023-07-20 21:59:49 -04:00
|
|
|
Rating.update_item_rating(self.item, self.owner, rating_grade, visibility)
|
2023-08-10 11:27:31 -04:00
|
|
|
self.rating_grade = rating_grade
|
2023-07-20 21:59:49 -04:00
|
|
|
|
|
|
|
if post_to_feed:
|
|
|
|
Takahe.post_mark(self, post_as_new)
|
|
|
|
|
|
|
|
def delete(self):
|
2023-08-10 11:27:31 -04:00
|
|
|
# self.logs.delete() # When deleting a mark, all logs of the mark are deleted first.
|
2023-07-20 21:59:49 -04:00
|
|
|
self.update(None, None, None, 0)
|
2023-08-10 11:27:31 -04:00
|
|
|
|
|
|
|
def delete_log(self, log_id):
|
|
|
|
ShelfLogEntry.objects.filter(
|
|
|
|
owner=self.owner, item=self.item, id=log_id
|
|
|
|
).delete()
|
|
|
|
|
|
|
|
def delete_all_logs(self):
|
|
|
|
self.logs.delete()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def logs(self):
|
|
|
|
return ShelfLogEntry.objects.filter(owner=self.owner, item=self.item).order_by(
|
|
|
|
"timestamp"
|
|
|
|
)
|