Skip to content

Commit 13617d7

Browse files
authored
Merge pull request #47 from nexB/14-purldb-add-package
Lookup in PurlDB by purl in Add Package
2 parents 7e32c30 + cc203b1 commit 13617d7

File tree

6 files changed

+98
-9
lines changed

6 files changed

+98
-9
lines changed

CHANGELOG.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ Release notes
33

44
### Version 5.0.2-dev
55

6+
- Lookup in PurlDB by purl in Add Package form.
7+
When a Package URL is available in the context of the "Add Package" form,
8+
for example when using a link from the Vulnerabilities tab,
9+
data is fetched from the PurlDB to initialize the form.
10+
https://github.com/nexB/dejacode/issues/47
11+
612
### Version 5.0.1
713

814
- Improve the stability of the "Check for new Package versions" feature.

component_catalog/tests/test_views.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3654,6 +3654,53 @@ def test_component_catalog_package_add_view_create_proper(self):
36543654
expected = "Package "name.zip" was successfully created."
36553655
self.assertContains(response, expected)
36563656

3657+
@mock.patch("dejacode_toolkit.purldb.PurlDB.request_get")
3658+
@mock.patch("dejacode_toolkit.purldb.PurlDB.is_configured")
3659+
def test_component_catalog_package_add_view_initial_data(
3660+
self, mock_is_configured, mock_request_get
3661+
):
3662+
self.client.login(username=self.super_user.username, password="secret")
3663+
add_url = reverse("component_catalog:package_add")
3664+
3665+
mock_is_configured.return_value = True
3666+
self.dataspace.enable_purldb_access = True
3667+
self.dataspace.save()
3668+
3669+
puyrldb_entry = {
3670+
"filename": "abbot-1.4.0.jar",
3671+
"release_date": "2015-09-22",
3672+
"type": "maven",
3673+
"namespace": "abbot",
3674+
"name": "abbot",
3675+
"version": "1.4.0",
3676+
"qualifiers": "",
3677+
"subpath": "",
3678+
"primary_language": "Java",
3679+
"description": "Abbot Java GUI Test Library",
3680+
"declared_license_expression": "bsd-new OR eps-1.0 OR apache-2.0 OR mit",
3681+
}
3682+
mock_request_get.return_value = {
3683+
"count": 1,
3684+
"results": [puyrldb_entry],
3685+
}
3686+
3687+
response = self.client.get(add_url)
3688+
self.assertEqual({}, response.context["form"].initial)
3689+
3690+
response = self.client.get(add_url + "?package_url=pkg:maven/abbot/abbot@1.4.0")
3691+
expected = {
3692+
"filename": "abbot-1.4.0.jar",
3693+
"release_date": "2015-09-22",
3694+
"type": "maven",
3695+
"namespace": "abbot",
3696+
"name": "abbot",
3697+
"version": "1.4.0",
3698+
"primary_language": "Java",
3699+
"description": "Abbot Java GUI Test Library",
3700+
"license_expression": "bsd-new OR eps-1.0 OR apache-2.0 OR mit",
3701+
}
3702+
self.assertEqual(expected, response.context["form"].initial)
3703+
36573704
@mock.patch("dje.tasks.scancodeio_submit_scan.delay")
36583705
@mock.patch("dejacode_toolkit.scancodeio.ScanCodeIO.is_configured")
36593706
def test_component_catalog_package_add_view_create_with_submit_scan(

component_catalog/views.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from django.contrib.auth.decorators import login_required
2121
from django.contrib.auth.mixins import LoginRequiredMixin
2222
from django.core import signing
23+
from django.core.validators import EMPTY_VALUES
2324
from django.db.models import Prefetch
2425
from django.http import FileResponse
2526
from django.http import Http404
@@ -45,6 +46,7 @@
4546
from natsort import natsorted
4647
from notifications.signals import notify
4748
from packageurl import PackageURL
49+
from packageurl.contrib import purl2url
4850
from packageurl.contrib import url2purl
4951

5052
from component_catalog.filters import ComponentFilterSet
@@ -1896,26 +1898,52 @@ def get_initial(self):
18961898
"""Pre-fill the form with initial data from a PurlDB entry or a `package_url`."""
18971899
initial = super().get_initial()
18981900

1899-
purldb_uuid = self.request.GET.get("purldb_uuid", None)
1900-
if purldb_uuid:
1901-
purldb_entry = PurlDB(self.request.user).get_package(purldb_uuid)
1901+
if purldb_entry := self.get_entry_from_purldb():
19021902
purldb_entry["license_expression"] = purldb_entry.get("declared_license_expression")
1903-
model_fields = [field.name for field in Package._meta.get_fields()]
1903+
model_fields = [
1904+
field.name
1905+
for field in Package._meta.get_fields()
1906+
# Generic keywords are not supported because of validation
1907+
if field.name != "keywords"
1908+
]
19041909
initial_from_purldb_entry = {
19051910
field_name: value
19061911
for field_name, value in purldb_entry.items()
1907-
if value and field_name in model_fields
1912+
if value not in EMPTY_VALUES and field_name in model_fields
19081913
}
19091914
initial.update(initial_from_purldb_entry)
1915+
messages.info(self.request, "Initial data fetched from PurlDB.")
19101916

1911-
package_url = self.request.GET.get("package_url", None)
1912-
if package_url:
1917+
elif package_url := self.request.GET.get("package_url", None):
19131918
purl = PackageURL.from_string(package_url)
19141919
package_url_dict = purl.to_dict(encode=True, empty="")
19151920
initial.update(package_url_dict)
1921+
if download_url := purl2url.get_download_url(package_url):
1922+
initial.update({"download_url": download_url})
19161923

19171924
return initial
19181925

1926+
def get_entry_from_purldb(self):
1927+
user = self.request.user
1928+
purldb = PurlDB(user)
1929+
is_purldb_enabled = all(
1930+
[
1931+
purldb.is_configured(),
1932+
user.dataspace.enable_purldb_access,
1933+
]
1934+
)
1935+
1936+
if not is_purldb_enabled:
1937+
return
1938+
1939+
purldb_uuid = self.request.GET.get("purldb_uuid", None)
1940+
package_url = self.request.GET.get("package_url", None)
1941+
1942+
if purldb_uuid:
1943+
return purldb.get_package(purldb_uuid)
1944+
elif package_url:
1945+
return purldb.get_package_by_purl(package_url)
1946+
19191947
def get_success_message(self, cleaned_data):
19201948
success_message = super().get_success_message(cleaned_data)
19211949

dejacode_toolkit/purldb.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def get_package(self, uuid):
5454
"""Get a Package details entry providing its `uuid`."""
5555
return self.request_get(url=f"{self.package_api_url}{uuid}/")
5656

57+
def get_package_by_purl(self, package_url):
58+
"""Get a Package details entry providing its `package_url`."""
59+
if results := self.find_packages({"purl": package_url}):
60+
return results[0]
61+
5762
def find_packages(self, payload, timeout=None):
5863
"""Get Packages details using provided `payload` filters on the PurlDB package list."""
5964
response = self.request_get(self.package_api_url, params=payload, timeout=timeout)

dje/templates/includes/messages_alert.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{% for message in messages %}
22
{% if wrapper_classes %}<div class="{{ wrapper_classes }}">{% endif %}
3-
<div class="alert alert-{% if message.level_tag == 'error' %}danger{% else %}{{ message.level_tag }}{% endif %} alert-dismissible" role="alert">
3+
<div class="alert alert-{% if message.level_tag == 'error' %}danger{% elif message.level_tag == 'info' %}primary{% else %}{{ message.level_tag }}{% endif %} alert-dismissible" role="alert">
44
<strong>{{ message.level_tag|title }}:</strong> {{ message|linebreaksbr }}
55
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
66
</div>

dje/templates/object_form.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ <h1 class="header-title">
2828
</div>
2929
</div>
3030

31-
{% include 'includes/form_errors_alert.html' %}
31+
{% block messages-alert %}
32+
{% include 'includes/form_errors_alert.html' %}
33+
{% include 'includes/messages_alert.html' with wrapper_classes='container p-0' %}
34+
{% endblock %}
3235

3336
<div class="card card-border-color card-border-color-primary">
3437
<div class="card-body bg-light p-4">

0 commit comments

Comments
 (0)