Skip to content

Commit 2715377

Browse files
committed
REST: Fix issues with comment-related events
When we introduced this functionality, we missed the fact that these resources use nested-style URLs that need to be specially handled. Fix this now. Signed-off-by: Stephen Finucane <[email protected]> Fixes: e3d8f75 ("REST: Add 'patch-comment-created', 'cover-comment-created' events") Cc: Siddhesh Poyarekar <[email protected]> Cc: DJ Delorie <[email protected]> Cc: Carlos O'Donell <[email protected]> (cherry picked from commit d05a2ff)
1 parent 40bf7ca commit 2715377

File tree

5 files changed

+88
-16
lines changed

5 files changed

+88
-16
lines changed

patchwork/api/base.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,40 @@ def get_url(self, obj, view_name, request, format):
139139
)
140140

141141

142+
class CoverCommentHyperlinkedIdentityField(HyperlinkedIdentityField):
143+
def get_url(self, obj, view_name, request, format):
144+
# Unsaved objects will not yet have a valid URL.
145+
if obj.pk is None:
146+
return None
147+
148+
return self.reverse(
149+
view_name,
150+
kwargs={
151+
'cover_id': obj.cover.id,
152+
'comment_id': obj.id,
153+
},
154+
request=request,
155+
format=format,
156+
)
157+
158+
159+
class PatchCommentHyperlinkedIdentityField(HyperlinkedIdentityField):
160+
def get_url(self, obj, view_name, request, format):
161+
# Unsaved objects will not yet have a valid URL.
162+
if obj.pk is None:
163+
return None
164+
165+
return self.reverse(
166+
view_name,
167+
kwargs={
168+
'patch_id': obj.patch.id,
169+
'comment_id': obj.id,
170+
},
171+
request=request,
172+
format=format,
173+
)
174+
175+
142176
class BaseHyperlinkedModelSerializer(HyperlinkedModelSerializer):
143177
def to_representation(self, instance):
144178
data = super(BaseHyperlinkedModelSerializer, self).to_representation(

patchwork/api/embedded.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
from patchwork.api.base import BaseHyperlinkedModelSerializer
1919
from patchwork.api.base import CheckHyperlinkedIdentityField
20+
from patchwork.api.base import CoverCommentHyperlinkedIdentityField
21+
from patchwork.api.base import PatchCommentHyperlinkedIdentityField
2022
from patchwork import models
2123

2224

@@ -127,6 +129,9 @@ class Meta:
127129

128130
class CoverCommentSerializer(SerializedRelatedField):
129131
class _Serializer(MboxMixin, WebURLMixin, BaseHyperlinkedModelSerializer):
132+
133+
url = CoverCommentHyperlinkedIdentityField('api-cover-comment-detail')
134+
130135
class Meta:
131136
model = models.CoverComment
132137
fields = (
@@ -136,7 +141,6 @@ class Meta:
136141
'msgid',
137142
'list_archive_url',
138143
'date',
139-
'name',
140144
)
141145
read_only_fields = fields
142146
versioned_fields = {
@@ -177,6 +181,9 @@ class Meta:
177181

178182
class PatchCommentSerializer(SerializedRelatedField):
179183
class _Serializer(MboxMixin, WebURLMixin, BaseHyperlinkedModelSerializer):
184+
185+
url = PatchCommentHyperlinkedIdentityField('api-patch-comment-detail')
186+
180187
class Meta:
181188
model = models.PatchComment
182189
fields = (
@@ -186,7 +193,6 @@ class Meta:
186193
'msgid',
187194
'list_archive_url',
188195
'date',
189-
'name',
190196
)
191197
read_only_fields = fields
192198
versioned_fields = {

patchwork/api/event.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from patchwork.api.embedded import SeriesSerializer
2020
from patchwork.api.embedded import UserSerializer
2121
from patchwork.api.filters import EventFilterSet
22+
from patchwork.api import utils
2223
from patchwork.models import Event
2324

2425

@@ -140,7 +141,7 @@ class EventList(ListAPIView):
140141
ordering = '-date'
141142

142143
def get_queryset(self):
143-
return Event.objects.all().prefetch_related(
144+
events = Event.objects.all().prefetch_related(
144145
'project',
145146
'patch__project',
146147
'series__project',
@@ -150,6 +151,24 @@ def get_queryset(self):
150151
'previous_delegate',
151152
'current_delegate',
152153
'created_check',
153-
'cover_comment',
154-
'patch_comment',
155154
)
155+
# NOTE(stephenfin): We need to exclude comment-related events because
156+
# until API v1.3, we didn't have an comment detail API to point to.
157+
# This goes against our pledge to version events in the docs but must
158+
# be done.
159+
# TODO(stephenfin): Make this more generic.
160+
if utils.has_version(self.request, '1.3'):
161+
events = events.prefetch_related(
162+
'cover_comment',
163+
'cover_comment__cover__project',
164+
'patch_comment',
165+
'patch_comment__patch__project',
166+
)
167+
else:
168+
events = events.exclude(
169+
category__in=[
170+
Event.CATEGORY_COVER_COMMENT_CREATED,
171+
Event.CATEGORY_PATCH_COMMENT_CREATED,
172+
]
173+
)
174+
return events

patchwork/tests/api/test_event.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
from patchwork.tests.api import utils
1313
from patchwork.tests.utils import create_check
1414
from patchwork.tests.utils import create_cover
15+
from patchwork.tests.utils import create_cover_comment
1516
from patchwork.tests.utils import create_maintainer
1617
from patchwork.tests.utils import create_patch
18+
from patchwork.tests.utils import create_patch_comment
1719
from patchwork.tests.utils import create_series
1820
from patchwork.tests.utils import create_state
1921

@@ -70,7 +72,7 @@ def _create_events(self):
7072
# patch-created, patch-completed, series-completed
7173
patch = create_patch(series=series)
7274
# cover-created
73-
create_cover(series=series)
75+
cover = create_cover(series=series)
7476
# check-created
7577
create_check(patch=patch)
7678
# patch-delegated, patch-state-changed
@@ -81,6 +83,9 @@ def _create_events(self):
8183
patch.state = state
8284
self.assertTrue(patch.is_editable(actor))
8385
patch.save()
86+
# patch-cover-created, cover-comment-created
87+
create_patch_comment(patch=patch, submitter=patch.submitter)
88+
create_cover_comment(cover=cover, submitter=cover.submitter)
8489

8590
return Event.objects.all()
8691

@@ -91,7 +96,9 @@ def test_list(self):
9196

9297
resp = self.client.get(self.api_url())
9398
self.assertEqual(status.HTTP_200_OK, resp.status_code)
94-
self.assertEqual(8, len(resp.data), [x['category'] for x in resp.data])
99+
self.assertEqual(
100+
10, len(resp.data), [x['category'] for x in resp.data]
101+
)
95102
for event_rsp in resp.data:
96103
event_obj = events.get(category=event_rsp['category'])
97104
self.assertSerialized(event_obj, event_rsp)
@@ -104,7 +111,7 @@ def test_list_filter_project(self):
104111

105112
resp = self.client.get(self.api_url(), {'project': project.pk})
106113
# All but one event belongs to the same project
107-
self.assertEqual(8, len(resp.data))
114+
self.assertEqual(10, len(resp.data))
108115

109116
resp = self.client.get(self.api_url(), {'project': 'invalidproject'})
110117
self.assertEqual(0, len(resp.data))
@@ -132,9 +139,9 @@ def test_list_filter_patch(self):
132139

133140
patch = events.get(category='patch-created').patch
134141
resp = self.client.get(self.api_url(), {'patch': patch.pk})
135-
# There should be five - patch-created, patch-completed, check-created,
136-
# patch-state-changed and patch-delegated
137-
self.assertEqual(5, len(resp.data))
142+
# There should be six - patch-created, patch-completed, check-created,
143+
# patch-state-changed, patch-delegated and patch-comment-created
144+
self.assertEqual(6, len(resp.data))
138145

139146
resp = self.client.get(self.api_url(), {'patch': 999999})
140147
self.assertEqual(0, len(resp.data))
@@ -145,8 +152,8 @@ def test_list_filter_cover(self):
145152

146153
cover = events.get(category='cover-created').cover
147154
resp = self.client.get(self.api_url(), {'cover': cover.pk})
148-
# There should only be one - cover-created
149-
self.assertEqual(1, len(resp.data))
155+
# There should be two - cover-created and cover-comment-created
156+
self.assertEqual(2, len(resp.data))
150157

151158
resp = self.client.get(self.api_url(), {'cover': 999999})
152159
self.assertEqual(0, len(resp.data))
@@ -170,7 +177,7 @@ def test_list_filter_actor(self):
170177

171178
# The final two events (patch-delegated, patch-state-changed)
172179
# have an actor set
173-
actor = events[0].actor
180+
actor = events.get(category='patch-delegated').actor
174181
resp = self.client.get(self.api_url(), {'actor': actor.pk})
175182
self.assertEqual(2, len(resp.data))
176183

@@ -185,14 +192,15 @@ def test_list_filter_actor_version_1_1(self):
185192
resp = self.client.get(
186193
self.api_url(version='1.1'), {'actor': 'foo-bar'}
187194
)
188-
self.assertEqual(len(events), len(resp.data))
195+
# we don't see the two comment-related fields
196+
self.assertEqual(len(events) - 2, len(resp.data))
189197

190198
def test_list_bug_335(self):
191199
"""Ensure we retrieve the embedded series project once."""
192200
for _ in range(3):
193201
self._create_events()
194202

195-
with self.assertNumQueries(27):
203+
with self.assertNumQueries(33):
196204
self.client.get(self.api_url())
197205

198206
def test_order_by_date_default(self):
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
fixes:
3+
- |
4+
Fix an issue whereby comment-based events would cause a HTTP 500 error
5+
for the events API (``/api/events``).

0 commit comments

Comments
 (0)