From 86289bdaab703ad772b42212c0edc15e1ea0f127 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 28 Jun 2023 23:25:36 -0400 Subject: [PATCH] fix potential missing match when link ExternalResource to Item --- catalog/common/models.py | 10 ++++++---- catalog/common/sites.py | 21 ++++++++++++++++++--- catalog/templates/_sidebar_edit.html | 3 ++- catalog/views_edit.py | 12 ++++++++++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/catalog/common/models.py b/catalog/common/models.py index eb2173ec..579b5b43 100644 --- a/catalog/common/models.py +++ b/catalog/common/models.py @@ -342,16 +342,16 @@ class Item(SoftDeleteMixin, PolymorphicModel): ) def merge_to(self, to_item): - self.log_action({"!merged": [str(self.merged_to_item), str(to_item)]}) if to_item is None: if self.merged_to_item is not None: self.merged_to_item = None self.save() return - elif to_item.merged_to_item is not None: - raise ValueError("cannot merge with an item aleady merged") + if to_item.merged_to_item is not None: + raise ValueError("cannot merge to item which is merged to another item") if to_item.__class__ != self.__class__: - _logger.warn(f"merging item across class from {self} to {to_item}") + raise ValueError(f"cannot merge to item in a different model") + self.log_action({"!merged": [str(self.merged_to_item), str(to_item)]}) self.merged_to_item = to_item self.save() for res in self.external_resources.all(): @@ -530,6 +530,8 @@ class ExternalResource(models.Model): return f"{self.pk}:{self.id_type}:{self.id_value or ''} ({self.url})" def unlink_from_item(self): + if not self.item: + return self.item.log_action({"!unlink": [str(self), None]}) self.item = None self.save() diff --git a/catalog/common/sites.py b/catalog/common/sites.py index 986e603a..09f5493e 100644 --- a/catalog/common/sites.py +++ b/catalog/common/sites.py @@ -8,7 +8,7 @@ ResourceContent persists as an ExternalResource which may link to an Item """ from typing import Callable import re -from .models import ExternalResource, IdType, Item +from .models import ExternalResource, IdType, IdealIdTypes, Item from dataclasses import dataclass, field import logging import json @@ -122,6 +122,21 @@ class AbstractSite: matched = model.objects.filter( primary_lookup_id_type=t, primary_lookup_id_value=v ).first() + if matched is None: + matched = model.objects.filter( + primary_lookup_id_type=resource.id_type, + primary_lookup_id_value=resource.id_value, + ).first() + if matched and matched.merged_to_item: + matched = matched.merged_to_item + if ( + matched + and matched.primary_lookup_id_type not in IdealIdTypes + and t in IdealIdTypes + ): + matched.primary_lookup_id_type = t + matched.primary_lookup_id_value = v + matched.save() return matched @classmethod @@ -211,7 +226,7 @@ class AbstractSite: p.item.save() self.scrape_additional_data() if auto_link: - for linked_resource in p.required_resources: + for linked_resource in p.required_resources: # type: ignore linked_url = linked_resource.get("url") if linked_url: linked_site = SiteManager.get_site_by_url(linked_url) @@ -293,7 +308,7 @@ def crawl_related_resources_task(resource_pk): _logger.warn(f"crawl resource not found {resource_pk}") return links = resource.related_resources - for w in links: + for w in links: # type: ignore try: item = None site = None diff --git a/catalog/templates/_sidebar_edit.html b/catalog/templates/_sidebar_edit.html index 77f3ccfa..1bd7a3f2 100644 --- a/catalog/templates/_sidebar_edit.html +++ b/catalog/templates/_sidebar_edit.html @@ -172,6 +172,7 @@
@@ -191,7 +192,7 @@ + value="{% trans '删除' %}"> {% endif %} diff --git a/catalog/views_edit.py b/catalog/views_edit.py index 93429fb9..89d825a9 100644 --- a/catalog/views_edit.py +++ b/catalog/views_edit.py @@ -128,6 +128,18 @@ def delete(request, item_path, item_uuid): ) +@login_required +def undelete(request, item_path, item_uuid): + if request.method != "POST": + raise BadRequest() + item = get_object_or_404(Item, uid=get_uuid_or_404(item_uuid)) + if not request.user.is_staff: + raise PermissionDenied() + item.is_deleted = False + item.save() + return redirect(item.url) + + @login_required def recast(request, item_path, item_uuid): if request.method != "POST":