Skip to content

Commit 6098118

Browse files
authored
Add expandable backoffice_assets and datacenter_assets fields to Supports API (#3921)
1 parent 53f18fa commit 6098118

File tree

2 files changed

+215
-5
lines changed

2 files changed

+215
-5
lines changed

src/ralph/supports/api.py

Lines changed: 149 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
# -*- coding: utf-8 -*-
22
import django_filters
3+
from django.contrib.contenttypes.models import ContentType
34
from django.db.models import Prefetch
45
from rest_framework import serializers
56

7+
from django.urls import reverse
8+
69
from ralph.api import RalphAPISerializer, RalphAPIViewSet, router
710
from ralph.assets.api.serializers import (
811
ServiceEnvironmentSimpleSerializer,
912
StrField,
1013
TypeFromContentTypeSerializerMixin,
1114
)
1215
from ralph.assets.models import BaseObject
16+
from ralph.back_office.models import BackOfficeAsset
17+
from ralph.data_center.models import DataCenterAsset
1318
from ralph.lib.permissions.api import PermissionsForObjectFilter
1419
from ralph.lib.visibility_scope.filters import visibility_scope_asset_support_filter
1520
from ralph.supports.models import BaseObjectsSupport, Support, SupportType
@@ -44,18 +49,118 @@ class Meta:
4449
_skip_tags_field = True
4550

4651

52+
class BackOfficeAssetForSupportSerializer(RalphAPISerializer):
53+
id = serializers.IntegerField(source="pk")
54+
model = serializers.CharField(source="model.name", read_only=True)
55+
manufacturer = serializers.CharField(source="model.manufacturer.name", read_only=True)
56+
category = serializers.CharField(source="model.category.name", read_only=True)
57+
service_env = ServiceEnvironmentSimpleSerializer(read_only=True)
58+
property_of = serializers.CharField(source="property_of.name", read_only=True)
59+
status = serializers.CharField(source="get_status_display", read_only=True)
60+
61+
class Meta:
62+
model = BackOfficeAsset
63+
exclude_from_registry = True
64+
fields = [
65+
"id",
66+
"barcode",
67+
"sn",
68+
"hostname",
69+
"model",
70+
"manufacturer",
71+
"category",
72+
"status",
73+
"service_env",
74+
"property_of",
75+
"order_no",
76+
]
77+
_skip_tags_field = True
78+
79+
80+
class DataCenterAssetForSupportSerializer(RalphAPISerializer):
81+
id = serializers.IntegerField(source="pk")
82+
model = serializers.CharField(source="model.name", read_only=True)
83+
manufacturer = serializers.CharField(source="model.manufacturer.name", read_only=True)
84+
category = serializers.CharField(source="model.category.name", read_only=True)
85+
service_env = ServiceEnvironmentSimpleSerializer(read_only=True)
86+
property_of = serializers.CharField(source="property_of.name", read_only=True)
87+
status = serializers.CharField(source="get_status_display", read_only=True)
88+
89+
class Meta:
90+
model = DataCenterAsset
91+
exclude_from_registry = True
92+
fields = [
93+
"id",
94+
"barcode",
95+
"sn",
96+
"hostname",
97+
"model",
98+
"manufacturer",
99+
"category",
100+
"status",
101+
"service_env",
102+
"property_of",
103+
"order_no",
104+
]
105+
_skip_tags_field = True
106+
107+
47108
class SupportSerializer(TypeFromContentTypeSerializerMixin, RalphAPISerializer):
48109
__str__ = StrField(show_type=True)
49-
base_objects = serializers.HyperlinkedRelatedField(
50-
many=True, view_name="baseobject-detail", read_only=True
51-
)
110+
base_objects = serializers.SerializerMethodField()
52111
service_env = ServiceEnvironmentSimpleSerializer()
112+
backoffice_assets = serializers.SerializerMethodField()
113+
datacenter_assets = serializers.SerializerMethodField()
114+
115+
def get_base_objects(self, obj):
116+
request = self.context.get('request')
117+
base_objects = [bos.baseobject for bos in obj.baseobjectssupport_set.all()]
118+
return [
119+
request.build_absolute_uri(
120+
reverse('baseobject-detail', kwargs={'pk': bo.pk})
121+
)
122+
for bo in base_objects
123+
]
53124

54125
class Meta:
55126
model = Support
56127
depth = 1
57128
exclude = ("content_type", "configuration_path")
58129

130+
def get_fields(self):
131+
fields = super().get_fields()
132+
request = self.context.get('request')
133+
if request and not request.query_params.get('include_assets'):
134+
fields.pop('backoffice_assets', None)
135+
fields.pop('datacenter_assets', None)
136+
return fields
137+
138+
def get_backoffice_assets(self, obj):
139+
request = self.context.get('request')
140+
if not request or not request.query_params.get('include_assets'):
141+
return []
142+
143+
backoffice_ct_id = ContentType.objects.get_for_model(BackOfficeAsset).id
144+
145+
backoffice_assets = [
146+
bos.baseobject for bos in obj.baseobjectssupport_set.all()
147+
if bos.baseobject.content_type_id == backoffice_ct_id
148+
]
149+
return BackOfficeAssetForSupportSerializer(backoffice_assets, many=True).data
150+
151+
def get_datacenter_assets(self, obj):
152+
request = self.context.get('request')
153+
if not request or not request.query_params.get('include_assets'):
154+
return []
155+
156+
datacenter_ct_id = ContentType.objects.get_for_model(DataCenterAsset).id
157+
158+
datacenter_assets = [
159+
bos.baseobject for bos in obj.baseobjectssupport_set.all()
160+
if bos.baseobject.content_type_id == datacenter_ct_id
161+
]
162+
return DataCenterAssetForSupportSerializer(datacenter_assets, many=True).data
163+
59164

60165
class BaseObjectsFilter(django_filters.FilterSet):
61166
"""
@@ -91,6 +196,7 @@ class SupportViewSet(RalphAPIViewSet):
91196
)
92197
filterset_class = BaseObjectsFilter
93198
select_related = [
199+
"content_type",
94200
"region",
95201
"budget_info",
96202
"support_type",
@@ -101,9 +207,48 @@ class SupportViewSet(RalphAPIViewSet):
101207
]
102208
prefetch_related = [
103209
"tags",
104-
Prefetch("base_objects", queryset=BaseObject.objects.all()),
105210
]
106211

212+
def get_queryset(self):
213+
queryset = super().get_queryset()
214+
215+
if self.request.query_params.get("include_assets"):
216+
queryset = queryset.prefetch_related(
217+
Prefetch(
218+
"baseobjectssupport_set__baseobject",
219+
queryset=BaseObject.polymorphic_objects.select_related(
220+
"content_type"
221+
).polymorphic_select_related(
222+
BackOfficeAsset=[
223+
"model",
224+
"model__manufacturer",
225+
"model__category",
226+
"service_env",
227+
"service_env__service",
228+
"service_env__environment",
229+
"property_of",
230+
],
231+
DataCenterAsset=[
232+
"model",
233+
"model__manufacturer",
234+
"model__category",
235+
"service_env",
236+
"service_env__service",
237+
"service_env__environment",
238+
"property_of",
239+
],
240+
),
241+
)
242+
)
243+
else:
244+
queryset = queryset.prefetch_related(
245+
Prefetch(
246+
"baseobjectssupport_set__baseobject",
247+
queryset=BaseObject.polymorphic_objects.all(),
248+
)
249+
)
250+
return queryset
251+
107252

108253
class BaseObjectsSupportSerializer(RalphAPISerializer):
109254
support = SupportSimpleSerializer()

src/ralph/supports/tests/test_api.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
from ralph.api.tests._base import RalphAPITestCase
99
from ralph.assets.tests.factories import ServiceEnvironmentFactory
1010
from ralph.supports.models import Support, SupportStatus
11-
from ralph.supports.tests.factories import SupportFactory
11+
from ralph.supports.tests.factories import (
12+
BackOfficeAssetSupportFactory,
13+
DataCenterAssetSupportFactory,
14+
SupportFactory,
15+
)
1216

1317

1418
class SupportAPITests(RalphAPITestCase):
@@ -74,3 +78,64 @@ def test_patch_support(self):
7478
self.assertEqual(self.support.name, "support2")
7579
self.assertEqual(self.support.contract_id, "12345")
7680
self.assertEqual(self.support.date_to, date(2015, 12, 31))
81+
82+
def test_support_with_include_assets(self):
83+
support1 = SupportFactory(name="support_with_assets_1")
84+
support2 = SupportFactory(name="support_with_assets_2")
85+
support3 = SupportFactory(name="support_with_assets_3")
86+
87+
BackOfficeAssetSupportFactory.create_batch(3, support=support1)
88+
BackOfficeAssetSupportFactory.create_batch(2, support=support2)
89+
90+
DataCenterAssetSupportFactory.create_batch(2, support=support1)
91+
DataCenterAssetSupportFactory.create_batch(3, support=support3)
92+
93+
# Mix of both base_object types for one support
94+
BackOfficeAssetSupportFactory.create_batch(2, support=support3)
95+
96+
support4 = SupportFactory(name="support_with_assets_4")
97+
BackOfficeAssetSupportFactory.create_batch(3, support=support4)
98+
DataCenterAssetSupportFactory.create_batch(3, support=support4)
99+
SupportFactory.create_batch(10)
100+
101+
url = reverse("support-list")
102+
103+
with self.assertQueriesMoreOrLess(7, plus_minus=2):
104+
response = self.client.get(
105+
url, {"include_assets": "true"}, format="json"
106+
)
107+
108+
self.assertEqual(response.status_code, status.HTTP_200_OK)
109+
self.assertEqual(response.data["count"], 15) # 4 with assets + 10 without + 1 from setUp
110+
111+
for result in response.data["results"]:
112+
if result["name"] == "support_with_assets_1":
113+
self.assertEqual(len(result["backoffice_assets"]), 3)
114+
self.assertEqual(len(result["datacenter_assets"]), 2)
115+
self.assertIn("model", result["backoffice_assets"][0])
116+
self.assertIn("manufacturer", result["backoffice_assets"][0])
117+
self.assertIn("service_env", result["backoffice_assets"][0])
118+
elif result["name"] == "support_with_assets_2":
119+
self.assertEqual(len(result["backoffice_assets"]), 2)
120+
self.assertEqual(len(result["datacenter_assets"]), 0)
121+
elif result["name"] == "support_with_assets_3":
122+
self.assertEqual(len(result["backoffice_assets"]), 2)
123+
self.assertEqual(len(result["datacenter_assets"]), 3)
124+
125+
def test_support_without_include_assets_parameter(self):
126+
support = SupportFactory(name="support_minimal")
127+
BackOfficeAssetSupportFactory.create_batch(2, support=support)
128+
DataCenterAssetSupportFactory.create_batch(2, support=support)
129+
130+
url = reverse("support-detail", args=(support.id,))
131+
with self.assertQueriesMoreOrLess(6, plus_minus=2):
132+
response = self.client.get(url, format="json")
133+
134+
self.assertEqual(response.status_code, status.HTTP_200_OK)
135+
self.assertEqual(response.data["name"], "support_minimal")
136+
137+
self.assertIn("base_objects", response.data)
138+
self.assertEqual(len(response.data["base_objects"]), 4)
139+
140+
self.assertNotIn("backoffice_assets", response.data)
141+
self.assertNotIn("datacenter_assets", response.data)

0 commit comments

Comments
 (0)