From cfb572660dfd823181e0867454a79e351ca39dfb Mon Sep 17 00:00:00 2001 From: tdruez <489057+tdruez@users.noreply.github.com> Date: Mon, 27 May 2024 11:48:53 +0400 Subject: [PATCH] Add replace_existing_version field on the AddToProduct form #12 (#124) Signed-off-by: tdruez --- CHANGELOG.rst | 4 + component_catalog/forms.py | 19 ++- component_catalog/models.py | 6 +- .../component_catalog/add_to_product.html | 9 +- .../component_catalog/includes/add_to.js.html | 48 ++++-- .../includes/add_to_modal.html | 4 +- component_catalog/tests/test_models.py | 3 + component_catalog/views.py | 15 +- dje/models.py | 13 +- policy/models.py | 2 +- product_portfolio/models.py | 121 +++++++++---- product_portfolio/tests/test_models.py | 160 +++++++++++++++++- 12 files changed, 342 insertions(+), 62 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ee11fe2e..fb6b2937 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -78,6 +78,10 @@ Release notes - Enhance Package Import to support modifications. https://github.com/nexB/dejacode/issues/84 +- Add an option on the "Add to Product" form to to replace any existing relationships + with a different version of the same object by the selected object. + https://github.com/nexB/dejacode/issues/12 + ### Version 5.0.1 - Improve the stability of the "Check for new Package versions" feature. diff --git a/component_catalog/forms.py b/component_catalog/forms.py index 73a4cb60..e6c3ddf8 100644 --- a/component_catalog/forms.py +++ b/component_catalog/forms.py @@ -646,6 +646,17 @@ class AddToProductAdminForm(forms.Form): queryset=Product.objects.none(), ) ids = forms.CharField(widget=forms.widgets.HiddenInput) + replace_existing_version = forms.BooleanField( + required=False, + initial=False, + label="Replace existing relationships by newer version.", + help_text=( + "Select this option to replace any existing relationships with a different version " + "of the same object. " + "If more than one version of the object is already assigned, no replacements will be " + "made, and the new version will be added instead." + ), + ) def __init__(self, request, model, relation_model, *args, **kwargs): super().__init__(*args, **kwargs) @@ -663,9 +674,11 @@ def get_selected_objects(self): def save(self): product = self.cleaned_data["product"] + return product.assign_objects( related_objects=self.get_selected_objects(), user=self.request.user, + replace_version=self.cleaned_data["replace_existing_version"], ) @@ -719,15 +732,15 @@ def new_component_from_package_link(self): href = f"{component_add_url}?package_ids={package.id}" return HTML( + f"
" f'
' f' ' f" Add Component from Package data" f" " f"
" - f"
" ) def clean_component(self): @@ -749,9 +762,9 @@ def helper(self): helper.layout = Layout( Fieldset( None, - self.new_component_from_package_link(), "object_id", "component", + self.new_component_from_package_link(), ), ) return helper diff --git a/component_catalog/models.py b/component_catalog/models.py index a220135b..e4917f4c 100644 --- a/component_catalog/models.py +++ b/component_catalog/models.py @@ -1915,12 +1915,16 @@ def get_export_cyclonedx_url(self): return self.get_url("export_cyclonedx") @classmethod - def get_identifier_fields(cls): + def get_identifier_fields(cls, *args, purl_fields_only=False, **kwargs): """ Explicit list of identifier fields as we do not enforce a unique together on this model. This is used in the Importer, to catch duplicate entries. + The purl_fields_only option can be use to limit the results. """ + if purl_fields_only: + return PACKAGE_URL_FIELDS + return ["filename", "download_url", *PACKAGE_URL_FIELDS] @property diff --git a/component_catalog/templates/admin/component_catalog/add_to_product.html b/component_catalog/templates/admin/component_catalog/add_to_product.html index 854add47..a1621436 100644 --- a/component_catalog/templates/admin/component_catalog/add_to_product.html +++ b/component_catalog/templates/admin/component_catalog/add_to_product.html @@ -19,17 +19,22 @@

Add {% trans opts.verbose_name %} to a product

The Product provides you with a group of {% trans opts.verbose_name_plural|title %} that are used together, so that you can generate Attribution documentation for all of the {% trans opts.verbose_name_plural|title %} in that Product.

-

+

{{ form.non_field_errors }} {{ form.product.errors }} {{ form.product }} +
+ {{ form.replace_existing_version }} + {{ form.replace_existing_version.label }} +

{{ form.replace_existing_version.help_text }}

+
{% if perms.product_portfolio.add_product %} {% endif %} {{ form.ct }} {{ form.ids }} -

+

diff --git a/component_catalog/templates/component_catalog/includes/add_to.js.html b/component_catalog/templates/component_catalog/includes/add_to.js.html index 77e2ffeb..a024fe67 100644 --- a/component_catalog/templates/component_catalog/includes/add_to.js.html +++ b/component_catalog/templates/component_catalog/includes/add_to.js.html @@ -1,29 +1,35 @@ \ No newline at end of file + \ No newline at end of file diff --git a/component_catalog/templates/component_catalog/includes/add_to_modal.html b/component_catalog/templates/component_catalog/includes/add_to_modal.html index 122323ce..847f1758 100644 --- a/component_catalog/templates/component_catalog/includes/add_to_modal.html +++ b/component_catalog/templates/component_catalog/includes/add_to_modal.html @@ -8,13 +8,13 @@