Skip to content

Commit

Permalink
REST: Add patch relations
Browse files Browse the repository at this point in the history
View relations and add/update/delete them as a maintainer. Maintainers
can only create relations of patches which are part of a project they
maintain. Because this is a writable many-many nested relationship, it
behaves a little unusually. In short:

- All operations use PATCH to the 'related' field of a patch

- To relate a patch to another patch, say 7 to 19, either:

    PATCH /api/patch/7  related := [19]
    PATCH /api/patch/19 related := [7]

- To delete a patch from a relation, say 1, 21 and 42 are related but we
  only want it to be 1 and 42:

    PATCH /api/patch/21 related := []

  * You _cannot_ remove a patch from a relation by patching another
    patch in the relation: I'm trying to avoid read-modify-write loops.

  * Relations that would be left with just 1 patch are deleted. This is
    only ensured in the API - the admin interface will let you do this.

- Break-before-make: if you have [1, 12, 24] and [7, 15, 42] and you want
  to end up with [1, 12, 15, 42], you have to remove 15 from the second
  relation first:

    PATCH /api/patch/1 related := [15] will fail with 409 Conflict.

  Instead do:

    PATCH /api/patch/15 related := []
    PATCH /api/patch/1  related := [15]
       -> 200 OK, [1, 12, 15, 42] and [7, 42] are the resulting relations

Signed-off-by: Mete Polat <metepolat2000@gmail.com>
Signed-off-by: Stephen Finucane <stephen@that.guru>
Signed-off-by: Daniel Axtens <dja@axtens.net>
  • Loading branch information
metp authored and daxtens committed Mar 16, 2020
1 parent 27c2acf commit 83f364a
Show file tree
Hide file tree
Showing 11 changed files with 656 additions and 6 deletions.
44 changes: 44 additions & 0 deletions docs/api/schemas/latest/patchwork.yaml
Expand Up @@ -352,6 +352,7 @@ paths:
- patch-created
- patch-completed
- patch-state-changed
- patch-relation-changed
- patch-delegated
- check-created
- series-created
Expand Down Expand Up @@ -390,6 +391,7 @@ paths:
- $ref: '#/components/schemas/EventPatchCreated'
- $ref: '#/components/schemas/EventPatchCompleted'
- $ref: '#/components/schemas/EventPatchStateChanged'
- $ref: '#/components/schemas/EventPatchRelationChanged'
- $ref: '#/components/schemas/EventPatchDelegated'
- $ref: '#/components/schemas/EventCheckCreated'
- $ref: '#/components/schemas/EventSeriesCreated'
Expand All @@ -403,6 +405,8 @@ paths:
'#/components/schemas/EventPatchCompleted'
patch-state-changed: >
'#/components/schemas/EventPatchStateChanged'
patch-relation-changed: >
'#/components/schemas/EventPatchRelationChanged'
patch-delegated: >
'#/components/schemas/EventPatchDelegated'
check-created: '#/components/schemas/EventCheckCreated'
Expand Down Expand Up @@ -552,6 +556,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- patches
put:
Expand Down Expand Up @@ -595,6 +605,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- patches
/api/patches/{id}/comments/:
Expand Down Expand Up @@ -1721,6 +1737,24 @@ components:
current_state:
title: Current state
type: string
EventPatchRelationChanged:
allOf:
- $ref: '#/components/schemas/EventBase'
- type: object
properties:
category:
enum:
- patch-relation-changed
payload:
properties:
patch:
$ref: '#/components/schemas/PatchEmbedded'
previous_relation:
title: Previous relation
type: string
current_relation:
title: Current relation
type: string
EventPatchDelegated:
allOf:
- $ref: '#/components/schemas/EventBase'
Expand Down Expand Up @@ -1893,6 +1927,11 @@ components:
items:
type: string
readOnly: true
related:
title: Relations
type: array
items:
type: string
PatchDetail:
allOf:
- $ref: '#/components/schemas/PatchList'
Expand Down Expand Up @@ -1943,6 +1982,11 @@ components:
title: Delegate
type: integer
nullable: true
related:
title: Relations
type: array
items:
type: string
Person:
type: object
properties:
Expand Down
60 changes: 60 additions & 0 deletions docs/api/schemas/patchwork.j2
Expand Up @@ -359,6 +359,9 @@ paths:
- patch-created
- patch-completed
- patch-state-changed
{% if version >= (1, 2) %}
- patch-relation-changed
{% endif %}
- patch-delegated
- check-created
- series-created
Expand Down Expand Up @@ -397,6 +400,9 @@ paths:
- $ref: '#/components/schemas/EventPatchCreated'
- $ref: '#/components/schemas/EventPatchCompleted'
- $ref: '#/components/schemas/EventPatchStateChanged'
{% if version >= (1, 2) %}
- $ref: '#/components/schemas/EventPatchRelationChanged'
{% endif %}
- $ref: '#/components/schemas/EventPatchDelegated'
- $ref: '#/components/schemas/EventCheckCreated'
- $ref: '#/components/schemas/EventSeriesCreated'
Expand All @@ -410,6 +416,10 @@ paths:
'#/components/schemas/EventPatchCompleted'
patch-state-changed: >
'#/components/schemas/EventPatchStateChanged'
{% if version >= (1, 2) %}
patch-relation-changed: >
'#/components/schemas/EventPatchRelationChanged'
{% endif %}
patch-delegated: >
'#/components/schemas/EventPatchDelegated'
check-created: '#/components/schemas/EventCheckCreated'
Expand Down Expand Up @@ -561,6 +571,14 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
{% if version >= (1, 2) %}
'409':
description: Conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
{% endif %}
tags:
- patches
put:
Expand Down Expand Up @@ -604,6 +622,14 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
{% if version >= (1, 2) %}
'409':
description: Conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
{% endif %}
tags:
- patches
/api/{{ version_url }}patches/{id}/comments/:
Expand Down Expand Up @@ -1777,6 +1803,26 @@ components:
current_state:
title: Current state
type: string
{% if version >= (1, 1) %}
EventPatchRelationChanged:
allOf:
- $ref: '#/components/schemas/EventBase'
- type: object
properties:
category:
enum:
- patch-relation-changed
payload:
properties:
patch:
$ref: '#/components/schemas/PatchEmbedded'
previous_relation:
title: Previous relation
type: string
current_relation:
title: Current relation
type: string
{% endif %}
EventPatchDelegated:
allOf:
- $ref: '#/components/schemas/EventBase'
Expand Down Expand Up @@ -1955,6 +2001,13 @@ components:
items:
type: string
readOnly: true
{% if version >= (1, 2) %}
related:
title: Relations
type: array
items:
type: string
{% endif %}
PatchDetail:
allOf:
- $ref: '#/components/schemas/PatchList'
Expand Down Expand Up @@ -2005,6 +2058,13 @@ components:
title: Delegate
type: integer
nullable: true
{% if version >= (1, 2) %}
related:
title: Relations
type: array
items:
type: string
{% endif %}
Person:
type: object
properties:
Expand Down
18 changes: 18 additions & 0 deletions docs/api/schemas/v1.1/patchwork.yaml
Expand Up @@ -1551,6 +1551,24 @@ components:
current_state:
title: Current state
type: string
EventPatchRelationChanged:
allOf:
- $ref: '#/components/schemas/EventBase'
- type: object
properties:
category:
enum:
- patch-relation-changed
payload:
properties:
patch:
$ref: '#/components/schemas/PatchEmbedded'
previous_relation:
title: Previous relation
type: string
current_relation:
title: Current relation
type: string
EventPatchDelegated:
allOf:
- $ref: '#/components/schemas/EventBase'
Expand Down
44 changes: 44 additions & 0 deletions docs/api/schemas/v1.2/patchwork.yaml
Expand Up @@ -352,6 +352,7 @@ paths:
- patch-created
- patch-completed
- patch-state-changed
- patch-relation-changed
- patch-delegated
- check-created
- series-created
Expand Down Expand Up @@ -390,6 +391,7 @@ paths:
- $ref: '#/components/schemas/EventPatchCreated'
- $ref: '#/components/schemas/EventPatchCompleted'
- $ref: '#/components/schemas/EventPatchStateChanged'
- $ref: '#/components/schemas/EventPatchRelationChanged'
- $ref: '#/components/schemas/EventPatchDelegated'
- $ref: '#/components/schemas/EventCheckCreated'
- $ref: '#/components/schemas/EventSeriesCreated'
Expand All @@ -403,6 +405,8 @@ paths:
'#/components/schemas/EventPatchCompleted'
patch-state-changed: >
'#/components/schemas/EventPatchStateChanged'
patch-relation-changed: >
'#/components/schemas/EventPatchRelationChanged'
patch-delegated: >
'#/components/schemas/EventPatchDelegated'
check-created: '#/components/schemas/EventCheckCreated'
Expand Down Expand Up @@ -552,6 +556,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- patches
put:
Expand Down Expand Up @@ -595,6 +605,12 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/Error'
'409':
description: Conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
tags:
- patches
/api/1.2/patches/{id}/comments/:
Expand Down Expand Up @@ -1721,6 +1737,24 @@ components:
current_state:
title: Current state
type: string
EventPatchRelationChanged:
allOf:
- $ref: '#/components/schemas/EventBase'
- type: object
properties:
category:
enum:
- patch-relation-changed
payload:
properties:
patch:
$ref: '#/components/schemas/PatchEmbedded'
previous_relation:
title: Previous relation
type: string
current_relation:
title: Current relation
type: string
EventPatchDelegated:
allOf:
- $ref: '#/components/schemas/EventBase'
Expand Down Expand Up @@ -1893,6 +1927,11 @@ components:
items:
type: string
readOnly: true
related:
title: Relations
type: array
items:
type: string
PatchDetail:
allOf:
- $ref: '#/components/schemas/PatchList'
Expand Down Expand Up @@ -1943,6 +1982,11 @@ components:
title: Delegate
type: integer
nullable: true
related:
title: Relations
type: array
items:
type: string
Person:
type: object
properties:
Expand Down
25 changes: 25 additions & 0 deletions patchwork/api/embedded.py
Expand Up @@ -14,6 +14,7 @@
from rest_framework.serializers import CharField
from rest_framework.serializers import SerializerMethodField
from rest_framework.serializers import PrimaryKeyRelatedField
from rest_framework.serializers import ValidationError

from patchwork.api.base import BaseHyperlinkedModelSerializer
from patchwork.api.base import CheckHyperlinkedIdentityField
Expand Down Expand Up @@ -138,6 +139,30 @@ class Meta:
}


class PatchRelationSerializer(BaseHyperlinkedModelSerializer):
"""Hide the PatchRelation model, just show the list"""
patches = PatchSerializer(many=True)

def to_internal_value(self, data):
if not isinstance(data, type([])):
raise ValidationError(
"Patch relations must be specified as a list of patch IDs"
)
result = super(PatchRelationSerializer, self).to_internal_value(
{'patches': data}
)
return result

def to_representation(self, instance):
data = super(PatchRelationSerializer, self).to_representation(instance)
data = data['patches']
return data

class Meta:
model = models.PatchRelation
fields = ('patches',)


class PersonSerializer(SerializedRelatedField):

class _Serializer(BaseHyperlinkedModelSerializer):
Expand Down
3 changes: 3 additions & 0 deletions patchwork/api/event.py
Expand Up @@ -13,6 +13,7 @@
from patchwork.api.embedded import CheckSerializer
from patchwork.api.embedded import CoverLetterSerializer
from patchwork.api.embedded import PatchSerializer
from patchwork.api.embedded import PatchRelationSerializer
from patchwork.api.embedded import ProjectSerializer
from patchwork.api.embedded import SeriesSerializer
from patchwork.api.embedded import UserSerializer
Expand All @@ -33,6 +34,8 @@ class EventSerializer(ModelSerializer):
current_delegate = UserSerializer()
created_check = SerializerMethodField()
created_check = CheckSerializer()
previous_relation = PatchRelationSerializer(read_only=True)
current_relation = PatchRelationSerializer(read_only=True)

_category_map = {
Event.CATEGORY_COVER_CREATED: ['cover'],
Expand Down

0 comments on commit 83f364a

Please sign in to comment.