Skip to content

Commit 145995d

Browse files
committed
serializers: Add 'related_versions' field to series serializer
For two series to be linked togheter they must belong to the same project Closes getpatchwork#506 Signed-off-by: andrepapoti <[email protected]>
1 parent 5f420db commit 145995d

File tree

1 file changed

+93
-4
lines changed

1 file changed

+93
-4
lines changed

patchwork/api/series.py

+93-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55

66
from rest_framework.generics import ListAPIView
77
from rest_framework.generics import RetrieveAPIView
8+
from rest_framework.generics import UpdateAPIView
89
from rest_framework.serializers import SerializerMethodField
10+
from rest_framework.exceptions import ValidationError
11+
from rest_framework.response import Response
912

1013
from patchwork.api.base import BaseHyperlinkedModelSerializer
1114
from patchwork.api.base import PatchworkPermission
@@ -14,6 +17,7 @@
1417
from patchwork.api.embedded import PatchSerializer
1518
from patchwork.api.embedded import PersonSerializer
1619
from patchwork.api.embedded import ProjectSerializer
20+
from patchwork.api.embedded import SeriesSerializer as RelatedSeriesSerializer
1721
from patchwork.models import Series
1822

1923

@@ -24,6 +28,51 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer):
2428
mbox = SerializerMethodField()
2529
cover_letter = CoverSerializer(read_only=True)
2630
patches = PatchSerializer(read_only=True, many=True)
31+
previous_series = RelatedSeriesSerializer(many=True, default=[])
32+
subsequent_series = RelatedSeriesSerializer(many=True, default=[])
33+
required_series = RelatedSeriesSerializer(many=True, default=[])
34+
required_by_series = RelatedSeriesSerializer(many=True, default=[])
35+
36+
def helper_get_series_urls(self, series_queryset):
37+
return [self.get_web_url(series) for series in series_queryset]
38+
39+
def helper_validate_series(self, related_series):
40+
for series in related_series:
41+
if self.instance.id == series.id:
42+
raise ValidationError('A series cannot be linked to itself.')
43+
if self.instance.project.id != series.project.id:
44+
raise ValidationError(
45+
'Series must belong to the same project.'
46+
)
47+
return related_series
48+
49+
def get_previous_series(self, obj):
50+
previous = obj.previous_series.all()
51+
return self.helper_get_series_urls(previous)
52+
53+
def get_subsequent_series(self, obj):
54+
subsequent = obj.subsequent_series.all()
55+
return self.helper_get_series_urls(subsequent)
56+
57+
def get_required_series(self, obj):
58+
required = obj.required_series.all()
59+
return self.helper_get_series_urls(required)
60+
61+
def get_required_by_series(self, obj):
62+
required_by = obj.required_by_series.all()
63+
return self.helper_get_series_urls(required_by)
64+
65+
def validate_previous_series(self, previous_series):
66+
return self.helper_validate_series(previous_series)
67+
68+
def validate_subsequent_series(self, subsequent_series):
69+
return self.helper_validate_series(subsequent_series)
70+
71+
def validate_required_series(self, required_series):
72+
return self.helper_validate_series(required_series)
73+
74+
def validate_required_by_series(self, required_by_series):
75+
return self.helper_validate_series(required_by_series)
2776

2877
def get_web_url(self, instance):
2978
request = self.context.get('request')
@@ -44,6 +93,10 @@ class Meta:
4493
'date',
4594
'submitter',
4695
'version',
96+
'previous_series',
97+
'subsequent_series',
98+
'required_series',
99+
'required_by_series',
47100
'total',
48101
'received_total',
49102
'received_all',
@@ -76,7 +129,14 @@ class SeriesMixin(object):
76129
def get_queryset(self):
77130
return (
78131
Series.objects.all()
79-
.prefetch_related('patches__project', 'cover_letter__project')
132+
.prefetch_related(
133+
'patches__project',
134+
'cover_letter__project',
135+
'previous_series__project',
136+
'subsequent_series__project',
137+
'required_series__project',
138+
'required_by_series__project',
139+
)
80140
.select_related('submitter', 'project')
81141
)
82142

@@ -90,7 +150,36 @@ class SeriesList(SeriesMixin, ListAPIView):
90150
ordering = 'id'
91151

92152

93-
class SeriesDetail(SeriesMixin, RetrieveAPIView):
94-
"""Show a series."""
153+
class SeriesDetail(SeriesMixin, RetrieveAPIView, UpdateAPIView):
154+
"""Show and update a series."""
155+
156+
queryset = Series.objects.all()
157+
serializer_class = SeriesSerializer
158+
159+
def update(self, request, *args, **kwargs):
160+
instance = self.get_object()
161+
162+
allowed_fields = {
163+
'previous_series',
164+
'subsequent_series',
165+
'required_series',
166+
'required_by_series',
167+
}
168+
provided_fields = set(request.data.keys())
169+
disallowed_fields = provided_fields - allowed_fields
170+
171+
if disallowed_fields:
172+
raise ValidationError(
173+
{
174+
'error': 'Invalid fields in request.',
175+
'invalid_fields': list(disallowed_fields),
176+
}
177+
)
178+
179+
serializer = self.get_serializer(
180+
instance, data=request.data, partial=True
181+
)
182+
serializer.is_valid(raise_exception=True)
183+
self.perform_update(serializer)
95184

96-
pass
185+
return Response(serializer.data)

0 commit comments

Comments
 (0)