Skip to content

Commit 88f5605

Browse files
Raxel Gutierrezdaxtens
authored andcommitted
api: add comments detail endpoint
Add new endpoint for patch and cover comments at api/.../comments/<comment_id>. This involves updating the API version to v1.3 to reflect the new endpoints as a minor change, following the usual semantic versioning convention. The endpoint will make it possible to use the REST API to update the new `addressed` field for individual patch and cover comments with JavaScript on the client side. In the process of these changes, clean up the use of the CurrentPatchDefault context so that it exists in base.py and can be used throughout the API (e.g. Check and Comment REST endpoints). The tests cover retrieval and update requests and also handle calls from the various API versions. Also, they cover permissions for update requests and handle invalid update values for the new `addressed` field. Signed-off-by: Raxel Gutierrez <raxel@google.com> [dja: changes to not conflict with, and to adopt the changes in, fecf7c8 various other minor changes as described on list] Signed-off-by: Daniel Axtens <dja@axtens.net>
1 parent 9c89061 commit 88f5605

File tree

7 files changed

+679
-83
lines changed

7 files changed

+679
-83
lines changed

docs/api/schemas/generate-schemas.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
yaml = None
1515

1616
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
17-
VERSIONS = [(1, 0), (1, 1), (1, 2), None]
18-
LATEST_VERSION = (1, 2)
17+
VERSIONS = [(1, 0), (1, 1), (1, 2), (1, 3), None]
18+
LATEST_VERSION = (1, 3)
1919

2020

2121
def generate_schemas():

docs/api/schemas/patchwork.j2

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,74 @@ paths:
324324
$ref: '#/components/schemas/Error'
325325
tags:
326326
- comments
327+
{% if version >= (1, 3) %}
328+
/api/{{ version_url }}covers/{cover_id}/comments/{comment_id}/:
329+
parameters:
330+
- in: path
331+
name: cover_id
332+
description: A unique integer value identifying the parent cover.
333+
required: true
334+
schema:
335+
title: Cover ID
336+
type: integer
337+
- in: path
338+
name: comment_id
339+
description: A unique integer value identifying this comment.
340+
required: true
341+
schema:
342+
title: Comment ID
343+
type: integer
344+
get:
345+
description: Show a cover comment.
346+
operationId: cover_comments_read
347+
responses:
348+
'200':
349+
description: ''
350+
content:
351+
application/json:
352+
schema:
353+
$ref: '#/components/schemas/Comment'
354+
'404':
355+
description: Not found
356+
content:
357+
application/json:
358+
schema:
359+
$ref: '#/components/schemas/Error'
360+
tags:
361+
- comments
362+
patch:
363+
description: Update a cover comment (partial).
364+
operationId: cover_comments_partial_update
365+
requestBody:
366+
$ref: '#/components/requestBodies/Comment'
367+
responses:
368+
'200':
369+
description: ''
370+
content:
371+
application/json:
372+
schema:
373+
$ref: '#/components/schemas/Comment'
374+
'400':
375+
description: Invalid Request
376+
content:
377+
application/json:
378+
schema:
379+
$ref: '#/components/schemas/ErrorCommentUpdate'
380+
'403':
381+
description: Forbidden
382+
content:
383+
application/json:
384+
schema:
385+
$ref: '#/components/schemas/Error'
386+
'404':
387+
description: Not found
388+
content:
389+
application/json:
390+
schema:
391+
$ref: '#/components/schemas/Error'
392+
tags:
393+
- comments
394+
{% endif %}
327395
/api/{{ version_url }}events/:
328396
get:
329397
description: List events.
@@ -656,6 +724,74 @@ paths:
656724
$ref: '#/components/schemas/Error'
657725
tags:
658726
- comments
727+
{% if version >= (1, 3) %}
728+
/api/{{ version_url }}patches/{patch_id}/comments/{comment_id}/:
729+
parameters:
730+
- in: path
731+
name: patch_id
732+
description: A unique integer value identifying the parent patch.
733+
required: true
734+
schema:
735+
title: Patch ID
736+
type: integer
737+
- in: path
738+
name: comment_id
739+
description: A unique integer value identifying this comment.
740+
required: true
741+
schema:
742+
title: Comment ID
743+
type: integer
744+
get:
745+
description: Show a patch comment.
746+
operationId: patch_comments_read
747+
responses:
748+
'200':
749+
description: ''
750+
content:
751+
application/json:
752+
schema:
753+
$ref: '#/components/schemas/Comment'
754+
'404':
755+
description: Not found
756+
content:
757+
application/json:
758+
schema:
759+
$ref: '#/components/schemas/Error'
760+
tags:
761+
- comments
762+
patch:
763+
description: Update a patch comment (partial).
764+
operationId: patch_comments_partial_update
765+
requestBody:
766+
$ref: '#/components/requestBodies/Comment'
767+
responses:
768+
'200':
769+
description: ''
770+
content:
771+
application/json:
772+
schema:
773+
$ref: '#/components/schemas/Comment'
774+
'400':
775+
description: Invalid Request
776+
content:
777+
application/json:
778+
schema:
779+
$ref: '#/components/schemas/ErrorCommentUpdate'
780+
'403':
781+
description: Forbidden
782+
content:
783+
application/json:
784+
schema:
785+
$ref: '#/components/schemas/Error'
786+
'404':
787+
description: Not found
788+
content:
789+
application/json:
790+
schema:
791+
$ref: '#/components/schemas/Error'
792+
tags:
793+
- comments
794+
{% endif %}
659795
/api/{{ version_url }}patches/{patch_id}/checks/:
660796
parameters:
661797
- in: path
@@ -1277,6 +1413,14 @@ components:
12771413
application/x-www-form-urlencoded:
12781414
schema:
12791415
$ref: '#/components/schemas/CheckCreate'
1416+
{% if version >= (1, 3) %}
1417+
Comment:
1418+
required: true
1419+
content:
1420+
application/json:
1421+
schema:
1422+
$ref: '#/components/schemas/CommentUpdate'
1423+
{% endif %}
12801424
Patch:
12811425
required: true
12821426
content:
@@ -1586,6 +1730,17 @@ components:
15861730
additionalProperties:
15871731
type: string
15881732
readOnly: true
1733+
{% if version >= (1, 3) %}
1734+
addressed:
1735+
title: Addressed
1736+
type: boolean
1737+
CommentUpdate:
1738+
type: object
1739+
properties:
1740+
addressed:
1741+
title: Addressed
1742+
type: boolean
1743+
{% endif %}
15891744
CoverList:
15901745
type: object
15911746
properties:
@@ -2659,6 +2814,16 @@ components:
26592814
items:
26602815
type: string
26612816
readOnly: true
2817+
{% if version >= (1, 3) %}
2818+
ErrorCommentUpdate:
2819+
type: object
2820+
properties:
2821+
addressed:
2822+
title: Addressed
2823+
type: array
2824+
items:
2825+
type: string
2826+
{% endif %}
26622827
ErrorPatchUpdate:
26632828
type: object
26642829
properties:

patchwork/api/base.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#
44
# SPDX-License-Identifier: GPL-2.0-or-later
55

6+
import rest_framework
67

78
from django.conf import settings
89
from django.shortcuts import get_object_or_404
@@ -15,6 +16,37 @@
1516
from patchwork.api import utils
1617

1718

19+
DRF_VERSION = tuple(int(x) for x in rest_framework.__version__.split('.'))
20+
21+
22+
if DRF_VERSION > (3, 11):
23+
class CurrentPatchDefault(object):
24+
requires_context = True
25+
26+
def __call__(self, serializer_field):
27+
return serializer_field.context['request'].patch
28+
29+
class CurrentCoverDefault(object):
30+
requires_context = True
31+
32+
def __call__(self, serializer_field):
33+
return serializer_field.context['request'].cover
34+
else:
35+
class CurrentPatchDefault(object):
36+
def set_context(self, serializer_field):
37+
self.patch = serializer_field.context['request'].patch
38+
39+
def __call__(self):
40+
return self.patch
41+
42+
class CurrentCoverDefault(object):
43+
def set_context(self, serializer_field):
44+
self.patch = serializer_field.context['request'].cover
45+
46+
def __call__(self):
47+
return self.cover
48+
49+
1850
class LinkHeaderPagination(PageNumberPagination):
1951
"""Provide pagination based on rfc5988.
2052
@@ -44,7 +76,10 @@ def get_paginated_response(self, data):
4476

4577

4678
class PatchworkPermission(permissions.BasePermission):
47-
"""This permission works for Project and Patch model objects"""
79+
"""
80+
This permission works for Project, Patch, PatchComment
81+
and CoverComment model objects
82+
"""
4883
def has_object_permission(self, request, view, obj):
4984
# read only for everyone
5085
if request.method in permissions.SAFE_METHODS:

patchwork/api/check.py

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

66
from django.http.request import QueryDict
7-
import rest_framework
7+
88
from rest_framework.exceptions import PermissionDenied
99
from rest_framework.generics import get_object_or_404
1010
from rest_framework.generics import ListCreateAPIView
@@ -16,30 +16,13 @@
1616

1717
from patchwork.api.base import CheckHyperlinkedIdentityField
1818
from patchwork.api.base import MultipleFieldLookupMixin
19+
from patchwork.api.base import CurrentPatchDefault
1920
from patchwork.api.embedded import UserSerializer
2021
from patchwork.api.filters import CheckFilterSet
2122
from patchwork.models import Check
2223
from patchwork.models import Patch
2324

2425

25-
DRF_VERSION = tuple(int(x) for x in rest_framework.__version__.split('.'))
26-
27-
28-
if DRF_VERSION > (3, 11):
29-
class CurrentPatchDefault(object):
30-
requires_context = True
31-
32-
def __call__(self, serializer_field):
33-
return serializer_field.context['request'].patch
34-
else:
35-
class CurrentPatchDefault(object):
36-
def set_context(self, serializer_field):
37-
self.patch = serializer_field.context['request'].patch
38-
39-
def __call__(self):
40-
return self.patch
41-
42-
4326
class CheckSerializer(HyperlinkedModelSerializer):
4427

4528
url = CheckHyperlinkedIdentityField('api-check-detail')

0 commit comments

Comments
 (0)