diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b13f7f43..be124fc1 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,6 +9,11 @@ Release notes Inactive is_active=False products are excluded. https://github.com/aboutcode-org/dejacode/issues/388 +- Allow Product "Scan all packages" for users with the "change_product" permission + on the Product instance. + Prior to this change only "superusers" could see and use this feature. + https://github.com/aboutcode-org/dejacode/issues/385 + ### Version 5.4.2 - Migrate the LDAP testing from using mockldap to slapdtest. diff --git a/product_portfolio/tests/test_views.py b/product_portfolio/tests/test_views.py index 080a1181..8c7f5e8c 100644 --- a/product_portfolio/tests/test_views.py +++ b/product_portfolio/tests/test_views.py @@ -1092,6 +1092,33 @@ def test_product_portfolio_detail_edit_productcomponent_permissions(self): response = self.client.get(url) self.assertContains(response, delete_button) + @mock.patch("dejacode_toolkit.scancodeio.ScanCodeIO.is_configured") + def test_product_portfolio_detail_view_has_scan_all_packages(self, mock_is_configured): + mock_is_configured.return_value = True + + self.client.login(username=self.basic_user.username, password="secret") + self.assertFalse(self.basic_user.dataspace.enable_package_scanning) + + url = self.product1.get_absolute_url() + response = self.client.get(url) + self.assertEqual(404, response.status_code) + + assign_perm("view_product", self.basic_user, self.product1) + response = self.client.get(url) + self.assertEqual(200, response.status_code) + self.assertFalse(response.context.get("has_scan_all_packages")) + + self.basic_user.dataspace.enable_package_scanning = True + self.basic_user.dataspace.save() + response = self.client.get(url) + self.assertEqual(200, response.status_code) + self.assertFalse(response.context.get("has_scan_all_packages")) + + assign_perm("change_product", self.basic_user, self.product1) + response = self.client.get(url) + self.assertEqual(200, response.status_code) + self.assertTrue(response.context.get("has_scan_all_packages")) + def test_product_portfolio_detail_view_display_purldb_features(self): self.client.login(username=self.super_user.username, password="secret") self.assertFalse(self.super_user.dataspace.enable_purldb_access) @@ -1251,10 +1278,10 @@ def test_product_portfolio_details_view_admin_links(self, mock_is_configured): manage_components_url = self.product1.get_manage_components_url() manage_packages_url = self.product1.get_manage_packages_url() - expected1 = "Scan all Packages" + expected_scan_all = "Scan all Packages" response = self.client.get(url) - self.assertContains(response, expected1, html=True) + self.assertContains(response, expected_scan_all, html=True) self.assertContains(response, manage_components_url) self.assertContains(response, manage_packages_url) @@ -1271,33 +1298,33 @@ def test_product_portfolio_details_view_admin_links(self, mock_is_configured): assign_perm("view_product", self.super_user, self.product1) response = self.client.get(url) - self.assertNotContains(response, expected1, html=True) + self.assertNotContains(response, expected_scan_all, html=True) self.assertNotContains(response, manage_components_url) self.assertNotContains(response, manage_packages_url) perms = ["change_productcomponent"] self.super_user = add_perms(self.super_user, perms) response = self.client.get(url) - self.assertNotContains(response, expected1, html=True) + self.assertNotContains(response, expected_scan_all, html=True) self.assertNotContains(response, manage_components_url) self.assertNotContains(response, manage_packages_url) assign_perm("change_product", self.super_user, self.product1) response = self.client.get(url) - self.assertNotContains(response, expected1, html=True) + self.assertContains(response, expected_scan_all, html=True) self.assertContains(response, manage_components_url) self.assertNotContains(response, manage_packages_url) self.super_user = add_perms(self.super_user, ["change_productpackage"]) response = self.client.get(url) - self.assertNotContains(response, expected1, html=True) + self.assertContains(response, expected_scan_all, html=True) self.assertContains(response, manage_components_url) self.assertContains(response, manage_packages_url) self.super_user.is_superuser = True self.super_user.save() response = self.client.get(url) - self.assertContains(response, expected1, html=True) + self.assertContains(response, expected_scan_all, html=True) def test_product_portfolio_list_view_request_links(self): self.client.login(username="nexb_user", password="secret") @@ -1734,11 +1761,15 @@ def test_product_scan_all_packages_view(self, mock_is_configured, mock_scancodei dataspace_uuid=self.super_user.dataspace.uuid, ) - self.super_user.is_superuser = False - self.super_user.save() + self.client.login(username=self.basic_user.username, password="secret") response = self.client.get(scan_all_packages_url) self.assertEqual(404, response.status_code) + assign_perm("view_product", self.basic_user, self.product1) + assign_perm("change_product", self.basic_user, self.product1) + response = self.client.get(scan_all_packages_url) + self.assertRedirects(response, self.product1.get_absolute_url()) + def test_product_portfolio_product_add_view_permission_access(self): add_url = reverse("product_portfolio:product_add") response = self.client.get(add_url) diff --git a/product_portfolio/views.py b/product_portfolio/views.py index d1a1b19c..03199a5b 100644 --- a/product_portfolio/views.py +++ b/product_portfolio/views.py @@ -704,9 +704,9 @@ def get_context_data(self, **kwargs): include_scancodeio_features = all( [ scancodeio.is_configured(), - user.is_superuser, dataspace.enable_package_scanning, context["is_user_dataspace"], + context["has_change_permission"], ] ) context["has_scan_all_packages"] = include_scancodeio_features @@ -1964,7 +1964,6 @@ def scan_all_packages_view(request, dataspace, name, version=""): scancodeio = ScanCodeIO(user_dataspace) conditions = [ scancodeio.is_configured(), - user.is_superuser, user_dataspace.enable_package_scanning, user_dataspace.name == dataspace, ] @@ -1972,9 +1971,8 @@ def scan_all_packages_view(request, dataspace, name, version=""): if not all(conditions): raise Http404 - guarded_qs = Product.objects.get_queryset(user) + guarded_qs = Product.objects.get_queryset(user, perms="change_product") product = get_object_or_404(guarded_qs, name=unquote_plus(name), version=unquote_plus(version)) - if not product.all_packages: raise Http404("No packages available for this product.")