Skip to content

Commit c793044

Browse files
committed
Add is_locked indication in the UI #310
Also, remove edit permissions when Product is_locked Signed-off-by: tdruez <[email protected]>
1 parent 782497a commit c793044

File tree

7 files changed

+80
-65
lines changed

7 files changed

+80
-65
lines changed

component_catalog/forms.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,9 @@ def __init__(self, user, *args, **kwargs):
625625

626626
product_field = self.fields["product"]
627627
perms = ["view_product", "change_product"]
628-
product_field.queryset = Product.objects.get_queryset(user, perms=perms)
628+
product_field.queryset = Product.objects.get_queryset(user, perms=perms).filter(
629+
is_locked=False
630+
)
629631

630632
if relation_instance:
631633
help_text = f'"{relation_instance}" will be assigned to the selected product.'
@@ -708,9 +710,11 @@ def __init__(self, request, model, relation_model, *args, **kwargs):
708710
self.model = model
709711
self.relation_model = relation_model
710712
self.dataspace = request.user.dataspace
711-
self.fields["product"].queryset = Product.objects.get_queryset(
712-
request.user, perms=["view_product", "change_product"]
713+
product_qs = Product.objects.get_queryset(
714+
user=request.user,
715+
perms=["view_product", "change_product"],
713716
)
717+
self.fields["product"].queryset = product_qs.filter(is_locked=False)
714718

715719
def get_selected_objects(self):
716720
ids = self.initial.get("ids") or self.cleaned_data["ids"]

dejacode/static/css/dejacode_bootstrap.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ table.packages-table .column-primary_language {
368368
width: 130px;
369369
}
370370
.list-inline-margin-sm .list-inline-item:not(:last-child) {
371-
margin-right: 0.3rem;
371+
margin-right: 0.125rem;
372372
}
373373

374374
/* -- Vulnerability List -- */

product_portfolio/migrations/0013_product_is_locked_and_more.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class Migration(migrations.Migration):
1515
migrations.AddField(
1616
model_name='product',
1717
name='is_locked',
18-
field=models.BooleanField(db_index=True, default=False, help_text='Marks this product vertsion as read-only, preventing any modifications to its inventory.', verbose_name='Locked'),
18+
field=models.BooleanField(db_index=True, default=False, help_text='Marks this product version as read-only, preventing any modifications to its inventory.', verbose_name='Locked'),
1919
),
2020
migrations.AlterField(
2121
model_name='productdependency',

product_portfolio/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ class Product(BaseProductMixin, FieldChangesMixin, KeywordsMixin, DataspacedMode
226226
default=False,
227227
db_index=True,
228228
help_text=_(
229-
"Marks this product vertsion as read-only, preventing any modifications to "
229+
"Marks this product version as read-only, preventing any modifications to "
230230
"its inventory."
231231
),
232232
)

product_portfolio/templates/product_portfolio/product_details.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@
111111
{% endblock %}
112112

113113
{% block content %}
114+
{% if product.is_locked %}
115+
<small class="d-inline-flex mb-3 px-2 py-1 fw-semibold text-warning-emphasis bg-warning-subtle border border-warning-subtle rounded-2">
116+
This product version is marked as read-only, preventing any modifications to its inventory.
117+
</small>
118+
{% endif %}
114119
{{ block.super }}
115120
{% if has_scan_all_packages %}
116121
{% include 'product_portfolio/modals/scan_all_packages_modal.html' %}

product_portfolio/templates/product_portfolio/tables/product_list_table.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
</th>
2020
<th scope="row">
2121
<ul class="list-inline float-end mb-0 list-inline-margin-sm">
22+
{% if product.is_locked %}
23+
<li class="list-inline-item text-secondary">
24+
<i class="fas fa-lock" data-bs-toggle="tooltip" title="Inventory is locked"></i>
25+
</li>
26+
{% endif %}
2227
{% if request.user.is_authenticated and product.request_count %}
2328
<li class="list-inline-item">
2429
<a href="{% inject_preserved_filters product.get_absolute_url %}#activity" class="r-link"><span class="badge text-bg-request">R</span></a>

product_portfolio/views.py

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -648,56 +648,55 @@ def tab_imports(self):
648648
}
649649

650650
def get_context_data(self, **kwargs):
651+
product = self.object
651652
user = self.request.user
652653
dataspace = user.dataspace
653654

654655
# This behavior does not works well in the context of getting informed about
655656
# tasks completion on the Product.
656657
if user.is_authenticated:
657-
self.object.mark_all_notifications_as_read(user)
658+
product.mark_all_notifications_as_read(user)
658659

659660
context = super().get_context_data(**kwargs)
660-
661-
context["has_change_codebaseresource_permission"] = user.has_perm(
662-
"product_portfolio.change_codebaseresource"
663-
)
664-
665661
context["filter_productcomponent"] = self.filter_productcomponent
666662
context["filter_productpackage"] = self.filter_productpackage
667663
# The reference data label and help does not make sense in the Product context
668664
context["is_reference_data"] = None
669665

670-
perms = guardian_get_perms(user, self.object)
666+
perms = guardian_get_perms(user, product)
671667
context["has_change_permission"] = "change_product" in perms
672668
context["has_delete_permission"] = "delete_product" in perms
673669

674-
context["has_edit_productpackage"] = all(
675-
[
676-
user.has_perm("product_portfolio.change_productpackage"),
677-
context["has_change_permission"],
678-
]
679-
)
680-
context["has_delete_productpackage"] = user.has_perm(
681-
"product_portfolio.delete_productpackage"
682-
)
683-
684-
context["has_add_productcomponent"] = all(
685-
[
686-
user.has_perm("product_portfolio.add_productcomponent"),
687-
context["has_change_permission"],
688-
]
689-
)
690-
context["has_edit_productcomponent"] = all(
691-
[
692-
user.has_perm("product_portfolio.change_productcomponent"),
693-
context["has_change_permission"],
694-
]
695-
)
696-
context["has_delete_productcomponent"] = user.has_perm(
697-
"product_portfolio.delete_productcomponent"
698-
)
670+
if not product.is_locked:
671+
context["has_edit_productpackage"] = all(
672+
[
673+
user.has_perm("product_portfolio.change_productpackage"),
674+
context["has_change_permission"],
675+
]
676+
)
677+
context["has_delete_productpackage"] = user.has_perm(
678+
"product_portfolio.delete_productpackage"
679+
)
680+
context["has_add_productcomponent"] = all(
681+
[
682+
user.has_perm("product_portfolio.add_productcomponent"),
683+
context["has_change_permission"],
684+
]
685+
)
686+
context["has_edit_productcomponent"] = all(
687+
[
688+
user.has_perm("product_portfolio.change_productcomponent"),
689+
context["has_change_permission"],
690+
]
691+
)
692+
context["has_delete_productcomponent"] = user.has_perm(
693+
"product_portfolio.delete_productcomponent"
694+
)
695+
context["has_change_codebaseresource_permission"] = user.has_perm(
696+
"product_portfolio.change_codebaseresource"
697+
)
699698

700-
if context["has_edit_productpackage"] or context["has_edit_productcomponent"]:
699+
if context.get("has_edit_productpackage") or context.get("has_edit_productcomponent"):
701700
all_licenses = License.objects.scope(dataspace).filter(is_active=True)
702701
add_client_data(self.request, license_data=all_licenses.data_for_expression_builder())
703702

@@ -741,12 +740,13 @@ class ProductTabInventoryView(
741740
def get_context_data(self, **kwargs):
742741
context = super().get_context_data(**kwargs)
743742

743+
product = self.object
744744
user = self.request.user
745745
dataspace = user.dataspace
746-
context["inventory_count"] = self.object.productinventoryitem_set.count()
746+
context["inventory_count"] = product.productinventoryitem_set.count()
747747

748748
license_qs = License.objects.select_related("usage_policy")
749-
declared_dependencies_qs = ProductDependency.objects.product(self.object)
749+
declared_dependencies_qs = ProductDependency.objects.product(product)
750750
package_qs = (
751751
Package.objects.select_related(
752752
"dataspace",
@@ -762,7 +762,7 @@ def get_context_data(self, **kwargs):
762762
).with_vulnerability_count()
763763

764764
productpackage_qs = (
765-
self.object.productpackages.select_related(
765+
product.productpackages.select_related(
766766
"review_status",
767767
"purpose",
768768
)
@@ -783,13 +783,13 @@ def get_context_data(self, **kwargs):
783783
filter_productpackage = ProductPackageFilterSet(
784784
self.request.GET,
785785
queryset=productpackage_qs,
786-
dataspace=self.object.dataspace,
786+
dataspace=product.dataspace,
787787
prefix=self.tab_id,
788788
anchor="#inventory",
789789
)
790790

791791
productcomponent_qs = (
792-
self.object.productcomponents.select_related(
792+
product.productcomponents.select_related(
793793
"review_status",
794794
"purpose",
795795
)
@@ -811,7 +811,7 @@ def get_context_data(self, **kwargs):
811811
filter_productcomponent = ProductComponentFilterSet(
812812
self.request.GET,
813813
queryset=productcomponent_qs,
814-
dataspace=self.object.dataspace,
814+
dataspace=product.dataspace,
815815
prefix=self.tab_id,
816816
anchor="#inventory",
817817
)
@@ -878,26 +878,27 @@ def get_context_data(self, **kwargs):
878878
}
879879
)
880880

881-
perms = guardian_get_perms(user, self.object)
882-
has_product_change_permission = "change_product" in perms
883-
context["has_edit_productcomponent"] = all(
884-
[
885-
has_product_change_permission,
886-
user.has_perm("product_portfolio.change_productcomponent"),
887-
]
888-
)
889-
context["has_edit_productpackage"] = all(
890-
[
891-
has_product_change_permission,
892-
user.has_perm("product_portfolio.change_productpackage"),
893-
]
894-
)
895-
context["has_delete_productpackage"] = user.has_perm(
896-
"product_portfolio.delete_productpackage"
897-
)
898-
context["has_delete_productcomponent"] = user.has_perm(
899-
"product_portfolio.delete_productcomponent"
900-
)
881+
if not product.is_locked:
882+
perms = guardian_get_perms(user, product)
883+
has_product_change_permission = "change_product" in perms
884+
context["has_edit_productcomponent"] = all(
885+
[
886+
has_product_change_permission,
887+
user.has_perm("product_portfolio.change_productcomponent"),
888+
]
889+
)
890+
context["has_edit_productpackage"] = all(
891+
[
892+
has_product_change_permission,
893+
user.has_perm("product_portfolio.change_productpackage"),
894+
]
895+
)
896+
context["has_delete_productpackage"] = user.has_perm(
897+
"product_portfolio.delete_productpackage"
898+
)
899+
context["has_delete_productcomponent"] = user.has_perm(
900+
"product_portfolio.delete_productcomponent"
901+
)
901902

902903
if page_obj:
903904
previous_url, next_url = self.get_previous_next(page_obj)

0 commit comments

Comments
 (0)