Multiple serializers for Entry based on type (#490)

* entry types with appropriate serializers and URL endpoints
This commit is contained in:
Pomax 2019-05-23 11:15:58 -07:00 коммит произвёл GitHub
Родитель a3fefe8ef8
Коммит f4c237a106
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
13 изменённых файлов: 350 добавлений и 9 удалений

Просмотреть файл

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-05-09 00:29
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('entries', '0024_entry_entry_type'),
]
operations = [
migrations.AlterField(
model_name='entry',
name='content_url',
field=models.URLField(blank=True),
),
]

Просмотреть файл

@ -87,10 +87,11 @@ class Entry(models.Model):
max_length=20,
choices=ENTRY_TYPES,
default=ENTRY_TYPES[0][0],
null=False,
)
title = models.CharField(max_length=140)
content_url = models.URLField()
content_url = models.URLField(
blank=True,
)
# optional fields
description = models.CharField(max_length=600, blank=True)

Просмотреть файл

@ -0,0 +1,34 @@
from .base import (
associate_entry_with_creator_data,
CreatableSlugRelatedField,
ModerationStateSerializer,
EntryBaseSerializer,
EntryWithV1CreatorsBaseSerializer,
EntryWithCreatorsBaseSerializer,
EntrySerializer,
EntrySerializerWithCreators,
EntrySerializerWithV1Creators,
)
from .curriculum import CurriculumEntrySerializer
from .info import InfoEntrySerializer
from .news import NewsEntrySerializer
from .project import ProjectEntrySerializer
from .session import SessionEntrySerializer
__all__ = [
'associate_entry_with_creator_data',
'CreatableSlugRelatedField',
'ModerationStateSerializer',
'EntryBaseSerializer',
'EntryWithV1CreatorsBaseSerializer',
'EntryWithCreatorsBaseSerializer',
'EntrySerializer',
'EntrySerializerWithCreators',
'EntrySerializerWithV1Creators',
'CurriculumEntrySerializer',
'InfoEntrySerializer',
'NewsEntrySerializer',
'ProjectEntrySerializer',
'SessionEntrySerializer',
]

Просмотреть файл

@ -59,6 +59,12 @@ class EntryBaseSerializer(serializers.ModelSerializer):
Serializes an entry with minimal information
"""
# As an optional-for-some-types-of-entries, this
# field is required "by default" in this serializer,
# and marked as "not required" for the various entry
# types that don't actually need it.
content_url = serializers.URLField(required=True)
is_bookmarked = serializers.SerializerMethodField()
def get_is_bookmarked(self, instance):

Просмотреть файл

@ -0,0 +1,5 @@
from .base import EntrySerializerWithCreators
class CurriculumEntrySerializer(EntrySerializerWithCreators):
pass

Просмотреть файл

@ -0,0 +1,5 @@
from .base import EntrySerializerWithCreators
class InfoEntrySerializer(EntrySerializerWithCreators):
pass

Просмотреть файл

@ -0,0 +1,9 @@
from .base import EntrySerializerWithCreators
class NewsEntrySerializer(EntrySerializerWithCreators):
class Meta(EntrySerializerWithCreators.Meta):
exclude = EntrySerializerWithCreators.Meta.exclude + (
'help_types',
)

Просмотреть файл

@ -0,0 +1,7 @@
from rest_framework import serializers
from .base import EntrySerializerWithCreators
class ProjectEntrySerializer(EntrySerializerWithCreators):
content_url = serializers.URLField(required=False)

Просмотреть файл

@ -0,0 +1,14 @@
from rest_framework import serializers
from .base import EntrySerializerWithCreators
class SessionEntrySerializer(EntrySerializerWithCreators):
content_url = serializers.URLField(required=False)
class Meta(EntrySerializerWithCreators.Meta):
exclude = EntrySerializerWithCreators.Meta.exclude + (
'thumbnail',
'get_involved',
'get_involved_url',
)

Просмотреть файл

@ -0,0 +1,173 @@
from pulseapi.entries.models import Entry
from pulseapi.tests import PulseMemberTestCase
def get_full_payload():
return {
'title': 'test test_post_full_entry',
'description': 'description full entry',
'tags': ['tag1', 'tag2'],
'interest': 'interest field',
'get_involved': 'get involved text field',
'get_involved_url': 'http://example.com/getinvolved',
'content_url': 'http://example.com/',
'internal_notes': 'Some internal notes',
'featured': True,
'issues': ['Decentralization'],
'related_creators': [
{'name': 'Pomax'},
{'name': 'Alan'}
]
}
class TestMemberEntryView(PulseMemberTestCase):
def test_base_serializer(self):
postresponse = self.client.post(
'/api/pulse/entries/',
data=self.generatePostPayload(
data=get_full_payload()
)
)
self.assertEqual(postresponse.status_code, 200)
def test_base_serializer_without_content_url(self):
postresponse = self.client.post(
'/api/pulse/entries/',
data=self.generatePostPayload(
data=get_full_payload(),
exclude=['title']
)
)
self.assertEqual(postresponse.status_code, 400)
def test_curriculum_serializer(self):
postresponse = self.client.post(
'/api/pulse/entries/curriculum/',
data=self.generatePostPayload(
data=get_full_payload()
)
)
self.assertEqual(postresponse.status_code, 200)
def test_curriculum_serializer_without_content_url(self):
postresponse = self.client.post(
'/api/pulse/entries/curriculum/',
data=self.generatePostPayload(
data=get_full_payload(),
exclude=['content_url']
)
)
self.assertEqual(postresponse.status_code, 400)
def test_info_serializer(self):
postresponse = self.client.post(
'/api/pulse/entries/info/',
data=self.generatePostPayload(
data=get_full_payload()
)
)
self.assertEqual(postresponse.status_code, 200)
def test_info_serializer_without_content_url(self):
postresponse = self.client.post(
'/api/pulse/entries/info/',
data=self.generatePostPayload(
data=get_full_payload(),
exclude=['content_url']
)
)
self.assertEqual(postresponse.status_code, 400)
def test_news_serializer(self):
postresponse = self.client.post(
'/api/pulse/entries/news/',
data=self.generatePostPayload(
data=get_full_payload()
)
)
self.assertEqual(postresponse.status_code, 200)
def test_news_serializer_without_content_url(self):
postresponse = self.client.post(
'/api/pulse/entries/news/',
data=self.generatePostPayload(
data=get_full_payload(),
exclude=['content_url']
)
)
self.assertEqual(postresponse.status_code, 400)
def test_project_serializer(self):
postresponse = self.client.post(
'/api/pulse/entries/project/',
data=self.generatePostPayload(
data=get_full_payload()
)
)
self.assertEqual(postresponse.status_code, 200)
def test_project_serializer_without_content_url(self):
postresponse = self.client.post(
'/api/pulse/entries/project/',
data=self.generatePostPayload(
data=get_full_payload(),
exclude=['content_url']
)
)
self.assertEqual(postresponse.status_code, 200)
def test_session_serializer(self):
postresponse = self.client.post(
'/api/pulse/entries/session/',
data=self.generatePostPayload(
data=get_full_payload()
)
)
self.assertEqual(postresponse.status_code, 200)
def test_session_serializer_without_content_url(self):
postresponse = self.client.post(
'/api/pulse/entries/session/',
data=self.generatePostPayload(
data=get_full_payload(),
exclude=['content_url']
)
)
self.assertEqual(postresponse.status_code, 200)
def test_session_serializer_without_content_url_with_thumbnail(self):
payload = get_full_payload()
payload['thumbnail'] = {
'name': 'myfile.jpg',
'base64':
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg==',
}
postresponse = self.client.post(
'/api/pulse/entries/session/',
data=self.generatePostPayload(
data=payload
)
)
self.assertEqual(postresponse.status_code, 200)
entry = Entry.objects.last()
self.assertEqual(str(entry.thumbnail), '')
self.assertEqual(entry.get_involved, '')
self.assertEqual(entry.get_involved_url, '')

Просмотреть файл

@ -8,6 +8,11 @@ from pulseapi.entries.views import (
BookmarkedEntries,
ModerationStateView,
EntriesListView,
ProjectEntriesListView,
NewsEntriesListView,
CurriculumEntriesListView,
InfoEntriesListView,
SessionEntriesListView,
)
urlpatterns = [
@ -16,6 +21,31 @@ urlpatterns = [
EntriesListView.as_view(),
name='entries-list'
),
url(
'curriculum/',
CurriculumEntriesListView.as_view(),
name='curriculum-entries'
),
url(
'info/',
InfoEntriesListView.as_view(),
name='info-entries'
),
url(
'news/',
NewsEntriesListView.as_view(),
name='news-entries'
),
url(
'project/',
ProjectEntriesListView.as_view(),
name='project-entries'
),
url(
'session/',
SessionEntriesListView.as_view(),
name='session-entries'
),
url(
'bookmarks/',
BookmarkedEntries.as_view(),

Просмотреть файл

@ -22,6 +22,14 @@ from pulseapi.entries.serializers import (
EntrySerializerWithCreators,
ModerationStateSerializer,
)
from .serializers import (
ProjectEntrySerializer,
NewsEntrySerializer,
CurriculumEntrySerializer,
InfoEntrySerializer,
SessionEntrySerializer
)
from pulseapi.profiles.models import UserBookmarks
from pulseapi.utility.userpermissions import is_staff_address
@ -469,6 +477,7 @@ class EntriesListView(ListCreateAPIView):
data=request_data,
context={'user': user},
)
if serializer.is_valid():
# ensure that the published_by is always the user doing
# the posting, and set 'featured' to false.
@ -502,3 +511,28 @@ class EntriesListView(ListCreateAPIView):
"post validation failed - {}".format(validation_result),
status=status.HTTP_400_BAD_REQUEST
)
class ProjectEntriesListView(EntriesListView):
def get_serializer_class(self):
return ProjectEntrySerializer
class NewsEntriesListView(EntriesListView):
def get_serializer_class(self):
return NewsEntrySerializer
class CurriculumEntriesListView(EntriesListView):
def get_serializer_class(self):
return CurriculumEntrySerializer
class InfoEntriesListView(EntriesListView):
def get_serializer_class(self):
return InfoEntrySerializer
class SessionEntriesListView(EntriesListView):
def get_serializer_class(self):
return SessionEntrySerializer

Просмотреть файл

@ -134,7 +134,7 @@ def generate_default_payload(values):
}
def generate_payload(test, data={}, payload=False):
def generate_payload(test, data={}, exclude={}, payload=False):
values = json.loads(
str(test.client.get('/api/pulse/nonce/').content, 'utf-8')
)
@ -145,6 +145,9 @@ def generate_payload(test, data={}, payload=False):
for key in data:
payload[key] = data[key]
for key in exclude:
del payload[key]
return json.dumps(payload)
@ -173,8 +176,8 @@ class PulseMemberTestCase(TestCase):
email="test@example.org"
)
def generatePostPayload(self, data={}):
return generate_payload(self, data)
def generatePostPayload(self, data={}, exclude=[]):
return generate_payload(self, data, exclude)
class PulseStaffTestCase(TestCase):
@ -190,8 +193,8 @@ class PulseStaffTestCase(TestCase):
email="test@mozillafoundation.org"
)
def generatePostPayload(self, data={}):
return generate_payload(self, data)
def generatePostPayload(self, data={}, exclude=[]):
return generate_payload(self, data, exclude)
class PulseModeratorTestCase(TestCase):
@ -206,8 +209,8 @@ class PulseModeratorTestCase(TestCase):
is_moderator=True
)
def generatePostPayload(self, data={}):
return generate_payload(self, data)
def generatePostPayload(self, data={}, exclude=[]):
return generate_payload(self, data, exclude)
class TestAPIVersioning(TestCase):