5
5
6
6
from rest_framework .generics import ListAPIView
7
7
from rest_framework .generics import RetrieveAPIView
8
+ from rest_framework .generics import UpdateAPIView
8
9
from rest_framework .serializers import SerializerMethodField
10
+ from rest_framework .exceptions import ValidationError
11
+ from rest_framework .response import Response
9
12
10
13
from patchwork .api .base import BaseHyperlinkedModelSerializer
11
14
from patchwork .api .base import PatchworkPermission
14
17
from patchwork .api .embedded import PatchSerializer
15
18
from patchwork .api .embedded import PersonSerializer
16
19
from patchwork .api .embedded import ProjectSerializer
20
+ from patchwork .api .embedded import SeriesSerializer as RelatedSeriesSerializer
17
21
from patchwork .models import Series
18
22
19
23
@@ -24,6 +28,51 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer):
24
28
mbox = SerializerMethodField ()
25
29
cover_letter = CoverSerializer (read_only = True )
26
30
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 )
27
76
28
77
def get_web_url (self , instance ):
29
78
request = self .context .get ('request' )
@@ -44,6 +93,10 @@ class Meta:
44
93
'date' ,
45
94
'submitter' ,
46
95
'version' ,
96
+ 'previous_series' ,
97
+ 'subsequent_series' ,
98
+ 'required_series' ,
99
+ 'required_by_series' ,
47
100
'total' ,
48
101
'received_total' ,
49
102
'received_all' ,
@@ -76,7 +129,14 @@ class SeriesMixin(object):
76
129
def get_queryset (self ):
77
130
return (
78
131
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
+ )
80
140
.select_related ('submitter' , 'project' )
81
141
)
82
142
@@ -90,7 +150,36 @@ class SeriesList(SeriesMixin, ListAPIView):
90
150
ordering = 'id'
91
151
92
152
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 )
95
184
96
- pass
185
+ return Response ( serializer . data )
0 commit comments