diff --git a/catalog/search/views.py b/catalog/search/views.py index 2e3c7ee8..1e77a59a 100644 --- a/catalog/search/views.py +++ b/catalog/search/views.py @@ -175,7 +175,10 @@ def external_search(request): ) +@login_required def refetch(request): + if request.method != "POST": + return HttpResponseBadRequest() url = request.POST.get("url") if not url: return HttpResponseBadRequest() diff --git a/catalog/templates/album.html b/catalog/templates/album.html index b3289fc3..9dfcf2f4 100644 --- a/catalog/templates/album.html +++ b/catalog/templates/album.html @@ -105,9 +105,6 @@ {% if user.is_authenticated %} {% trans '编辑' %}{{ item.demonstrative }} {% endif %} - {% if user.is_staff %} - / {% trans '删除' %} - {% endif %} {% endblock %} diff --git a/catalog/templates/catalog_edit.html b/catalog/templates/catalog_edit.html index 9bfa346c..c43fc57d 100644 --- a/catalog/templates/catalog_edit.html +++ b/catalog/templates/catalog_edit.html @@ -23,6 +23,7 @@
+ {% if item %}
{% for res in form.instance.external_resources.all %}
@@ -32,23 +33,63 @@ {% csrf_token %} - +
+ {% if request.user.is_staff %} +
+
+ {% csrf_token %} + + +
+
+ {% endif %}
{% endfor %}
+ + {% if request.user.is_staff %} +
+
+
{% trans '合并到另一条目' %}
+
+
+ {% csrf_token %} +
+ +
+
+
+ +
+
{% trans '删除' %}
+
+
+ {% csrf_token %} + +
+
+
+ + {% if item.is_deteled %} + + {% endif %} +
+ {% endif %} + + {% endif %}
-
- {% csrf_token %} - {{ form.media }} - {{ form }} -
- - 返回 -
-
+
+ {% csrf_token %} + {{ form.media }} + {{ form }} +
+ + 返回 +
+
diff --git a/catalog/templates/edition.html b/catalog/templates/edition.html index e1455579..af058098 100644 --- a/catalog/templates/edition.html +++ b/catalog/templates/edition.html @@ -41,8 +41,8 @@
{% if item.translator %}{% trans '译者:' %} {% for translator in item.translator %} {{ translator }}{% if not forloop.last %} / {% endif %} - {% endfor %} - {% endif %}
+ {% endfor %} + {% endif %}
{% if item.orig_title %}{% trans '原作名:' %}{{ item.orig_title }}{% endif %}
{% if item.language %}{% trans '语言:' %}{{ item.language }}{% endif %}
{%if item.pub_year %}{% trans '出版时间:' %}{{ item.pub_year }}{% trans '年' %}{% if item.pub_month %}{{ item.pub_month }}{% trans '月' %}{% endif %}{% endif %}
@@ -53,7 +53,7 @@
{% if item.price %}{% trans '定价:' %}{{ item.price }}{% endif %}
{% if item.pages %}{% trans '页数:' %}{{ item.pages }}{% endif %}
{% if item.imprint %}{% trans '出品方:' %}{{ item.imprint }}{% endif %}
- {% if item.other_info %} + {% if item.other_info %} {% for k, v in item.other_info.items %}
{{ k }}:{{ v | urlize }} @@ -70,9 +70,6 @@ {% if user.is_authenticated %} {% trans '编辑' %}{{ item.demonstrative }} {% endif %} - {% if user.is_staff %} - / {% trans '删除' %} - {% endif %}
{% endblock %} diff --git a/catalog/templates/item_base.html b/catalog/templates/item_base.html index dd7724f2..762439e7 100644 --- a/catalog/templates/item_base.html +++ b/catalog/templates/item_base.html @@ -45,6 +45,12 @@
+ {% if item.is_deleted %} + [DELETED] + {% endif %} + {% if item.merged_to_item %} + [MERGED] {{ item.merged_to_item.title }} + {% endif %} {% block title %}
{{ item.title }} @@ -122,7 +128,7 @@ {% trans '全部标记' %} 关注的人的标记 {% endif %} - +
{% endblock %} diff --git a/catalog/urls.py b/catalog/urls.py index b2595f96..f71a4d57 100644 --- a/catalog/urls.py +++ b/catalog/urls.py @@ -69,5 +69,6 @@ urlpatterns = [ path("search/external/", external_search, name="external_search"), path("fetch_refresh/", fetch_refresh, name="fetch_refresh"), path("refetch", refetch, name="refetch"), + path("unlink", unlink, name="unlink"), path("api/", api.urls), ] diff --git a/catalog/views.py b/catalog/views.py index e1bc3e24..63afe1a1 100644 --- a/catalog/views.py +++ b/catalog/views.py @@ -17,6 +17,7 @@ from django.db.models import Count from django.utils import timezone from django.core.paginator import Paginator from polymorphic.base import django +from catalog.common.models import ExternalResource from catalog.common.sites import AbstractSite, SiteManager from mastodon import mastodon_request_included from mastodon.models import MastodonApplication @@ -58,6 +59,11 @@ def retrieve(request, item_path, item_uuid): item_url = f"/{item_path}/{item_uuid}" if item.url != item_url: return redirect(item.url) + skipcheck = request.GET.get("skipcheck", False) and request.user.is_staff + if not skipcheck and item.merged_to_item: + return redirect(item.merged_to_item.url) + if not skipcheck and item.is_deleted: + return HttpResponseNotFound("item not found") mark = None review = None mark_list = None @@ -148,7 +154,7 @@ def edit(request, item_path, item_uuid): "catalog_edit.html", { "form": form, - "is_update": True, + "item": item, }, ) elif request.method == "POST": @@ -176,7 +182,29 @@ def delete(request, item_path, item_uuid): return HttpResponseBadRequest() if not request.user.is_staff: raise PermissionDenied() - return HttpResponseBadRequest() + item = get_object_or_404(Item, uid=base62.decode(item_uuid)) + for res in item.external_resources.all(): + res.item = None + res.save() + item.delete() + return ( + redirect(item.url + "?skipcheck=1") if request.user.is_staff else redirect("/") + ) + + +@login_required +def unlink(request): + if request.method != "POST": + return HttpResponseBadRequest() + if not request.user.is_staff: + raise PermissionDenied() + res_id = request.POST.get("id") + if not res_id: + return HttpResponseBadRequest() + resource = get_object_or_404(ExternalResource, id=res_id) + resource.item = None + resource.save() + return HttpResponseRedirect(request.META.get("HTTP_REFERER")) @login_required @@ -189,6 +217,7 @@ def merge(request, item_path, item_uuid): new_item = Item.get_by_url(request.POST.get("new_item_url")) if not new_item or new_item.is_deleted or new_item.merged_to_item_id: return HttpResponseBadRequest(b"invalid new item") + _logger.warn(f"{request.user} merges {item} to {new_item}") item.merge_to(new_item) update_journal_for_merged_item(item_uuid) return redirect(new_item.url) diff --git a/journal/migrations/0008_alter_shelfmember_unique_together.py b/journal/migrations/0008_alter_shelfmember_unique_together.py new file mode 100644 index 00000000..285084e8 --- /dev/null +++ b/journal/migrations/0008_alter_shelfmember_unique_together.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.16 on 2023-01-23 05:05 + +from django.conf import settings +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("catalog", "0002_initial"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ("journal", "0007_alter_collection_catalog_item"), + ] + + operations = [ + migrations.AlterUniqueTogether( + name="shelfmember", + unique_together={("owner", "item")}, + ), + ] diff --git a/journal/models.py b/journal/models.py index bcdc6b99..3733f0d4 100644 --- a/journal/models.py +++ b/journal/models.py @@ -96,7 +96,7 @@ def query_item_category(item_category): class Piece(PolymorphicModel, UserOwnedObjectMixin): - url_path = "piece" # subclass must specify this + url_path = "p" # subclass must specify this uid = models.UUIDField(default=uuid.uuid4, editable=False, db_index=True) @property @@ -494,7 +494,7 @@ class ShelfMember(ListMember): ) class Meta: - unique_together = [["parent", "item"]] + unique_together = [["owner", "item"]] @cached_property def mark(self): @@ -1054,12 +1054,13 @@ def update_journal_for_merged_item(legacy_item_uuid): _logger.error("update_journal_for_merged_item: unable to find item") return new_item = legacy_item.merged_to_item - for cls in Content.__subclasses__ + ListMember.__subclasses__: - _logger.info(f"update {cls.__name__}: {legacy_item} -> {new_item}") + for cls in list(Content.__subclasses__()) + list(ListMember.__subclasses__()): for p in cls.objects.filter(item=legacy_item): try: p.item = new_item p.save(update_fields=["item_id"]) except: - _logger.info(f"delete duplicated piece {p}") + _logger.warn( + f"deleted piece {p} when merging {cls.__name__}: {legacy_item} -> {new_item}" + ) p.delete()