Skip to content

Commit

Permalink
Create new contact API
Browse files Browse the repository at this point in the history
With this API, there is no inheritance between release and global
components. Instead, what would previously be inherited is stored
directly on a release component.

The relationship between a component and a contact is simplified to a
regular Many-to-Many relationship with an intermediate model to point to
role for that contact.

In this patch, new API is added and old tests are adapted to verify it
is correct. There is database schema migration, but the current data is
not migrated.

JIRA: PDC-1039
  • Loading branch information
ycheng-aa authored and lubomir committed Oct 5, 2015
1 parent d8ba479 commit 45220db
Show file tree
Hide file tree
Showing 7 changed files with 405 additions and 7 deletions.
24 changes: 23 additions & 1 deletion pdc/apps/component/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
from pdc.apps.contact.models import (Person,
Maillist,
ContactRole,
RoleContact)
RoleContact,
GlobalComponentRoleContact,
ReleaseComponentRoleContact)
from pdc.apps.common.filters import (ComposeFilterSet,
value_is_not_empty,
MultiValueFilter,
Expand Down Expand Up @@ -298,3 +300,23 @@ class Meta:
model = ReleaseComponentRelationship
fields = ('type', 'from_component_release', 'from_component_name', 'to_component_release',
'to_component_name')


class GlobalComponentRoleContactFilter(RoleContactFilter):
component_name = MultiValueFilter(name='component__name')
role = MultiValueFilter(name='contact_role__name')
contact_id = MultiValueFilter(name='contact')

class Meta:
model = GlobalComponentRoleContact
fields = ('role', 'email', 'username', 'mail_name', 'component_name', 'contact_id')


class ReleaseComponentRoleContactFilter(RoleContactFilter):
component_id = MultiValueFilter(name='component__id')
role = MultiValueFilter(name='contact_role__name')
contact_id = MultiValueFilter(name='contact')

class Meta:
model = ReleaseComponentRoleContact
fields = ('role', 'email', 'username', 'mail_name', 'component_id', 'contact_id')
28 changes: 26 additions & 2 deletions pdc/apps/component/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

from rest_framework import serializers

from pdc.apps.contact.models import Contact, ContactRole
from pdc.apps.contact.serializers import RoleContactSerializer
from pdc.apps.contact.models import Contact, ContactRole, GlobalComponentRoleContact, ReleaseComponentRoleContact
from pdc.apps.contact.serializers import RoleContactSerializer, ContactField
from pdc.apps.common.serializers import DynamicFieldsSerializerMixin, LabelSerializer, StrictSerializerMixin
from pdc.apps.common.fields import ChoiceSlugField
from pdc.apps.release.models import Release
Expand Down Expand Up @@ -549,3 +549,27 @@ class ReleaseComponentRelationshipSerializer(StrictSerializerMixin, serializers.
class Meta:
model = ReleaseComponentRelationship
fields = ('id', 'type', 'from_component', 'to_component')


class GlobalComponentRoleContactSerializer(StrictSerializerMixin, serializers.ModelSerializer):
component_name = serializers.SlugRelatedField(source='component', slug_field='name', read_only=False,
queryset=GlobalComponent.objects.all())
role = serializers.SlugRelatedField(source='contact_role', slug_field='name',
read_only=False, queryset=ContactRole.objects.all())
contact = ContactField()

class Meta:
model = GlobalComponentRoleContact
fields = ('id', 'component_name', 'role', 'contact')


class ReleaseComponentRoleContactSerializer(StrictSerializerMixin, serializers.ModelSerializer):
component_id = serializers.SlugRelatedField(source='component', slug_field='id', read_only=False,
queryset=ReleaseComponent.objects.all())
role = serializers.SlugRelatedField(source='contact_role', slug_field='name',
read_only=False, queryset=ContactRole.objects.all())
contact = ContactField()

class Meta:
model = ReleaseComponentRoleContact
fields = ('id', 'component_id', 'role', 'contact')
215 changes: 214 additions & 1 deletion pdc/apps/component/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
from rest_framework.test import APITestCase

from pdc.apps.common.test_utils import TestCaseWithChangeSetMixin
from pdc.apps.contact.models import Person, Maillist, RoleContact, ContactRole
from pdc.apps.contact.models import Person, Maillist, RoleContact, ContactRole, GlobalComponentRoleContact,\
ReleaseComponentRoleContact
from pdc.apps.release.models import Release, ProductVersion
from . import models

Expand Down Expand Up @@ -2515,3 +2516,215 @@ def test_delete_group(self):

response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)


class GlobalComponentContactInfoRESTTestCase(TestCaseWithChangeSetMixin, APITestCase):
fixtures = [
"pdc/apps/component/fixtures/tests/global_component.json",
"pdc/apps/contact/fixtures/tests/contact_role.json",
"pdc/apps/contact/fixtures/tests/maillist.json",
"pdc/apps/contact/fixtures/tests/person.json",
"pdc/apps/component/fixtures/tests/upstream.json"
]

def setUp(self):
super(GlobalComponentContactInfoRESTTestCase, self).setUp()
person = Person.objects.get(username='person1')
maillist = Maillist.objects.get(mail_name="maillist2")
pm_type = ContactRole.objects.get(name='pm')
qe_type = ContactRole.objects.get(name='qe_ack')

python = models.GlobalComponent.objects.get(name='MySQL-python')
java = models.GlobalComponent.objects.get(name='java')

GlobalComponentRoleContact.objects.create(component=python, contact_role=pm_type, contact=person)
GlobalComponentRoleContact.objects.create(component=java, contact_role=qe_type, contact=maillist)

def test_list_global_component_contacts(self):
url = reverse('globalcomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data.get('count'), 2)
results = response.data.get('results')
self.assertEqual(results[0]['role'], 'pm')
self.assertEqual(results[0]['contact']['email'], 'person1@test.com')

self.assertEqual(results[1]['role'], 'qe_ack')
self.assertEqual(results[1]['contact']['mail_name'], 'maillist2')

def test_retrieve_global_component_contacts(self):
url = reverse('globalcomponentcontacts-detail', kwargs={'pk': 2})
response = self.client.get(url, format='json')
result = response.data
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(result['role'], 'qe_ack')
self.assertEqual(result['contact']['mail_name'], 'maillist2')
self.assertEqual(result['contact']['email'], 'maillist2@test.com')

def test_destroy_global_component_contacts(self):
url = reverse('globalcomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.data.get('count'), 2)
url = reverse('globalcomponentcontacts-detail', kwargs={'pk': 2})
self.client.delete(url, format='json')
url = reverse('globalcomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.data.get('count'), 1)

def test_filter_global_component_contacts(self):
url = reverse('globalcomponentcontacts-list')
data = {'contact_role': 'pm'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 1)

data = {'contact_role': 'no_such_role'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

data = {'contact_role': 'qe_ack', 'mail_name': 'maillist2'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 1)

# should not get anything
data = {'contact_role': 'qe_ack', 'username': 'person1'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

# should not get anything
data = {'contact_role': 'pm', 'mail_name': 'maillist2'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

data = {'component_name': 'java'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 1)

data = {'component_name': 'no_component'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

def test_create_global_component_contacts(self):
url = reverse('globalcomponentcontacts-list')
data = {'component_name': 'python', 'role': 'pm', 'contact': {'mail_name': 'maillist2'}}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse('globalcomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.data.get('count'), 3)

def test_patch_global_component_contacts(self):
url = reverse('globalcomponentcontacts-detail', kwargs={'pk': 2})
data = {"contact": {"username": "person2", "email": "person2@test.com"}}
response = self.client.patch(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
response.data['contact'].pop('id')
self.assertEqual(response.data['contact'], data['contact'])
self.assertNumChanges([1])


class ReleaseComponentContactInfoRESTTestCase(TestCaseWithChangeSetMixin, APITestCase):
fixtures = [
"pdc/apps/component/fixtures/tests/global_component.json",
"pdc/apps/release/fixtures/tests/release.json",
"pdc/apps/component/fixtures/tests/release_component.json",
"pdc/apps/contact/fixtures/tests/contact_role.json",
"pdc/apps/contact/fixtures/tests/maillist.json",
"pdc/apps/contact/fixtures/tests/person.json",
"pdc/apps/component/fixtures/tests/upstream.json"
]

def setUp(self):
super(ReleaseComponentContactInfoRESTTestCase, self).setUp()
person = Person.objects.get(username='person1')
maillist = Maillist.objects.get(mail_name="maillist2")
pm_type = ContactRole.objects.get(name='pm')
qe_type = ContactRole.objects.get(name='qe_ack')

python = models.ReleaseComponent.objects.get(name='MySQL-python')
python27 = models.ReleaseComponent.objects.get(name='python27')

ReleaseComponentRoleContact.objects.create(component=python, contact_role=pm_type, contact=person)
ReleaseComponentRoleContact.objects.create(component=python27, contact_role=qe_type, contact=maillist)

def test_list_release_component_contacts(self):
url = reverse('releasecomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data.get('count'), 2)
results = response.data.get('results')
self.assertEqual(results[0]['role'], 'pm')
self.assertEqual(results[0]['contact']['email'], 'person1@test.com')

self.assertEqual(results[1]['role'], 'qe_ack')
self.assertEqual(results[1]['contact']['mail_name'], 'maillist2')

def test_retrieve_release_component_contacts(self):
url = reverse('releasecomponentcontacts-detail', kwargs={'pk': 2})
response = self.client.get(url, format='json')
result = response.data
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(result['role'], 'qe_ack')
self.assertEqual(result['contact']['mail_name'], 'maillist2')
self.assertEqual(result['contact']['email'], 'maillist2@test.com')

def test_destroy_release_component_contacts(self):
url = reverse('releasecomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.data.get('count'), 2)
url = reverse('releasecomponentcontacts-detail', kwargs={'pk': 2})
self.client.delete(url, format='json')
url = reverse('releasecomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.data.get('count'), 1)

def test_filter_release_component_contacts(self):
url = reverse('releasecomponentcontacts-list')
data = {'contact_role': 'pm'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['count'], 1)

data = {'contact_role': 'no_such_role'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

data = {'contact_role': 'qe_ack', 'mail_name': 'maillist2'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 1)

# should not get anything
data = {'contact_role': 'qe_ack', 'username': 'person1'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

# should not get anything
data = {'contact_role': 'pm', 'mail_name': 'maillist2'}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

data = {'component_id': 1}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 1)

data = {'component_id': 200}
response = self.client.get(url, data, format='json')
self.assertEqual(response.data['count'], 0)

def test_create_release_component_contacts(self):
url = reverse('releasecomponentcontacts-list')
data = {'component_id': 2, 'role': 'pm', 'contact': {'mail_name': 'maillist2'}}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
url = reverse('releasecomponentcontacts-list')
response = self.client.get(url, format='json')
self.assertEqual(response.data.get('count'), 3)

def test_patch_release_component_contacts(self):
url = reverse('releasecomponentcontacts-detail', kwargs={'pk': 2})
data = {"contact": {"username": "person2", "email": "person2@test.com"}}
response = self.client.patch(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
response.data['contact'].pop('id')
self.assertEqual(response.data['contact'], data['contact'])
self.assertNumChanges([1])
48 changes: 45 additions & 3 deletions pdc/apps/component/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from pdc.apps.common import viewsets
from pdc.apps.common.models import Label
from pdc.apps.contact.models import RoleContact, ContactRole
from pdc.apps.contact.models import RoleContact, ContactRole, GlobalComponentRoleContact, ReleaseComponentRoleContact
from pdc.apps.common.serializers import LabelSerializer, StrictSerializerMixin
from pdc.apps.common.filters import LabelFilter
from .models import (GlobalComponent,
Expand All @@ -38,14 +38,18 @@
GroupTypeSerializer,
ReleaseComponentRelationshipSerializer,
ReleaseComponentTypeSerializer,
RCRelationshipTypeSerializer)
RCRelationshipTypeSerializer,
GlobalComponentRoleContactSerializer,
ReleaseComponentRoleContactSerializer)
from .filters import (ComponentFilter,
ReleaseComponentFilter,
RoleContactFilter,
BugzillaComponentFilter,
GroupFilter,
GroupTypeFilter,
ReleaseComponentRelationshipFilter)
ReleaseComponentRelationshipFilter,
GlobalComponentRoleContactFilter,
ReleaseComponentRoleContactFilter)
from . import signals


Expand Down Expand Up @@ -1851,3 +1855,41 @@ def destroy(self, request, *args, **kwargs):
On success, HTTP status code is 204 and the response has no content.
"""
return super(ReleaseComponentRelationshipViewSet, self).destroy(request, *args, **kwargs)


class GlobalComponentContactInfoViewSet(viewsets.PDCModelViewSet):

queryset = GlobalComponentRoleContact.objects.all()
serializer_class = GlobalComponentRoleContactSerializer
filter_class = GlobalComponentRoleContactFilter

def list(self, request, *args, **kwargs):
return super(GlobalComponentContactInfoViewSet, self).list(request, *args, **kwargs)

def retrieve(self, request, *args, **kwargs):
return super(GlobalComponentContactInfoViewSet, self).retrieve(request, *args, **kwargs)

def destroy(self, request, *args, **kwargs):
return super(GlobalComponentContactInfoViewSet, self).destroy(request, *args, **kwargs)

def update(self, request, *args, **kwargs):
return super(GlobalComponentContactInfoViewSet, self).update(request, *args, **kwargs)


class ReleaseComponentContactInfoViewSet(viewsets.PDCModelViewSet):

queryset = ReleaseComponentRoleContact.objects.all()
serializer_class = ReleaseComponentRoleContactSerializer
filter_class = ReleaseComponentRoleContactFilter

def list(self, request, *args, **kwargs):
return super(ReleaseComponentContactInfoViewSet, self).list(request, *args, **kwargs)

def retrieve(self, request, *args, **kwargs):
return super(ReleaseComponentContactInfoViewSet, self).retrieve(request, *args, **kwargs)

def destroy(self, request, *args, **kwargs):
return super(ReleaseComponentContactInfoViewSet, self).destroy(request, *args, **kwargs)

def update(self, request, *args, **kwargs):
return super(ReleaseComponentContactInfoViewSet, self).update(request, *args, **kwargs)
Loading

0 comments on commit 45220db

Please sign in to comment.