diff --git a/catalog/models.py b/catalog/models.py index 75a92b05..9adb3054 100644 --- a/catalog/models.py +++ b/catalog/models.py @@ -7,6 +7,7 @@ from .game.models import Game from .podcast.models import Podcast from .performance.models import Performance from .collection.models import Collection as CatalogCollection +from django.contrib.contenttypes.models import ContentType # class Exhibition(Item): @@ -25,3 +26,20 @@ from .collection.models import Collection as CatalogCollection # class Meta: # proxy = True + + +CATEGORY_LIST = {} +CONTENT_TYPE_LIST = {} + + +def _init_item_subclasses(): + for cls in Item.__subclasses__(): + c = getattr(cls, 'category', None) + if c not in CATEGORY_LIST: + CATEGORY_LIST[c] = [cls] + else: + CATEGORY_LIST[c].append(cls) + CONTENT_TYPE_LIST[cls] = ContentType.objects.get(app_label='catalog', model=cls.__name__.lower()).id + + +_init_item_subclasses() diff --git a/catalog/sites/tmdb.py b/catalog/sites/tmdb.py index c6bd9d3e..ba7f7538 100644 --- a/catalog/sites/tmdb.py +++ b/catalog/sites/tmdb.py @@ -136,6 +136,7 @@ class TMDB_Movie(AbstractSite): @SiteManager.register class TMDB_TV(AbstractSite): + SITE_NAME = SiteName.TMDB ID_TYPE = IdType.TMDB_TV URL_PATTERNS = [r'\w+://www.themoviedb.org/tv/(\d+)[^/]*$', r'\w+://www.themoviedb.org/tv/(\d+)[^/]*/seasons'] WIKI_PROPERTY_ID = '?' @@ -246,6 +247,7 @@ class TMDB_TV(AbstractSite): @SiteManager.register class TMDB_TVSeason(AbstractSite): + SITE_NAME = SiteName.TMDB ID_TYPE = IdType.TMDB_TVSeason URL_PATTERNS = [r'\w+://www.themoviedb.org/tv/(\d+)[^/]*/season/(\d+)[^/]*$'] WIKI_PROPERTY_ID = '?' diff --git a/catalog/static/catalog.js b/catalog/static/catalog.js index 71fac978..00865dd7 100644 --- a/catalog/static/catalog.js +++ b/catalog/static/catalog.js @@ -1,6 +1,6 @@ function catalog_init(context) { // readonly star rating of detail display section - let ratingLabels = $("#main .rating-star", context); + let ratingLabels = $(".grid__main .rating-star", context); $(ratingLabels).each( function(index, value) { let ratingScore = $(this).data("rating-score") / 2; $(this).starRating({ diff --git a/catalog/templates/album.html b/catalog/templates/album.html index f57d2aa2..a6d04396 100644 --- a/catalog/templates/album.html +++ b/catalog/templates/album.html @@ -14,10 +14,10 @@ {% block details %}
- {% if item.rating and item.rating_number >= 5 %} + {% if item.rating and item.rating_count >= 5 %} {{ item.rating }} - ({{ item.rating_number }}人评分) + ({{ item.rating_count }}人评分) {% else %} {% trans '评分:评分人数不足' %} {% endif %} diff --git a/catalog/templates/edition.html b/catalog/templates/edition.html index 3b497936..abe4a2fe 100644 --- a/catalog/templates/edition.html +++ b/catalog/templates/edition.html @@ -62,7 +62,7 @@ {% endif %} - {% if item.last_editor and item.last_editor.preference.show_last_edit or user.is_staff %} + {% if item.last_editor and item.last_editor.preference.show_last_edit %}
{% trans '最近编辑者:' %}{{ item.last_editor | default:"" }}
{% endif %} diff --git a/catalog/templates/game.html b/catalog/templates/game.html index 0bfad623..3ca075a6 100644 --- a/catalog/templates/game.html +++ b/catalog/templates/game.html @@ -14,10 +14,10 @@ {% block details %}
- {% if item.rating and item.rating_number >= 5 %} + {% if item.rating and item.rating_count >= 5 %} {{ item.rating }} - ({{ item.rating_number }}人评分) + ({{ item.rating_count }}人评分) {% else %} {% trans '评分:评分人数不足' %} {% endif %} @@ -91,7 +91,7 @@ - {% if item.last_editor and item.last_editor.preference.show_last_edit or user.is_staff %} + {% if item.last_editor and item.last_editor.preference.show_last_edit %}
{% trans '最近编辑者:' %}{{ item.last_editor | default:"" }}
{% endif %} diff --git a/catalog/templates/movie.html b/catalog/templates/movie.html index c84d005d..4038e6d6 100644 --- a/catalog/templates/movie.html +++ b/catalog/templates/movie.html @@ -155,7 +155,7 @@ {% endif %} - {% if item.last_editor and item.last_editor.preference.show_last_edit or user.is_staff %} + {% if item.last_editor and item.last_editor.preference.show_last_edit %}
{% trans '最近编辑者:' %}{{ item.last_editor | default:"" }}
{% endif %} diff --git a/catalog/templates/tvseason.html b/catalog/templates/tvseason.html index d5cb0542..a30394b1 100644 --- a/catalog/templates/tvseason.html +++ b/catalog/templates/tvseason.html @@ -36,10 +36,10 @@ {% block details %}
- {% if item.rating and item.rating_number >= 5 %} + {% if item.rating and item.rating_count >= 5 %} {{ item.rating }} - ({{ item.rating_number }}人评分) + ({{ item.rating_count }}人评分) {% else %} {% trans '评分:评分人数不足' %} {% endif %} @@ -155,7 +155,7 @@ {% endif %} - {% if item.last_editor and item.last_editor.preference.show_last_edit or user.is_staff %} + {% if item.last_editor and item.last_editor.preference.show_last_edit %}
{% trans '最近编辑者:' %}{{ item.last_editor | default:"" }}
{% endif %} diff --git a/catalog/templates/tvshow.html b/catalog/templates/tvshow.html index d5cb0542..c23c99bc 100644 --- a/catalog/templates/tvshow.html +++ b/catalog/templates/tvshow.html @@ -36,10 +36,10 @@ {% block details %}
- {% if item.rating and item.rating_number >= 5 %} - - {{ item.rating }} - ({{ item.rating_number }}人评分) + {% if item.rating and item.rating_count >= 5 %} + + {{ item.rating | floatformat:1 }} + ({{ item.rating_count }}人评分) {% else %} {% trans '评分:评分人数不足' %} {% endif %} @@ -155,7 +155,7 @@ {% endif %} - {% if item.last_editor and item.last_editor.preference.show_last_edit or user.is_staff %} + {% if item.last_editor and item.last_editor.preference.show_last_edit %}
{% trans '最近编辑者:' %}{{ item.last_editor | default:"" }}
{% endif %} diff --git a/catalog/urls.py b/catalog/urls.py index d65ff69c..723fedf8 100644 --- a/catalog/urls.py +++ b/catalog/urls.py @@ -17,7 +17,7 @@ def _get_all_url_paths(): urlpatterns = [ - re_path(r'^item/(?P[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12})/?$', retrieve_by_uuid, name='retrieve_by_uuid'), + re_path(r'^item/(?P[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12})?$', retrieve_by_uuid, name='retrieve_by_uuid'), re_path(r'^(?P' + _get_all_url_paths() + ')/(?P[A-Za-z0-9]{21,22})$', retrieve, name='retrieve'), re_path(r'^(?P' + _get_all_url_paths() + ')/(?P[A-Za-z0-9]{21,22})/reviews', review_list, name='review_list'), re_path(r'^(?P' + _get_all_url_paths() + ')/(?P[A-Za-z0-9]{21,22})/marks(?:/(?P\\w+))?', mark_list, name='mark_list'), diff --git a/common/templates/partial/_sidebar.html b/common/templates/partial/_sidebar.html index bfe5a335..0458f39b 100644 --- a/common/templates/partial/_sidebar.html +++ b/common/templates/partial/_sidebar.html @@ -87,8 +87,8 @@ {% trans '更多' %}
- {% if tags %} - {% for t in tags %} + {% if top_tags %} + {% for t in top_tags %} {{ t }} diff --git a/journal/models.py b/journal/models.py index 4635d3fe..e0a53274 100644 --- a/journal/models.py +++ b/journal/models.py @@ -20,7 +20,9 @@ import uuid from catalog.common.utils import DEFAULT_ITEM_COVER, item_cover_path from django.utils.baseconv import base62 from django.db.models import Q +from catalog.models import * import mistune +from django.contrib.contenttypes.models import ContentType class VisibilityType(models.IntegerChoices): @@ -37,6 +39,16 @@ def query_following(user): return Q(owner_id__in=user.following, visibility__lt=2) | Q(owner_id=user.id) +def query_item_category(item_category): + classes = CATEGORY_LIST[item_category] + # q = Q(item__instance_of=classes[0]) + # for cls in classes[1:]: + # q = q | Q(instance_of=cls) + # return q + contenttype_ids = [CONTENT_TYPE_LIST[cls] for cls in classes] + return Q(item__polymorphic_ctype__in=sorted(contenttype_ids)) + + class Piece(PolymorphicModel, UserOwnedObjectMixin): url_path = 'piece' # subclass must specify this uid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True) @@ -67,6 +79,12 @@ class Piece(PolymorphicModel, UserOwnedObjectMixin): class Content(Piece): item = models.ForeignKey(Item, on_delete=models.PROTECT) + @cached_property + def mark(self): + m = Mark(self.owner, self.item) + m.review = self + return m + def __str__(self): return f"{self.uuid}@{self.item}" @@ -271,14 +289,17 @@ class ListMember(Piece): ListMember - List class's member class It's an abstract class, subclass must add this: - _list = models.ForeignKey('ListClass', related_name='members', on_delete=models.CASCADE) - - it starts with _ bc Django internally created OneToOne Field on Piece - https://docs.djangoproject.com/en/3.2/topics/db/models/#specifying-the-parent-link-field + parent = models.ForeignKey('List', related_name='members', on_delete=models.CASCADE) """ item = models.ForeignKey(Item, on_delete=models.PROTECT) position = models.PositiveIntegerField() + @cached_property + def mark(self): + m = Mark(self.owner, self.item) + m.shelfmember = self + return m + class Meta: abstract = True @@ -322,12 +343,6 @@ ShelfTypeNames = [ class ShelfMember(ListMember): parent = models.ForeignKey('Shelf', related_name='members', on_delete=models.CASCADE) - @ cached_property - def mark(self): - m = Mark(self.owner, self.item) - m.shelfmember = self - return m - class Shelf(List): class Meta: @@ -515,8 +530,8 @@ class TagManager: @ staticmethod def all_tags_for_user(user): - tags = user.tag_set.all().values('title').annotate(frequency=Count('members')).order_by('-frequency') - return sorted(list(map(lambda t: t['title'], tags))) + tags = user.tag_set.all().values('title').annotate(frequency=Count('members__id')).order_by('-frequency') + return list(map(lambda t: t['title'], tags)) @ staticmethod def tag_item_by_user(item, user, tag_titles, default_visibility=0): diff --git a/journal/templates/list_item_album.html b/journal/templates/list_item_album.html new file mode 100644 index 00000000..b005c54a --- /dev/null +++ b/journal/templates/list_item_album.html @@ -0,0 +1,21 @@ +{% extends "list_item_base.html" %} + +{% load i18n %} +{% load highlight %} + +{% block info %} +{% if item.artist %}{% trans '艺术家' %}: +{% for artist in item.artist %} +{{ artist }} +{% if not forloop.last %} {% endif %} +{% endfor %} +{% endif %} + +{% if item.genre %}/ {% trans '流派' %}: +{{ item.genre }} +{% endif %} + +{% if item.release_date %}/ {% trans '发行日期' %}: + {{ item.release_date }} +{% endif %} +{% endblock %} diff --git a/journal/templates/list_item_base.html b/journal/templates/list_item_base.html new file mode 100644 index 00000000..387b0f91 --- /dev/null +++ b/journal/templates/list_item_base.html @@ -0,0 +1,136 @@ +{# parameters: item, collection_edit, hide_category #} +{% load thumb %} +{% load highlight %} +{% load i18n %} +{% load l10n %} +{% load user_actions %} +{% wish_item_action item as action %} +
  • +
    + + + + {% if not action.taken %} + + {% endif %} +
    + +
    + {% if collection_edit %} +
    + {% if not forloop.first %} + + {% endif %} + {% if not forloop.last %} + + {% endif %} + +
    + {% endif %} + +
    + + + {% if request.GET.q %} + {{ item.title | highlight:request.GET.q }} + {% else %} + {{ item.title }} + {% endif %} + + {% if not request.GET.c and not hide_category %} + [{{item.category.label}}] + {% endif %} + {% for res in item.external_resources.all %} + + {{ res.site_name.label }} + + {% endfor %} +
    + + {% if item.rating %} +
    + {{ item.rating | floatformat:1 }} + {% else %} +
    {% trans '暂无评分' %}
    + {% endif %} + + + {% block info %} + {% endblock %} + + + {% block info_full %} + {% endblock %} + +

    + {{ item.brief }} +

    + +
    + {% for tag_dict in item.tags %} + + {{ tag_dict }} + + {% endfor %} +
    + + {% if mark %} +
    +
    +
    +
      +
    • + {% if mark.rating %} + + {% endif %} + {% if mark.visibility > 0 %} + + + + {% endif %} + + {% trans '标记于' %} {{ member.created_time }} + +

        + {% if mark.text %} + {{ mark.text }} + {% endif %} +

      +
    • + {% if mark.review %} +
    • + + {% trans '评论于' %} {{ mark.review.created_time }} + +

      + {{ mark.review.title }} + {% if mark.review.visibility > 0 %} + + + + {% endif %} +

      +
    • + {% endif %} +
    +
    + {% endif %} + + {% if collectionitem %} +
    +
    +
    +
      +
    • +

      + {% include "show_item_comment.html" %} +

      +
    • +
    +
    + {% endif %} +
    +
  • \ No newline at end of file diff --git a/journal/templates/list_item_edition.html b/journal/templates/list_item_edition.html new file mode 100644 index 00000000..3e2cc0e0 --- /dev/null +++ b/journal/templates/list_item_edition.html @@ -0,0 +1,51 @@ +{% extends "list_item_base.html" %} + +{% load i18n %} +{% load highlight %} + +{% block info %} +{% if item.pub_year %} / +{{ item.pub_year }}{% trans '年' %}{% if item.pub_month %}{{item.pub_month }}{% trans '月' %}{% endif %} +{% endif %} + +{% if item.author %} / +{% for author in item.author %} +{% if request.GET.q %} +{{ author | highlight:request.GET.q }} +{% else %} +{{ author }} +{% endif %} +{% if not forloop.last %},{% endif %} +{% endfor %} +{% endif %} + +{% if item.translator %} / +{% trans '翻译' %}: +{% for translator in item.translator %} +{% if request.GET.q %} +{{ translator | highlight:request.GET.q }} +{% else %} +{{ translator }} +{% endif %} +{% if not forloop.last %},{% endif %} +{% endfor %} +{% endif %} + +{% if item.subtitle %} / +{% trans '副标题' %}: +{% if request.GET.q %} +{{ item.subtitle | highlight:request.GET.q }} +{% else %} +{{ item.subtitle }} +{% endif %} +{% endif %} + +{% if item.orig_title %} / +{% trans '原名' %}: +{% if request.GET.q %} +{{ item.orig_title | highlight:request.GET.q }} +{% else %} +{{ item.orig_title }} +{% endif %} +{% endif %} +{% endblock %} diff --git a/journal/templates/list_item_game.html b/journal/templates/list_item_game.html new file mode 100644 index 00000000..46ed1aff --- /dev/null +++ b/journal/templates/list_item_game.html @@ -0,0 +1,32 @@ +{% extends "list_item_base.html" %} + +{% load i18n %} +{% load highlight %} + +{% block info %} + +{% if item.other_title %}{% trans '别名' %}: +{% for other_title in item.other_title %} +{{ other_title }}{% if not forloop.last %} {% endif %} +{% endfor %}/ +{% endif %} + +{% if item.developer %}{% trans '开发商' %}: +{% for developer in item.developer %} +{{ developer }}{% if not forloop.last %} {% endif %} +{% endfor %}/ +{% endif %} + +{% if item.genre %}{% trans '类型' %}: +{% for genre in item.genre %} +{{ genre }}{% if not forloop.last %} {% endif %} +{% endfor %}/ +{% endif %} + +{% if item.platform %}{% trans '平台' %}: +{% for platform in item.platform %} +{{ platform }}{% if not forloop.last %} {% endif %} +{% endfor %} +{% endif %} + +{% endblock %} diff --git a/journal/templates/list_item_movie.html b/journal/templates/list_item_movie.html new file mode 100644 index 00000000..c0d95136 --- /dev/null +++ b/journal/templates/list_item_movie.html @@ -0,0 +1,45 @@ +{% extends "list_item_base.html" %} + +{% load i18n %} +{% load highlight %} + +{% block info %} + +{% if item.director %}{% trans '导演' %}: +{% for director in item.director %} +{% if request.GET.q %} +{{ director | highlight:request.GET.q }} +{% else %} +{{ director }} +{% endif %} +{% if not forloop.last %},{% endif %} +{% endfor %}/ +{% endif %} + +{% if item.genre %}{% trans '类型' %}: +{% for genre in item.genre %} +{{ genre }}{% if not forloop.last %} {% endif %} +{% endfor %}/ +{% endif %} + +{% endblock %} + +{% block info_full %} + +{% if item.actor %}{% trans '主演' %}: +{% for actor in item.actor %} + 5 %}style="display: none;" {% endif %}> +{% if request.GET.q %} +{{ actor | highlight:request.GET.q }} +{% else %} +{{ actor }} +{% endif %} + +{% if forloop.counter <= 5 %} + {% if not forloop.counter == 5 and not forloop.last %} {% endif %} +{% endif %} +{% endfor %} +{% endif %} + + +{% endblock %} diff --git a/journal/templates/list_item_tvseason.html b/journal/templates/list_item_tvseason.html new file mode 100644 index 00000000..102dd69b --- /dev/null +++ b/journal/templates/list_item_tvseason.html @@ -0,0 +1,48 @@ +{% extends "list_item_base.html" %} + +{% load i18n %} +{% load highlight %} + +{% block info %} + +{% if item.director %}{% trans '导演' %}: +{% for director in item.director %} +{% if request.GET.q %} +{{ director | highlight:request.GET.q }} +{% else %} +{{ director }} +{% endif %} +{% if not forloop.last %},{% endif %} +{% endfor %}/ +{% endif %} + +{% if item.genre %}{% trans '类型' %}: +{% for genre in item.genre %} +{{ genre }}{% if not forloop.last %} {% endif %} +{% endfor %}/ +{% endif %} + +{% endblock %} + +{% block info_full %} + +{% if item.actor %}{% trans '主演' %}: +{% for actor in item.actor %} + 5 %}style="display: none;" {% endif %}> +{% if request.GET.q %} +{{ actor | highlight:request.GET.q }} +{% else %} +{{ actor }} +{% endif %} + +{% if forloop.counter <= 5 %} + {% if not forloop.counter == 5 and not forloop.last %} {% endif %} +{% endif %} +{% endfor %} +{% endif %} + +{% if item.show %} + +{% endif %} + +{% endblock %} diff --git a/journal/templates/list_item_tvshow.html b/journal/templates/list_item_tvshow.html new file mode 100644 index 00000000..b14c237f --- /dev/null +++ b/journal/templates/list_item_tvshow.html @@ -0,0 +1,46 @@ +{% extends "list_item_base.html" %} + +{% load i18n %} +{% load highlight %} + + +{% block info %} + +{% if item.director %}{% trans '导演' %}: +{% for director in item.director %} +{% if request.GET.q %} +{{ director | highlight:request.GET.q }} +{% else %} +{{ director }} +{% endif %} +{% if not forloop.last %},{% endif %} +{% endfor %}/ +{% endif %} + +{% if item.genre %}{% trans '类型' %}: +{% for genre in item.genre %} +{{ genre }}{% if not forloop.last %} {% endif %} +{% endfor %}/ +{% endif %} + +{% endblock %} + +{% block info_full %} + +{% if item.actor %}{% trans '主演' %}: +{% for actor in item.actor %} + 5 %}style="display: none;" {% endif %}> +{% if request.GET.q %} +{{ actor | highlight:request.GET.q }} +{% else %} +{{ actor }} +{% endif %} + +{% if forloop.counter <= 5 %} + {% if not forloop.counter == 5 and not forloop.last %} {% endif %} +{% endif %} +{% endfor %} +{% endif %} + + +{% endblock %} diff --git a/journal/templates/user_item_list_base.html b/journal/templates/user_item_list_base.html new file mode 100644 index 00000000..96c124fb --- /dev/null +++ b/journal/templates/user_item_list_base.html @@ -0,0 +1,92 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} + + + + + + + {% block title %} + {{ site_name }} - {{ user.mastodon_username }} + {% endblock %} + {% include "common_libs.html" with jquery=1 %} + + + +
    +
    + {% include "partial/_navbar.html" %} + +
    +
    +
    +
    +
    + +
    +
    + {% block head %} + {{ user.mastodon_username }} + {% endblock %} +
    +
    +
      + {% for member in members %} + {% with "list_item_"|add:member.item.class_name|add:".html" as template %} + {% include template with item=member.item mark=member.mark hide_category=True %} + {% endwith %} + {% empty %} +
      {% trans '无结果' %}
      + {% endfor %} +
    +
    + +
    +
    + + {% include "partial/_sidebar.html" %} +
    +
    +
    + {% include "partial/_footer.html" %} +
    + + + + + + diff --git a/journal/templates/user_mark_list.html b/journal/templates/user_mark_list.html new file mode 100644 index 00000000..cb526c3a --- /dev/null +++ b/journal/templates/user_mark_list.html @@ -0,0 +1,10 @@ +{% extends "user_item_list_base.html" %} +{% load i18n %} + +{% block title%} +{{ site_name }} - {{ user.mastodon_username }} - {% trans '标记' %} +{% endblock %} + +{% block head %} +{{ user.mastodon_username }} - {% trans '标记' %} +{% endblock %} diff --git a/journal/templates/user_review_list.html b/journal/templates/user_review_list.html new file mode 100644 index 00000000..64d39e36 --- /dev/null +++ b/journal/templates/user_review_list.html @@ -0,0 +1,10 @@ +{% extends "user_item_list_base.html" %} +{% load i18n %} + +{% block title%} +{{ site_name }} - {{ user.mastodon_username }} - {% trans '评论' %} +{% endblock %} + +{% block head %} +{{ user.mastodon_username }} - {% trans '评论' %} +{% endblock %} diff --git a/journal/templates/user_tag_list.html b/journal/templates/user_tag_list.html new file mode 100644 index 00000000..1c9efa3f --- /dev/null +++ b/journal/templates/user_tag_list.html @@ -0,0 +1,65 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load humanize %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load highlight %} +{% load thumb %} + + + + + + + {{ site_name }} - 我的标签 + {% include "common_libs.html" with jquery=1 %} + + + +
    +
    + {% include "partial/_navbar.html" %} + +
    +
    +
    +
    +
    +
    +
    {% trans '全部标签' %}
    + {% for v in tags %} + + + {{ v.title }} + + ({{ v.total }}) + + {% empty %} + {% trans '暂无标签' %} + {% endfor %} +
    +
    +
    +
    +
    + + {% include "partial/_sidebar.html" %} + +
    +
    +
    + {% include "partial/_footer.html" %} +
    + + + + + + + + diff --git a/journal/templates/user_tagmember_list.html b/journal/templates/user_tagmember_list.html new file mode 100644 index 00000000..82e691e2 --- /dev/null +++ b/journal/templates/user_tagmember_list.html @@ -0,0 +1,10 @@ +{% extends "user_item_list_base.html" %} +{% load i18n %} + +{% block title%} +{{ site_name }} - {{ user.mastodon_username }} - {% trans '标签' %} +{% endblock %} + +{% block head %} +{{ user.mastodon_username }} - {% trans '标签' %} +{% endblock %} diff --git a/journal/urls.py b/journal/urls.py index 434f7796..af4c5d68 100644 --- a/journal/urls.py +++ b/journal/urls.py @@ -1,8 +1,20 @@ from django.urls import path, re_path from .views import * +from catalog.models import * app_name = 'journal' + + +def _get_all_categories(): + res = "|".join(CATEGORY_LIST.keys()) + return res + + +def _get_all_shelf_types(): + return "|".join(ShelfType.values) + + urlpatterns = [ path('wish/', wish, name='wish'), path('like/', like, name='like'), @@ -13,4 +25,12 @@ urlpatterns = [ path('review/create//', review_edit, name='review_create'), path('review/edit//', review_edit, name='review_edit'), path('review/delete/', review_delete, name='review_delete'), + + re_path(r'^user/(?P[A-Za-z0-0_\-.@]+)/(?P' + _get_all_shelf_types() + ')/(?P' + _get_all_categories() + ')/$', user_mark_list, name='user_mark_list'), + re_path(r'^user/(?P[A-Za-z0-0_\-.@]+)/reviews/(?P' + _get_all_categories() + ')/$', user_review_list, name='user_review_list'), + re_path(r'^user/(?P[A-Za-z0-0_\-.@]+)/tags/(?P[^/]+)/$', user_tag_member_list, name='user_tag_member_list'), + re_path(r'^user/(?P[A-Za-z0-0_\-.@]+)/collections/$', user_collection_list, name='user_collection_list'), + re_path(r'^user/(?P[A-Za-z0-0_\-.@]+)/like/collections/$', user_liked_collection_list, name='user_liked_collection_list'), + re_path(r'^user/(?P[A-Za-z0-0_\-.@]+)/tags/$', user_tag_list, name='user_tag_list'), + ] diff --git a/journal/views.py b/journal/views.py index c9015cb0..08daefdb 100644 --- a/journal/views.py +++ b/journal/views.py @@ -19,6 +19,7 @@ from management.models import Announcement from django.utils.baseconv import base62 from .forms import * from mastodon.api import share_review +from users.views import render_user_blocked, render_user_not_found _logger = logging.getLogger(__name__) @@ -71,7 +72,7 @@ def add_to_collection(request, item_uuid): return HttpResponseRedirect(request.META.get('HTTP_REFERER')) -def go_relogin(request): +def render_relogin(request): return render(request, 'common/error.html', { 'url': reverse("users:connect") + '?domain=' + request.user.mastodon_site, 'msg': _("信息已保存,但是未能分享到联邦网络"), @@ -110,7 +111,7 @@ def mark(request, item_uuid): try: mark.update(status, text, rating, visibility, share_to_mastodon=share_to_mastodon) except Exception: - go_relogin(request) + return render_relogin(request) return HttpResponseRedirect(request.META.get('HTTP_REFERER')) @@ -141,7 +142,7 @@ def review_edit(request, item_uuid, review_uuid=None): form.instance.save = lambda **args: None form.instance.shared_link = None if not share_review(form.instance): - return go_relogin(request) + return render_relogin(request) return redirect(reverse("journal:review_retrieve", args=[form.instance.uuid])) else: return HttpResponseBadRequest(form.errors) @@ -165,18 +166,115 @@ def review_delete(request, review_uuid): return HttpResponseBadRequest() -def mark_list(request, shelf_type, item_category): - pass +def render_list_not_fount(request): + msg = _("相关列表不存在") + return render( + request, + 'common/error.html', + { + 'msg': msg, + } + ) -def review_list(request): - pass - - -def collection_list(request): - pass +def _render_list(request, user_name, type, shelf_type=None, item_category=None, tag_title=None): + user = User.get(user_name) + if user is None: + return render_user_not_found(request) + if user != request.user and (request.user.is_blocked_by(user) or request.user.is_blocking(user)): + return render_user_blocked(request) + if type == 'mark': + shelf = user.shelf_manager.get_shelf(item_category, shelf_type) + queryset = ShelfMember.objects.filter(owner=user, parent=shelf) + elif type == 'tagmember': + tag = Tag.objects.filter(owner=user, title=tag_title).first() + if not tag: + return render_list_not_fount(request) + if tag.visibility != 0 and user != request.user: + return render_list_not_fount(request) + queryset = TagMember.objects.filter(parent=tag) + elif type == 'review': + queryset = Review.objects.filter(owner=user) + queryset = queryset.filter(query_item_category(item_category)) + else: + return HttpResponseBadRequest() + if user != request.user: + if request.user.is_following(user): + queryset = queryset.filter(visibility__ne=2) + else: + queryset = queryset.filter(visibility=0) + paginator = Paginator(queryset, PAGE_SIZE) + page_number = request.GET.get('page', default=1) + members = paginator.get_page(page_number) + return render(request, f'user_{type}_list.html', { + 'user': user, + 'members': members, + }) @login_required -def liked_list(request): - pass +def user_mark_list(request, user_name, shelf_type, item_category): + return _render_list(request, user_name, 'mark', shelf_type=shelf_type, item_category=item_category) + + +@login_required +def user_tag_member_list(request, user_name, tag_title): + return _render_list(request, user_name, 'tagmember', tag_title=tag_title) + + +@login_required +def user_review_list(request, user_name, item_category): + return _render_list(request, user_name, 'review', item_category=item_category) + + +@login_required +def user_tag_list(request, user_name): + user = User.get(user_name) + if user is None: + return render_user_not_found(request) + if user != request.user and (request.user.is_blocked_by(user) or request.user.is_blocking(user)): + return render_user_blocked(request) + tags = Tag.objects.filter(owner=user) + tags = user.tag_set.all() + if user != request.user: + tags = tags.filter(visibility=0) + tags = tags.values('title').annotate(total=Count('members')).order_by('-total') + return render(request, f'user_tag_list.html', { + 'user': user, + 'tags': tags, + }) + + +@login_required +def user_collection_list(request, user_name): + user = User.get(user_name) + if user is None: + return render_user_not_found(request) + if user != request.user and (request.user.is_blocked_by(user) or request.user.is_blocking(user)): + return render_user_blocked(request) + collections = Tag.objects.filter(owner=user) + if user != request.user: + if request.user.is_following(user): + collections = collections.filter(visibility__ne=2) + else: + collections = collections.filter(visibility=0) + return render(request, f'user_collection_list.html', { + 'user': user, + 'collections': collections, + }) + + +@login_required +def user_liked_collection_list(request, user_name): + user = User.get(user_name) + if user is None: + return render_user_not_found(request) + if user != request.user and (request.user.is_blocked_by(user) or request.user.is_blocking(user)): + return render_user_blocked(request) + collections = Collection.objects.filter(likes__owner=user) + if user != request.user: + collections = collections.filter(query_visible(request.user)) + return render(request, f'user_collection_list.html', { + 'user': user, + 'collections': collections, + }) diff --git a/social/templates/activity/review_item.html b/social/templates/activity/review_item.html new file mode 100644 index 00000000..0bc0b45b --- /dev/null +++ b/social/templates/activity/review_item.html @@ -0,0 +1,54 @@ +{% load static %} +{% load i18n %} +{% load l10n %} +{% load admin_url %} +{% load mastodon %} +{% load oauth_token %} +{% load truncate %} +{% load thumb %} +{% load prettydate %} +{% load user_actions %} + +{% wish_item_action activity.action_object.item as action %} + +
    + + + + {% if not action.take %} + + {% endif %} +
    +
    +
    + + {% if activity.action_object.metadata.shared_link %} + + + {{ activity.action_object.created_time|prettydate }} + {% else %} + {{ activity.action_object.created_time|prettydate }} + {% endif %} + +
    + + {{ activity.owner.display_name }} {% trans '评论了' %} + {{ activity.action_object.item.title }} + {% if activity.action_object.item.year %}({{ activity.action_object.item.year }}){% endif %} + + + +

    + {% if activity.action_object.review %} + {{ activity.review.title }} + {% endif %} + {% if activity.action_object.rating_grade %} + + {% endif %} +

    + +

    +

    +
    \ No newline at end of file diff --git a/social/views.py b/social/views.py index 412e507e..cbeb5bc8 100644 --- a/social/views.py +++ b/social/views.py @@ -34,7 +34,7 @@ def feed(request): request, 'feed.html', { - 'tags': user.tag_manager.all_tags[:10], + 'top_tags': user.tag_manager.all_tags[:10], 'unread_announcements': unread, } ) diff --git a/users/views.py b/users/views.py index e216f806..838ebc5e 100644 --- a/users/views.py +++ b/users/views.py @@ -56,6 +56,17 @@ def render_user_not_found(request): ) +def render_user_blocked(request): + msg = _("你没有访问TA主页的权限😥") + return render( + request, + 'common/error.html', + { + 'msg': msg, + } + ) + + def home_redirect(request, id): try: query_kwargs = {'pk': id} @@ -93,7 +104,7 @@ def home(request, id): reports = Report.objects.order_by( '-submitted_time').filter(is_read=False) unread_announcements = Announcement.objects.filter( - pk__gt=request.user.read_announcement_index).order_by('-pk') + pk__gt=request.user.read_announcement_index).order_by('-pk') try: request.user.read_announcement_index = Announcement.objects.latest( 'pk').pk @@ -510,14 +521,7 @@ def music_list(request, id, status): tag = request.GET.get('t', default='') if not user == request.user: if request.user.is_blocked_by(user) or request.user.is_blocking(user): - msg = _("你没有访问TA主页的权限😥") - return render( - request, - 'common/error.html', - { - 'msg': msg, - } - ) + return render_user_blocked(request) is_following = request.user.is_following(user) if status == 'reviewed': queryset = list(AlbumReview.get_available_by_user(user, is_following).order_by("-edited_time")) + \ @@ -527,7 +531,7 @@ def music_list(request, id, status): else: queryset = list(AlbumMark.get_available_by_user(user, is_following).filter( status=MarkStatusEnum[status.upper()])) \ - + list(SongMark.get_available_by_user(user, is_following).filter( + + list(SongMark.get_available_by_user(user, is_following).filter( status=MarkStatusEnum[status.upper()])) else: if status == 'reviewed':