Skip to content

Commit 2240516

Browse files
api: add series versioning updates
Add PUT and PATCH methods to the series detail view, both are handled as partial updates and the only accepted field for now is 'supersedes'. To update which series are superseded by the current one the user must provide the complete list. Signed-off-by: Victor Accarini <[email protected]>
1 parent 6e7a961 commit 2240516

File tree

2 files changed

+69
-11
lines changed

2 files changed

+69
-11
lines changed

patchwork/api/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def get_paginated_response(self, data):
9696

9797
class PatchworkPermission(permissions.BasePermission):
9898
"""
99-
This permission works for Project, Patch, PatchComment
99+
This permission works for Project, Patch, Series, PatchComment
100100
and CoverComment model objects
101101
"""
102102

patchwork/api/series.py

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
# SPDX-License-Identifier: GPL-2.0-or-later
55

66
from rest_framework.generics import ListAPIView
7-
from rest_framework.generics import RetrieveAPIView
8-
from rest_framework.serializers import (
9-
SerializerMethodField,
10-
HyperlinkedRelatedField,
11-
)
7+
from rest_framework.generics import RetrieveUpdateAPIView
8+
from rest_framework.serializers import SerializerMethodField
9+
from rest_framework.serializers import HyperlinkedRelatedField
10+
from rest_framework.serializers import ValidationError
1211

1312
from patchwork.api.base import BaseHyperlinkedModelSerializer
1413
from patchwork.api.base import PatchworkPermission
@@ -34,8 +33,9 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer):
3433
read_only=True, view_name='api-series-detail', many=True
3534
)
3635
supersedes = HyperlinkedRelatedField(
37-
read_only=True,
3836
view_name='api-series-detail',
37+
queryset=Series.objects.all(),
38+
required=False,
3939
many=True,
4040
)
4141
superseded = HyperlinkedRelatedField(
@@ -44,6 +44,32 @@ class SeriesSerializer(BaseHyperlinkedModelSerializer):
4444
many=True,
4545
)
4646

47+
def update(self, instance, validated_data, *args, **kwargs):
48+
allowed_fields = {'supersedes'}
49+
incoming_fields = set(validated_data.keys())
50+
51+
if not incoming_fields.issubset(allowed_fields):
52+
invalid_fields = incoming_fields - allowed_fields
53+
raise ValidationError(
54+
{
55+
'detail': 'Cannot update fields: '
56+
f"{', '.join(invalid_fields)}. Only 'supersedes' can be "
57+
'updated.'
58+
}
59+
)
60+
61+
if 'supersedes' in validated_data:
62+
supersedes = validated_data.pop('supersedes', [])
63+
64+
try:
65+
instance.supersedes.set(supersedes)
66+
except Series.DoesNotExist:
67+
raise ValidationError(
68+
{'detail': 'Unable to find one of the referenced series'}
69+
)
70+
71+
return instance
72+
4773
def get_web_url(self, instance):
4874
request = self.context.get('request')
4975
return request.build_absolute_uri(instance.get_absolute_url())
@@ -100,7 +126,6 @@ class Meta:
100126
'patches',
101127
'dependencies',
102128
'dependents',
103-
'supersedes',
104129
'superseded',
105130
)
106131
versioned_fields = {
@@ -140,7 +165,40 @@ class SeriesList(SeriesMixin, ListAPIView):
140165
ordering = 'id'
141166

142167

143-
class SeriesDetail(SeriesMixin, RetrieveAPIView):
144-
"""Show a series."""
168+
class SeriesDetail(SeriesMixin, RetrieveUpdateAPIView):
169+
"""Show a series.
170+
171+
retrieve:
172+
Return the details of a series.
173+
174+
update:
175+
Only updates the 'supersedes' field of a series. Replaces the whole set
176+
of superseded series.
177+
178+
::
179+
180+
Instance:
181+
instance.supersedes = [
182+
'http://example.com/api/series/1/',
183+
'http://example.com/api/series/2/',
184+
'http://example.com/api/series/5/'
185+
]
186+
187+
Request:
188+
PUT/PATCH {
189+
"supersedes": [
190+
'http://example.com/api/series/1/',
191+
'http://example.com/api/series/8/'
192+
]
193+
}
194+
195+
Result:
196+
instance.supersedes = [
197+
'http://example.com/api/series/1/',
198+
'http://example.com/api/series/8/'
199+
]
200+
"""
145201

146-
pass
202+
# PUT operation will behave as a partial update
203+
def put(self, request, *args, **kwargs):
204+
return self.partial_update(request, *args, **kwargs)

0 commit comments

Comments
 (0)