From dcfa05ab474d8a1527f3902b535a2d6bd1dfc419 Mon Sep 17 00:00:00 2001 From: Serghei Mihai Date: Mon, 2 May 2016 15:24:29 +0200 Subject: [PATCH 1/3] api: newsletters retrieval endpoint (#10794) --- corbo/api_urls.py | 23 +++++++++++++++++++++++ corbo/api_views.py | 32 ++++++++++++++++++++++++++++++++ corbo/channels.py | 13 +++++++++---- corbo/settings.py | 1 + corbo/urls.py | 4 +++- jenkins.sh | 13 +++++++++++++ requirements.txt | 1 + setup.py | 3 ++- tests/conftest.py | 9 +++++++++ tests/test_api.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ tox.ini | 23 +++++++++++++++++++++++ 11 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 corbo/api_urls.py create mode 100644 corbo/api_views.py create mode 100755 jenkins.sh create mode 100644 tests/conftest.py create mode 100644 tests/test_api.py create mode 100644 tox.ini diff --git a/corbo/api_urls.py b/corbo/api_urls.py new file mode 100644 index 0000000..cb275e5 --- /dev/null +++ b/corbo/api_urls.py @@ -0,0 +1,23 @@ +# corbo - Announces Manager +# Copyright (C) 2016 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from django.conf.urls import patterns, include, url + +from .api_views import NewslettersView + +urlpatterns = patterns('', + url(r'^newsletters/', NewslettersView.as_view(), name='newsletters'), +) diff --git a/corbo/api_views.py b/corbo/api_views.py new file mode 100644 index 0000000..e9db43f --- /dev/null +++ b/corbo/api_views.py @@ -0,0 +1,32 @@ +# corbo - Announces Manager +# Copyright (C) 2016 Entr'ouvert +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Affero General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from rest_framework.views import APIView +from rest_framework.response import Response + +from .models import Category, Subscription +from .channels import get_channels + + +class NewslettersView(APIView): + + def get(self, request): + newsletters = [] + for c in Category.objects.all(): + newsletter = {'id': str(c.pk), 'text': c.name, + 'transports': get_channels()} + newsletters.append(newsletter) + return Response({'data': newsletters}) diff --git a/corbo/channels.py b/corbo/channels.py index a8ab660..f63eeb7 100644 --- a/corbo/channels.py +++ b/corbo/channels.py @@ -9,28 +9,33 @@ def get_channel_choices(include=[], exclude=[]): for identifier, display_name in channel.get_choices(): yield (identifier, display_name) +def get_channels(): + return [{'id': c_id, 'text': unicode(c_name)} for c_id, c_name in get_channel_choices()] + + class HomepageChannel(object): identifier = 'homepage' @classmethod def get_choices(self): - return (('homepage', _('Homepage')),) + return ((self.identifier, _('Homepage')),) class SMSChannel(object): + identifier = 'mobile' @classmethod def get_choices(self): - return (('sms', _('SMS')),) + return ((self.identifier, _('SMS')),) def send(self, announce): pass class EmailChannel(object): - identifier = 'email' + identifier = 'mail' @classmethod def get_choices(self): - return (('email', _('Email')),) + return ((self.identifier, _('Email')),) def send(self, announce): pass diff --git a/corbo/settings.py b/corbo/settings.py index f90e4e6..654c98c 100644 --- a/corbo/settings.py +++ b/corbo/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = ( 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'rest_framework', ) MIDDLEWARE_CLASSES = ( diff --git a/corbo/urls.py b/corbo/urls.py index f592202..f8b074d 100644 --- a/corbo/urls.py +++ b/corbo/urls.py @@ -8,6 +8,7 @@ from .urls_utils import decorated_includes, manager_required from .views import homepage, atom from manage_urls import urlpatterns as manage_urls +from api_urls import urlpatterns as api_urls urlpatterns = patterns('', url(r'^$', homepage, name='home'), @@ -15,7 +16,8 @@ urlpatterns = patterns('', url(r'^manage/', decorated_includes(manager_required, include(manage_urls))), url(r'^ckeditor/', include('ckeditor.urls')), - url(r'^admin/', include(admin.site.urls)) + url(r'^admin/', include(admin.site.urls)), + url(r'^api/', include(api_urls)) ) if 'mellon' in settings.INSTALLED_APPS: diff --git a/jenkins.sh b/jenkins.sh new file mode 100755 index 0000000..cbde55c --- /dev/null +++ b/jenkins.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -e + +rm -f coverage.xml +rm -f test_results.xml + +pip install --upgrade tox +pip install --upgrade pylint pylint-django +tox -r +test -f pylint.out && cp pylint.out pylint.out.prev +(pylint -f parseable --rcfile /var/lib/jenkins/pylint.django.rc corbo/ | tee pylint.out) || /bin/true +test -f pylint.out.prev && (diff pylint.out.prev pylint.out | grep '^[><]' | grep .py) || /bin/true diff --git a/requirements.txt b/requirements.txt index b2383ad..2f6bdfc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ Django>=1.7, <1.8 django-ckeditor<4.5.3 +djangorestframework -e git+http://repos.entrouvert.org/gadjo.git/#egg=gadjo diff --git a/setup.py b/setup.py index 4209333..e59a798 100644 --- a/setup.py +++ b/setup.py @@ -94,7 +94,8 @@ setup( 'Programming Language :: Python :: 2', ], install_requires=['django>=1.7, <1.8', - 'django-ckeditor<4.5.3' + 'django-ckeditor<4.5.3', + 'djangorestframework', 'gadjo' ], zip_safe=False, diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..674a805 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,9 @@ +import pytest +import django_webtest + +@pytest.fixture +def app(request): + wtm = django_webtest.WebTestMixin() + wtm._patch_settings() + request.addfinalizer(wtm._unpatch_settings) + return django_webtest.DjangoTestApp() diff --git a/tests/test_api.py b/tests/test_api.py new file mode 100644 index 0000000..56f728d --- /dev/null +++ b/tests/test_api.py @@ -0,0 +1,45 @@ +import pytest +import json + + +from django.core.urlresolvers import reverse + +from corbo.models import Category, Announce, Broadcast +from corbo.channels import get_channels + +pytestmark = pytest.mark.django_db + +CATEGORIES = ('Alerts', 'News') + + +@pytest.fixture +def categories(): + categories = [] + for category in CATEGORIES: + c, created = Category.objects.get_or_create(name=category) + categories.append(c) + return categories + +@pytest.fixture +def announces(): + announces = [] + for category in Category.objects.all(): + a = Announce.objects.create(category=category, title='By email') + Broadcast.objects.create(announce=a, channel='mail') + announces.append(a) + a = Announce.objects.create(category=category, title='On homepage') + Broadcast.objects.create(announce=a, channel='homepage') + announces.append(a) + return announces + + +def test_get_newsletters(app, categories, announces): + resp = app.get(reverse('newsletters'), status=200) + data = resp.json + assert data['data'] + for category in data['data']: + assert 'id' in category + assert 'text' in category + assert category['text'] in CATEGORIES + assert 'transports' in category + assert category['transports'] == get_channels() diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..54658f5 --- /dev/null +++ b/tox.ini @@ -0,0 +1,23 @@ +[tox] +envlist = coverage-{django17,django18} + +[testenv] +usedevelop = + coverage: True +setenv = + DJANGO_SETTINGS_MODULE=corbo.settings + coverage: COVERAGE=--junitxml=test_results.xml --cov-report xml --cov=corbo/ --cov-config .coveragerc +deps = + django17: django>1.7,<1.8 + django18: django>=1.8,<1.9 + pytest-cov + pytest-django + pytest + pytest-capturelog + django-webtest + django-ckeditor<4.5.3 + djangorestframework + pylint==1.4.0 + astroid==1.3.2 +commands = + py.test {env:COVERAGE:} {posargs:tests/} -- 2.8.1