Skip to content

Commit

Permalink
Merge pull request #2233 from MaibornWolff/dev
Browse files Browse the repository at this point in the history
chore: merge to main for release 1.22.3
  • Loading branch information
StefanFl authored Nov 19, 2024
2 parents 4e92588 + 9750a1c commit 38b4bed
Show file tree
Hide file tree
Showing 74 changed files with 1,110 additions and 523 deletions.
2 changes: 1 addition & 1 deletion backend/application/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "1.22.2"
__version__ = "1.22.3"

import pymysql

Expand Down
76 changes: 70 additions & 6 deletions backend/application/access_control/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,47 @@ class UserFilter(FilterSet):
username = CharFilter(field_name="username", lookup_expr="icontains")
full_name = CharFilter(field_name="full_name", lookup_expr="icontains")
authorization_group = NumberFilter(field_name="authorization_groups")
exclude_authorization_group = NumberFilter(
field_name="exclude_authorization_group",
method="get_exclude_authorization_group",
)
exclude_license_group = NumberFilter(
field_name="exclude_license_group", method="get_exclude_license_group"
)
exclude_license_policy = NumberFilter(
field_name="exclude_license_policy", method="get_exclude_license_policy"
)
exclude_product = NumberFilter(
field_name="exclude_product", method="get_exclude_product"
)

# search is needed for the ReferenceArrayInput field of react-admin
search = CharFilter(field_name="full_name", lookup_expr="icontains")
def get_exclude_authorization_group(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(authorization_groups__id=value)
return queryset

def get_exclude_license_group(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_groups__id=value)
return queryset

def get_exclude_license_policy(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_policies__id=value)
return queryset

def get_exclude_product(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(product_members__id=value)
return queryset

ordering = OrderingFilter(
# tuple-mapping retains order
Expand All @@ -38,7 +76,6 @@ class Meta:
"is_active",
"is_superuser",
"is_external",
"search",
]

def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
Expand All @@ -60,9 +97,36 @@ class AuthorizationGroupFilter(FilterSet):
name = CharFilter(field_name="name", lookup_expr="icontains")
oidc_group = CharFilter(field_name="oidc_group", lookup_expr="icontains")
user = NumberFilter(field_name="users")
exclude_license_group = NumberFilter(
field_name="exclude_license_group", method="get_exclude_license_group"
)
exclude_license_policy = NumberFilter(
field_name="exclude_license_policy", method="get_exclude_license_policy"
)
exclude_product = NumberFilter(
field_name="exclude_product", method="get_exclude_product"
)

# search is needed for the ReferenceArrayInput field of react-admin
search = CharFilter(field_name="name", lookup_expr="icontains")
def get_exclude_license_group(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_groups__id=value)
return queryset

def get_exclude_license_policy(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_policies__id=value)
return queryset

def get_exclude_product(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(authorization_groups__id=value)
return queryset

ordering = OrderingFilter(
# tuple-mapping retains order
Expand All @@ -71,7 +135,7 @@ class AuthorizationGroupFilter(FilterSet):

class Meta:
model = Authorization_Group
fields = ["name", "oidc_group", "search"]
fields = ["name", "oidc_group"]

def get_user(self, queryset, name, value): # pylint: disable=unused-argument
# field_name is used as a positional argument
Expand Down
6 changes: 6 additions & 0 deletions backend/application/access_control/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
validate_password,
)
from django.core.exceptions import ValidationError as DjangoValidationError
from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.filters import SearchFilter
from rest_framework.mixins import ListModelMixin
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.response import Response
Expand Down Expand Up @@ -91,6 +93,8 @@ class UserViewSet(ModelViewSet):
filterset_class = UserFilter
queryset = User.objects.none()
permission_classes = (IsAuthenticated, UserHasSuperuserPermission)
filter_backends = [SearchFilter, DjangoFilterBackend]
search_fields = ["full_name"]

def get_queryset(self):
if self.action == "list":
Expand Down Expand Up @@ -234,6 +238,8 @@ class AuthorizationGroupViewSet(ModelViewSet):
filterset_class = AuthorizationGroupFilter
queryset = Authorization_Group.objects.none()
permission_classes = (IsAuthenticated, UserHasAuthorizationGroupPermission)
filter_backends = [SearchFilter, DjangoFilterBackend]
search_fields = ["name"]

def get_queryset(self):
return get_authorization_groups()
Expand Down
11 changes: 8 additions & 3 deletions backend/application/core/api/serializers_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class ProductSerializer(

class Meta:
model = Product
exclude = ["is_product_group", "members"]
exclude = ["is_product_group", "members", "authorization_group_members"]

def get_product_group_name(self, obj: Product) -> str:
if not obj.product_group:
Expand Down Expand Up @@ -406,7 +406,7 @@ class NestedProductSerializer(ModelSerializer):

class Meta:
model = Product
exclude = ["members"]
exclude = ["members", "authorization_group_members"]

def get_permissions(self, product: Product) -> list[Permissions]:
return get_permissions_for_role(get_highest_user_role(product))
Expand Down Expand Up @@ -438,7 +438,12 @@ class NestedProductListSerializer(ModelSerializer):

class Meta:
model = Product
exclude = ["members", "is_product_group", "new_observations_in_review"]
exclude = [
"members",
"authorization_group_members",
"is_product_group",
"new_observations_in_review",
]

def get_product_group_name(self, obj: Product) -> str:
if not obj.product_group:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 5.1.3 on 2024-11-18 11:04

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("access_control", "0010_authorization_group_member_and_more"),
("core", "0054_convert_unknown_data"),
]

operations = [
migrations.AddField(
model_name="product",
name="authorization_group_members",
field=models.ManyToManyField(
blank=True,
related_name="authorization_groups",
through="core.Product_Authorization_Group_Member",
to="access_control.authorization_group",
),
),
]
7 changes: 7 additions & 0 deletions backend/application/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ class Product(Model):
members: ManyToManyField = ManyToManyField(
User, through="Product_Member", related_name="product_members", blank=True
)
authorization_group_members: ManyToManyField = ManyToManyField(
Authorization_Group,
through="Product_Authorization_Group_Member",
related_name="authorization_groups",
blank=True,
)

apply_general_rules = BooleanField(default=True)

notification_ms_teams_webhook = CharField(max_length=255, blank=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,21 @@ def get_license_components(self, data) -> list[License_Component]:
dependencies=observation_component_dependencies,
)
model_component.unsaved_license = component.unknown_license
self._add_license_component_evidence(component, model_component)
components.append(model_component)

return components

def _add_license_component_evidence(
self,
component: Component,
license_component: License_Component,
) -> None:
evidence = []
evidence.append("Component")
evidence.append(dumps(component.json))
license_component.unsaved_evidences.append(evidence)

def _get_components(self, data: dict) -> dict[str, Component]:
components_dict = {}
components_list: list[Component] = []
Expand Down Expand Up @@ -128,21 +139,14 @@ def _get_component(self, component_data: dict[str, Any]) -> Optional[Component]:
if licenses and licenses[0].get("expression"):
unknown_licenses.append(licenses[0].get("expression"))
else:
unknown_license_ids = []
unknown_license_names = []
for my_license in licenses:
component_license = my_license.get("license", {}).get("id")
if component_license:
unknown_license_ids.append(component_license)
unknown_licenses.append(component_license)

component_license = my_license.get("license", {}).get("name")
if component_license:
unknown_license_names.append(component_license)

if unknown_license_ids:
unknown_licenses = unknown_license_ids
else:
unknown_licenses = unknown_license_names
unknown_licenses.append(component_license)

return Component(
bom_ref=component_data.get("bom-ref", ""),
Expand Down
66 changes: 44 additions & 22 deletions backend/application/licenses/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from application.licenses.models import (
License,
License_Component,
License_Component_Evidence,
License_Group,
License_Group_Authorization_Group_Member,
License_Group_Member,
Expand Down Expand Up @@ -78,9 +79,42 @@ def get_age(self, queryset, field_name, value): # pylint: disable=unused-argume
return queryset.filter(last_change__gte=time_threshold)


class LicenseComponentEvidenceFilter(FilterSet):
name = CharFilter(field_name="name", lookup_expr="icontains")

ordering = OrderingFilter(
# tuple-mapping retains order
fields=(("name", "name"), ("license_component", "license_component")),
)

class Meta:
model = License_Component_Evidence
fields = ["name", "license_component"]


class LicenseFilter(FilterSet):
spdx_id = CharFilter(field_name="spdx_id", lookup_expr="icontains")
name = CharFilter(field_name="name", lookup_expr="icontains")
exclude_license_group = NumberFilter(
field_name="exclude_license_group", method="get_exclude_license_group"
)
exclude_license_policy = NumberFilter(
field_name="exclude_license_policy", method="get_exclude_license_policy"
)

def get_exclude_license_group(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_groups__id=value)
return queryset

def get_exclude_license_policy(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_policy_items__license_policy__id=value)
return queryset

ordering = OrderingFilter(
# tuple-mapping retains order
Expand All @@ -105,6 +139,16 @@ class Meta:

class LicenseGroupFilter(FilterSet):
name = CharFilter(field_name="name", lookup_expr="icontains")
exclude_license_policy = NumberFilter(
field_name="exclude_license_policy", method="get_exclude_license_policy"
)

def get_exclude_license_policy(
self, queryset, field_name, value
): # pylint: disable=unused-argument
if value is not None:
return queryset.exclude(license_policy_items__license_policy__id=value)
return queryset

ordering = OrderingFilter(
# tuple-mapping retains order
Expand All @@ -114,9 +158,6 @@ class LicenseGroupFilter(FilterSet):
),
)

# search is needed for the ReferenceArrayInput field of react-admin
search = CharFilter(field_name="name", lookup_expr="icontains")

class Meta:
model = License_Group
fields = ["name", "is_public", "licenses"]
Expand Down Expand Up @@ -161,12 +202,6 @@ class Meta:

class LicensePolicyFilter(FilterSet):
name = CharFilter(field_name="name", lookup_expr="icontains")
licenses = NumberFilter(
field_name="licenses", method="get_license_policies_with_license"
)
license_groups = NumberFilter(
field_name="license_groups", method="get_license_policies_with_license_group"
)

ordering = OrderingFilter(
# tuple-mapping retains order
Expand All @@ -176,23 +211,10 @@ class LicensePolicyFilter(FilterSet):
),
)

# search is needed for the ReferenceArrayInput field of react-admin
search = CharFilter(field_name="name", lookup_expr="icontains")

class Meta:
model = License_Policy
fields = ["name", "is_public"]

def get_license_policies_with_license(
self, queryset, field_name, value # pylint: disable=unused-argument
) -> bool:
return queryset.filter(license_policy_items__license=value)

def get_license_policies_with_license_group(
self, queryset, field_name, value # pylint: disable=unused-argument
) -> bool:
return queryset.filter(license_policy_items__license_group=value)


class LicensePolicyItemFilter(FilterSet):
license_group_name = CharFilter(
Expand Down
Loading

0 comments on commit 38b4bed

Please sign in to comment.