diff --git a/coldfront/core/resource/management/commands/add_resource_defaults.py b/coldfront/core/resource/management/commands/add_resource_defaults.py index 169086ec89..f7f6199f57 100644 --- a/coldfront/core/resource/management/commands/add_resource_defaults.py +++ b/coldfront/core/resource/management/commands/add_resource_defaults.py @@ -43,6 +43,11 @@ def handle(self, *args, **options): ("RackUnits", "Int"), ("InstallDate", "Date"), ("WarrantyExpirationDate", "Date"), + ("H200_quantity", "Int"), + ("H100_quantity", "Int"), + ("A100_quantity", "Int"), + ("L40s_quantity", "Int"), + ("RTX6000_quantity", "Int"), ): ResourceAttributeType.objects.get_or_create( name=resource_attribute_type, @@ -59,6 +64,4 @@ def handle(self, *args, **options): ("Storage", "NAS storage"), ("Generic", "Generic resource associated with a school"), ): - ResourceType.objects.get_or_create( - name=resource_type, description=description - ) + ResourceType.objects.get_or_create(name=resource_type, description=description) diff --git a/coldfront/plugins/api/serializers.py b/coldfront/plugins/api/serializers.py index 39c5362e6d..f20efaa51d 100644 --- a/coldfront/plugins/api/serializers.py +++ b/coldfront/plugins/api/serializers.py @@ -7,7 +7,7 @@ from coldfront.core.allocation.models import Allocation, AllocationAttribute, AllocationChangeRequest, AllocationUser from coldfront.core.project.models import Project, ProjectAttribute, ProjectUser -from coldfront.core.resource.models import Resource +from coldfront.core.resource.models import Resource, ResourceAttribute class UserSerializer(serializers.ModelSerializer): @@ -27,10 +27,25 @@ class Meta: class ResourceSerializer(serializers.ModelSerializer): resource_type = serializers.SlugRelatedField(slug_field="name", read_only=True) + resource_attributes = serializers.SerializerMethodField() class Meta: model = Resource - fields = ("id", "resource_type", "name", "description", "is_allocatable") + fields = ("id", "resource_type", "name", "description", "is_allocatable", "resource_attributes") + + def get_resource_attributes(self, obj): + request = self.context.get("request", None) + if request and request.query_params.get("resource_attributes") in ["true", "True"]: + return ResourceAttributeSerializer(obj.resourceattribute_set, many=True, read_only=True).data + return None + + +class ResourceAttributeSerializer(serializers.ModelSerializer): + resource_attribute_type = serializers.SlugRelatedField(slug_field="name", read_only=True) + + class Meta: + model = ResourceAttribute + fields = ("resource_attribute_type", "value") class AllocationSerializer(serializers.ModelSerializer): diff --git a/coldfront/plugins/api/views.py b/coldfront/plugins/api/views.py index 43d1eb4496..df877a54b0 100644 --- a/coldfront/plugins/api/views.py +++ b/coldfront/plugins/api/views.py @@ -23,8 +23,21 @@ class ResourceViewSet(viewsets.ReadOnlyModelViewSet): + """ + Query parameters: + - resource_attributes (default false) + Show related attributes. + """ + serializer_class = serializers.ResourceSerializer - queryset = Resource.objects.all() + + def get_queryset(self): + resources = Resource.objects.all() + + if self.request.query_params.get("resource_attributes") in ["True", "true"]: + resources = resources.prefetch_related("resourceattribute_set") + + return resources class AllocationViewSet(viewsets.ReadOnlyModelViewSet): @@ -40,14 +53,9 @@ class AllocationViewSet(viewsets.ReadOnlyModelViewSet): # permission_classes = (permissions.IsAuthenticatedOrReadOnly,) def get_queryset(self): - allocations = Allocation.objects.prefetch_related( - "project", "project__pi", "status" - ) + allocations = Allocation.objects.prefetch_related("project", "project__pi", "status") - if not ( - self.request.user.is_superuser - or self.request.user.has_perm("allocation.can_view_all_allocations") - ): + if not (self.request.user.is_superuser or self.request.user.has_perm("allocation.can_view_all_allocations")): allocations = allocations.filter( Q(project__status__name__in=["New", "Active"]) & ( @@ -79,9 +87,7 @@ class AllocationRequestFilter(filters.FilterSet): created = filters.DateFromToRangeFilter() fulfilled = filters.BooleanFilter(method="filter_fulfilled", label="Fulfilled") fulfilled_date = filters.DateFromToRangeFilter(label="Date fulfilled") - time_to_fulfillment = filters.NumericRangeFilter( - method="filter_time_to_fulfillment", label="Time to fulfillment" - ) + time_to_fulfillment = filters.NumericRangeFilter(method="filter_time_to_fulfillment", label="Time to fulfillment") class Meta: model = Allocation @@ -100,13 +106,9 @@ def filter_fulfilled(self, queryset, name, value): def filter_time_to_fulfillment(self, queryset, name, value): if value.start is not None: - queryset = queryset.filter( - time_to_fulfillment__gte=timedelta(days=int(value.start)) - ) + queryset = queryset.filter(time_to_fulfillment__gte=timedelta(days=int(value.start))) if value.stop is not None: - queryset = queryset.filter( - time_to_fulfillment__lte=timedelta(days=int(value.stop)) - ) + queryset = queryset.filter(time_to_fulfillment__lte=timedelta(days=int(value.stop))) return queryset @@ -143,15 +145,11 @@ def get_queryset(self): # Subquery to get the earliest historical record for each allocation earliest_history = ( - HistoricalAllocation.objects.filter(id=OuterRef("pk")) - .order_by("history_date") - .values("status__name")[:1] + HistoricalAllocation.objects.filter(id=OuterRef("pk")).order_by("history_date").values("status__name")[:1] ) fulfilled_date = ( - HistoricalAllocation.objects.filter( - id=OuterRef("pk"), status__name="Active" - ) + HistoricalAllocation.objects.filter(id=OuterRef("pk"), status__name="Active") .order_by("history_date") .values("modified")[:1] ) @@ -183,9 +181,7 @@ class AllocationChangeRequestFilter(filters.FilterSet): created = filters.DateFromToRangeFilter() fulfilled = filters.BooleanFilter(method="filter_fulfilled", label="Fulfilled") fulfilled_date = filters.DateFromToRangeFilter(label="Date fulfilled") - time_to_fulfillment = filters.NumericRangeFilter( - method="filter_time_to_fulfillment", label="Time to fulfillment" - ) + time_to_fulfillment = filters.NumericRangeFilter(method="filter_time_to_fulfillment", label="Time to fulfillment") class Meta: model = AllocationChangeRequest @@ -204,13 +200,9 @@ def filter_fulfilled(self, queryset, name, value): def filter_time_to_fulfillment(self, queryset, name, value): if value.start is not None: - queryset = queryset.filter( - time_to_fulfillment__gte=timedelta(days=int(value.start)) - ) + queryset = queryset.filter(time_to_fulfillment__gte=timedelta(days=int(value.start))) if value.stop is not None: - queryset = queryset.filter( - time_to_fulfillment__lte=timedelta(days=int(value.stop)) - ) + queryset = queryset.filter(time_to_fulfillment__lte=timedelta(days=int(value.stop))) return queryset @@ -248,23 +240,17 @@ def get_queryset(self): Q(allocation__project__status__name__in=["New", "Active"]) & ( ( - Q( - allocation__project__projectuser__role__name__contains="Manager" - ) + Q(allocation__project__projectuser__role__name__contains="Manager") & Q(allocation__project__projectuser__user=self.request.user) ) | Q(allocation__project__pi=self.request.user) ) ).distinct() - HistoricalAllocationChangeRequest = get_history_model_for_model( - AllocationChangeRequest - ) + HistoricalAllocationChangeRequest = get_history_model_for_model(AllocationChangeRequest) fulfilled_date = ( - HistoricalAllocationChangeRequest.objects.filter( - id=OuterRef("pk"), status__name="Approved" - ) + HistoricalAllocationChangeRequest.objects.filter(id=OuterRef("pk"), status__name="Approved") .order_by("history_date") .values("modified")[:1] ) @@ -307,10 +293,7 @@ def get_queryset(self): projects.filter( Q(status__name__in=["New", "Active"]) & ( - ( - Q(projectuser__role__name__contains="Manager") - & Q(projectuser__user=self.request.user) - ) + (Q(projectuser__role__name__contains="Manager") & Q(projectuser__user=self.request.user)) | Q(pi=self.request.user) ) )