Skip to content

Commit

Permalink
Store additional license fields #63 (#130)
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <tdruez@nexb.com>
  • Loading branch information
tdruez authored Jul 3, 2024
1 parent 5367624 commit 9ba5da0
Show file tree
Hide file tree
Showing 38 changed files with 1,728 additions and 323 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,29 @@ Release notes
- Populate the Package notice_text using "*NOTICE*" file content from Scan "key files".
https://github.com/nexB/dejacode/issues/136

- Added 2 new license related fields on the Component and Package models:
* declared_license_expression
* other_license_expression
https://github.com/nexB/dejacode/issues/63

- Added 2 properties on the Component and Package models:
* declared_license_expression_spdx (computed from declared_license_expression)
* other_license_expression_spdx (computed from other_license_expression)
https://github.com/nexB/dejacode/issues/63

- Removed 2 fields: Package.declared_license and Component.concluded_license
https://github.com/nexB/dejacode/issues/63

- The new license fields are automatically populated from the Package scan
"Update packages automatically from scan".
The new license fields are pre-filled in the Package form when using the
"Add Package" from a PurlDB entry.
The new license fields are pre-filled in the Component form when using the
"Add Component from Package data".
The license expression values provided in the form for the new field is now
properly checked and return a validation error when incorrect.
https://github.com/nexB/dejacode/issues/63

### Version 5.1.0

- Upgrade Python version to 3.12 and Django to 5.0.x
Expand Down
16 changes: 12 additions & 4 deletions component_catalog/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,8 @@ class ComponentAdmin(
"copyright",
"holder",
"license_expression",
"declared_license_expression",
"other_license_expression",
"reference_notes",
"release_date",
"description",
Expand Down Expand Up @@ -394,7 +396,6 @@ class ComponentAdmin(
"ip_sensitivity_approved",
"affiliate_obligations",
"affiliate_obligation_triggers",
"concluded_license",
"legal_comments",
"sublicense_allowed",
"express_patent_grant",
Expand All @@ -418,7 +419,10 @@ class ComponentAdmin(
autocomplete_lookup_fields = {"fk": ["owner"]}
# We have to use 'completion_level' rather than the 'completion_level_pct'
# callable to keep the help_text available during render in the template.
readonly_fields = DataspacedAdmin.readonly_fields + ("urn_link", "completion_level")
readonly_fields = DataspacedAdmin.readonly_fields + (
"urn_link",
"completion_level",
)
form = ComponentAdminForm
inlines = [
SubcomponentChildInline,
Expand Down Expand Up @@ -826,6 +830,8 @@ class PackageAdmin(
{
"fields": (
"license_expression",
"declared_license_expression",
"other_license_expression",
"copyright",
"holder",
"author",
Expand Down Expand Up @@ -864,7 +870,6 @@ class PackageAdmin(
"Others",
{
"fields": (
"declared_license",
"parties",
"datasource_id",
"file_references",
Expand All @@ -880,7 +885,10 @@ class PackageAdmin(
),
get_additional_information_fieldset(),
]
readonly_fields = DataspacedAdmin.readonly_fields + ("package_url", "inferred_url")
readonly_fields = DataspacedAdmin.readonly_fields + (
"package_url",
"inferred_url",
)
form = PackageAdminForm
importer_class = PackageImporter
mass_update_form = PackageMassUpdateForm
Expand Down
11 changes: 8 additions & 3 deletions component_catalog/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ class Meta:
"holder",
"author",
"license_expression",
"declared_license_expression",
"other_license_expression",
"reference_notes",
"homepage_url",
"vcs_url",
Expand Down Expand Up @@ -305,7 +307,6 @@ class Meta:
"ip_sensitivity_approved",
"affiliate_obligations",
"affiliate_obligation_triggers",
"concluded_license",
"legal_comments",
"sublicense_allowed",
"express_patent_grant",
Expand All @@ -323,6 +324,8 @@ class Meta:
"licenses_summary",
"license_choices_expression",
"license_choices",
"declared_license_expression",
"other_license_expression",
"created_date",
"last_modified_date",
)
Expand Down Expand Up @@ -524,6 +527,8 @@ class Meta(ComponentSerializer.Meta):
"copyright",
"holder",
"license_expression",
"declared_license_expression",
"other_license_expression",
"reference_notes",
"release_date",
"description",
Expand Down Expand Up @@ -551,7 +556,6 @@ class Meta(ComponentSerializer.Meta):
"ip_sensitivity_approved",
"affiliate_obligations",
"affiliate_obligation_triggers",
"concluded_license",
"legal_comments",
"sublicense_allowed",
"express_patent_grant",
Expand Down Expand Up @@ -639,6 +643,8 @@ class Meta:
"licenses_summary",
"license_choices_expression",
"license_choices",
"declared_license_expression",
"other_license_expression",
"reference_notes",
"homepage_url",
"vcs_url",
Expand All @@ -656,7 +662,6 @@ class Meta:
"version",
"qualifiers",
"subpath",
"declared_license",
"parties",
"datasource_id",
"file_references",
Expand Down
54 changes: 51 additions & 3 deletions component_catalog/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from django.urls import reverse
from django.urls import reverse_lazy
from django.utils.functional import cached_property
from django.utils.text import Truncator

import packageurl
from crispy_forms.helper import FormHelper
Expand Down Expand Up @@ -82,6 +83,11 @@ class ComponentForm(
DataspacedModelForm,
):
default_on_addition_fields = ["configuration_status"]
expression_field_names = [
"license_expression",
"declared_license_expression",
"other_license_expression",
]
save_as = True
clone_m2m_classes = [
ComponentAssignedPackage,
Expand All @@ -106,6 +112,8 @@ class Meta:
"holder",
"notice_text",
"license_expression",
"declared_license_expression",
"other_license_expression",
"release_date",
"description",
"homepage_url",
Expand All @@ -130,6 +138,8 @@ class Meta:
"owner": OwnerChoiceField,
}
widgets = {
"declared_license_expression": forms.Textarea(attrs={"rows": 2}),
"other_license_expression": forms.Textarea(attrs={"rows": 2}),
"copyright": forms.Textarea(attrs={"rows": 2}),
"notice_text": forms.Textarea(attrs={"rows": 2}),
"description": forms.Textarea(attrs={"rows": 2}),
Expand Down Expand Up @@ -188,6 +198,7 @@ def helper(self):
Group("name", "version", "owner"),
HTML("<hr>"),
"license_expression",
Group("declared_license_expression", "other_license_expression"),
Group("copyright", "holder"),
"notice_text",
Group("notice_filename", "notice_url"),
Expand Down Expand Up @@ -267,6 +278,11 @@ class PackageForm(
PackageFieldsValidationMixin,
DataspacedModelForm,
):
expression_field_names = [
"license_expression",
"declared_license_expression",
"other_license_expression",
]
save_as = True
color_initial = True

Expand Down Expand Up @@ -299,6 +315,8 @@ class Meta:
"notes",
"usage_policy",
"license_expression",
"declared_license_expression",
"other_license_expression",
"copyright",
"holder",
"author",
Expand All @@ -320,6 +338,8 @@ class Meta:
"collect_data",
]
widgets = {
"declared_license_expression": forms.Textarea(attrs={"rows": 2}),
"other_license_expression": forms.Textarea(attrs={"rows": 2}),
"description": forms.Textarea(attrs={"rows": 2}),
"notes": forms.Textarea(attrs={"rows": 2}),
"copyright": forms.Textarea(attrs={"rows": 2}),
Expand Down Expand Up @@ -377,6 +397,7 @@ def helper(self):
Group("version", "qualifiers", "subpath"),
HTML("<hr>"),
"license_expression",
Group("declared_license_expression", "other_license_expression"),
Group("copyright", "notice_text"),
Group("holder", "author"),
HTML("<hr>"),
Expand Down Expand Up @@ -429,6 +450,12 @@ def save(self, *args, **kwargs):


class BaseScanToPackageForm(LicenseExpressionFormMixin, DataspacedModelForm):
expression_field_names = [
"license_expression",
"declared_license_expression",
"other_license_expression",
]

@property
def helper(self):
helper = FormHelper()
Expand All @@ -451,6 +478,8 @@ class Meta:
fields = [
"package_url",
"license_expression",
"declared_license_expression",
"other_license_expression",
"copyright",
"primary_language",
"description",
Expand Down Expand Up @@ -482,14 +511,20 @@ def __init__(self, *args, **kwargs):
def fields_with_initial_value(self):
kept_fields = {}

# Duplicate the declared_license_expression into the license_expression field
# if currently empty on the Package instance.
if not self.instance.license_expression:
if declared_license_expression := self.initial.get("declared_license_expression"):
self.initial["license_expression"] = declared_license_expression

for field_name, field in self.fields.items():
if not self.initial.get(field_name):
continue

instance_value = getattr(self.instance, field_name, None)
help_text = "No current value"
if instance_value:
help_text = f"Current value: {instance_value}"
help_text = f"Current value: {Truncator(instance_value).chars(200)}"
field.help_text = help_text

kept_fields[field_name] = field
Expand Down Expand Up @@ -524,6 +559,8 @@ class Meta:
model = Package
fields = [
"license_expression",
"declared_license_expression",
"other_license_expression",
"primary_language",
"holder",
]
Expand All @@ -542,7 +579,7 @@ def set_help_text_with_initial_value(self):
instance_value = getattr(self.instance, field_name, None)
help_text = "No current value"
if instance_value:
help_text = f"Current value: {instance_value}"
help_text = f"Current value: {Truncator(instance_value).chars(200)}"
field.help_text = help_text


Expand Down Expand Up @@ -922,6 +959,12 @@ class ComponentAdminForm(
SetKeywordsChoicesFormMixin,
DataspacedAdminForm,
):
expression_field_names = [
"license_expression",
"declared_license_expression",
"other_license_expression",
]

keywords = JSONListField(
required=False,
widget=AdminAwesompleteInputWidget(attrs=autocomplete_placeholder),
Expand Down Expand Up @@ -956,6 +999,12 @@ class PackageAdminForm(
SetKeywordsChoicesFormMixin,
DataspacedAdminForm,
):
expression_field_names = [
"license_expression",
"declared_license_expression",
"other_license_expression",
]

keywords = JSONListField(
required=False,
widget=AdminAwesompleteInputWidget(attrs=autocomplete_placeholder),
Expand Down Expand Up @@ -1043,7 +1092,6 @@ class Meta:
"ip_sensitivity_approved",
"affiliate_obligations",
"affiliate_obligation_triggers",
"concluded_license",
"legal_comments",
"sublicense_allowed",
"express_patent_grant",
Expand Down
Loading

0 comments on commit 9ba5da0

Please sign in to comment.