Bug#824912: tracker.d.o: add an API for action items
Hi,
Raphael Hertzog <hertzog@debian.org> writes:
> Can you say what minimal version? We have 3.4 in testing/unstable but
> 2.4.3 in jessie.
> I'm fine with requiring 3.4 although it has not yet been backported
> for jessie. That will have to happen if we want to push this new module into
> production.
I encountered this issue when implementing pagination for json.
Basically it works differently between 2.4.3 and 3.4.
I decided to keep DRF 2.4.3. But i'm happy to change it if you prefer.
I have no big reasons to prefer one or the other one, so i fallback on
the fact that if it's on stable i go for it.
> Reported-by: Paul Wise <pabs@debian.org>
Done.
>> ---
>> distro_tracker/api/tests.py | 95 +++++++++++++++++++++++++++++++++++++++++-
>> distro_tracker/api/views.py | 42 ++++++++++++++++++-
>> distro_tracker/project/urls.py | 8 ++++
>
> Please don't modify project/urls.py directly. Use api/tracker_urls.py
> instead (see derivative/tracker_urls.py as an example).
>
Done. Also realized that i forgot to include a file -_- .
> I have not reviewed the rest yet.
Btw sorry for the short description of my last email, i try to
compensate it now:
```
$ curl -H 'Accept: application/json; indent=4' "http://tracker.dev:8000/api/v1/action-items"
{
"count": 21324,
"next": "http://tracker.dev:8000/api/v1/action-items?page=2",
"previous": null,
"results": [
{
"id": 1,
"package_name": "consolation",
"item_type_name": "debian-std-ver-outdated",
"short_description": "Standards version of the package is outdated.",
"severity": 0,
"created_timestamp": "2016-12-12T11:20:47.064Z",
"last_updated_timestamp": "2016-12-12T11:20:47.064Z",
"extra_data": {
"lastsv": "3.9.8",
"standards_version": "3.9.7",
"severely_outdated": false
}
},
...
],
}
```
```
$ curl -H 'Accept: application/json; indent=4' "http://tracker.dev:8000/api/v1/action-items/2/"
{
"id": 2,
"package_name": "gnokii",
"item_type_name": "debian-std-ver-outdated",
"short_description": "Standards version of the package is outdated.",
"severity": 0,
"created_timestamp": "2016-12-12T11:20:47.247Z",
"last_updated_timestamp": "2016-12-12T11:20:47.247Z",
"extra_data": {
"lastsv": "3.9.8",
"standards_version": "3.9.2",
"severely_outdated": false
}
}
```
> Cheers,
> --
> Raphaël Hertzog ◈ Debian Developer
>
> Support Debian LTS: http://www.freexian.com/services/debian-lts.html
> Learn to master Debian: http://debian-handbook.info/get/
cheers,
--
efkin.
>From 0790248b1c2bca5e6817476d1a6bfb35345b553d Mon Sep 17 00:00:00 2001
From: efkin <efkin@riseup.net>
Date: Wed, 14 Dec 2016 13:04:52 +0100
Subject: [PATCH 1/3] Include rest_framework dependency
---
distro_tracker/project/settings/defaults.py | 1 +
docs/setup/setup.rst | 3 ++-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/distro_tracker/project/settings/defaults.py b/distro_tracker/project/settings/defaults.py
index ad7defd..0f27309 100644
--- a/distro_tracker/project/settings/defaults.py
+++ b/distro_tracker/project/settings/defaults.py
@@ -249,6 +249,7 @@ INSTALLED_APPS = (
'django.contrib.staticfiles',
'django.contrib.admin',
'django_email_accounts',
+ 'rest_framework',
'distro_tracker.html',
'distro_tracker.core',
'distro_tracker.accounts',
diff --git a/docs/setup/setup.rst b/docs/setup/setup.rst
index dad9ac0..0cd5508 100644
--- a/docs/setup/setup.rst
+++ b/docs/setup/setup.rst
@@ -15,6 +15,7 @@ Distro Tracker currently depends on the following Debian packages:
- python-django-jsonfield (>= 1.0.0)
- python-django-debug-toolbar (in development mode only)
- python-django-captcha (optional)
+- python-djangorestframework (= 2.4.3)
- python-debian
- python-apt
- python-gpgme
@@ -35,7 +36,7 @@ For Python2.7, the following additional packages are required:
Here is the list of required packages for development on Debian Jessie::
- $ sudo apt install python-django python-requests python-django-jsonfield python-django-debug-toolbar python-debian python-apt python-gpgme python-yaml python-bs4 python-soappy python-ldap python-pyinotify python-tox python-mock python-lzma python-selenium python3-django python3-requests python3-django-jsonfield python3-django-debug-toolbar python3-debian python3-apt python3-gpgme python3-yaml python3-bs4 python3-pyinotify python3-selenium chromium chromedriver
+ $ sudo apt install python-django python-requests python-django-jsonfield python-django-debug-toolbar python-debian python-apt python-gpgme python-yaml python-bs4 python-soappy python-ldap python-pyinotify python-tox python-mock python-lzma python-selenium python-djangorestframework python3-django python3-requests python3-django-jsonfield python3-djangorestframework python3-django-debug-toolbar python3-debian python3-apt python3-gpgme python3-yaml python3-bs4 python3-pyinotify python3-selenium chromium chromedriver
.. _database_setup:
--
2.1.4
>From e6428acf8d29b7f1ab6af6e199d64db186f2815c Mon Sep 17 00:00:00 2001
From: efkin <efkin@riseup.net>
Date: Wed, 14 Dec 2016 13:14:35 +0100
Subject: [PATCH 2/3] Create distro_tracker submodule for API development
---
distro_tracker/api/__init__.py | 0
distro_tracker/api/tests.py | 3 +++
distro_tracker/api/views.py | 3 +++
distro_tracker/project/settings/defaults.py | 1 +
4 files changed, 7 insertions(+)
create mode 100644 distro_tracker/api/__init__.py
create mode 100644 distro_tracker/api/tests.py
create mode 100644 distro_tracker/api/views.py
diff --git a/distro_tracker/api/__init__.py b/distro_tracker/api/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/distro_tracker/api/tests.py b/distro_tracker/api/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/distro_tracker/api/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/distro_tracker/api/views.py b/distro_tracker/api/views.py
new file mode 100644
index 0000000..91ea44a
--- /dev/null
+++ b/distro_tracker/api/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/distro_tracker/project/settings/defaults.py b/distro_tracker/project/settings/defaults.py
index 0f27309..0d42a37 100644
--- a/distro_tracker/project/settings/defaults.py
+++ b/distro_tracker/project/settings/defaults.py
@@ -250,6 +250,7 @@ INSTALLED_APPS = (
'django.contrib.admin',
'django_email_accounts',
'rest_framework',
+ 'distro_tracker.api',
'distro_tracker.html',
'distro_tracker.core',
'distro_tracker.accounts',
--
2.1.4
>From 1131ed132b4b22a3e054a23439644512ff2e452e Mon Sep 17 00:00:00 2001
From: efkin <efkin@riseup.net>
Date: Wed, 14 Dec 2016 18:45:09 +0100
Subject: [PATCH 3/3] Create basic API list/detail endpoint for ActionItem
model instances
Reported_by: Paul Wise <pabs@debian.org>
---
distro_tracker/api/serializers.py | 37 +++++++++++++
distro_tracker/api/tests.py | 105 ++++++++++++++++++++++++++++++++++++-
distro_tracker/api/tracker_urls.py | 29 ++++++++++
distro_tracker/api/views.py | 52 +++++++++++++++++-
4 files changed, 219 insertions(+), 4 deletions(-)
create mode 100644 distro_tracker/api/serializers.py
create mode 100644 distro_tracker/api/tracker_urls.py
diff --git a/distro_tracker/api/serializers.py b/distro_tracker/api/serializers.py
new file mode 100644
index 0000000..fab1c42
--- /dev/null
+++ b/distro_tracker/api/serializers.py
@@ -0,0 +1,37 @@
+# Copyright 2014-2016 The Distro Tracker Developers
+# See the COPYRIGHT file at the top-level directory of this distribution and
+# at https://deb.li/DTAuthors
+#
+# This file is part of Distro Tracker. It is subject to the license terms
+# in the LICENSE file found in the top-level directory of this
+# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
+# including this file, may be copied, modified, propagated, or distributed
+# except according to the terms contained in the LICENSE file.
+
+from rest_framework import serializers
+
+from distro_tracker.core.models import ActionItem
+from distro_tracker.core.models import PackageName
+
+
+class ActionItemSerializer(serializers.ModelSerializer):
+
+ package_name = serializers.RelatedField(source='package', read_only=True)
+ item_type_name = serializers.RelatedField(source='item_type', read_only=True)
+
+ class Meta:
+ model = ActionItem
+ fields = (
+ 'id',
+ 'package_name',
+ 'item_type_name',
+ 'short_description',
+ 'severity',
+ 'created_timestamp',
+ 'last_updated_timestamp',
+ 'extra_data',
+ )
+
+
+
+
diff --git a/distro_tracker/api/tests.py b/distro_tracker/api/tests.py
index 7ce503c..255bbb8 100644
--- a/distro_tracker/api/tests.py
+++ b/distro_tracker/api/tests.py
@@ -1,3 +1,104 @@
-from django.test import TestCase
+# Copyright 2014-2016 The Distro Tracker Developers
+# See the COPYRIGHT file at the top-level directory of this distribution and
+# at https://deb.li/DTAuthors
+#
+# This file is part of Distro Tracker. It is subject to the license terms
+# in the LICENSE file found in the top-level directory of this
+# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
+# including this file, may be copied, modified, propagated, or distributed
+# except according to the terms contained in the LICENSE file.
-# Create your tests here.
+from django.core.urlresolvers import reverse
+
+from rest_framework import status
+from rest_framework.test import APITestCase
+
+from distro_tracker.core.models import ActionItem
+from distro_tracker.core.models import ActionItemType
+from distro_tracker.core.models import SourcePackageName
+
+
+class ActionItemListAPIViewTest(APITestCase):
+ """
+ Test for the :class:`distro_tracker.api.views.ActionItemListAPIView`.
+ """
+
+ def setUp(self):
+ self.url = reverse('dtracker-api-v1-action-items')
+
+ def test_empty_list(self):
+ """
+ Test when the queryset is empty.
+ """
+ response = self.client.get(self.url)
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(
+ 0,
+ response.data['count'],
+ )
+
+ def test_account_item(self):
+ """
+ Test with actual content.
+ """
+ package = SourcePackageName.objects.create(name='dummy-package')
+ action_type = ActionItemType.objects.create(
+ type_name='test',
+ full_description_template='action-item-test.html',
+ )
+ action_item = ActionItem.objects.create(
+ package=package,
+ item_type=action_type,
+ short_description="Short description of item",
+ )
+ response = self.client.get(self.url)
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(
+ 1,
+ response.data['count'],
+ )
+ result = response.data['results'][0]
+ self.assertEqual(
+ 'dummy-package',
+ result['package_name'],
+ )
+
+
+class ActionItemDetailAPIViewTest(APITestCase):
+ """
+ Test for the :class:`distro_tracker.api.views.ActionItemDetailAPIView`.
+ """
+
+ def setUp(self):
+ self.url = reverse('dtracker-api-v1-action-items', kwargs={'pk':1})
+
+ def test_404_on_non_existing_pk(self):
+ """
+ Test when the pk does not return any instance.
+ """
+ response = self.client.get(self.url)
+
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
+ def test_existing_instance(self):
+ """
+ Test when the pk does return an actual instance.
+ """
+ package = SourcePackageName.objects.create(name='dummy-package')
+ action_type = ActionItemType.objects.create(
+ type_name='test',
+ full_description_template='action-item-test.html',
+ )
+ action_item = ActionItem.objects.create(
+ package=package,
+ item_type=action_type,
+ short_description="Short description of item",
+ )
+ response = self.client.get(self.url)
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertEqual(
+ 'dummy-package',
+ response.data['package_name'],
+ )
+
+
diff --git a/distro_tracker/api/tracker_urls.py b/distro_tracker/api/tracker_urls.py
new file mode 100644
index 0000000..f7a15ab
--- /dev/null
+++ b/distro_tracker/api/tracker_urls.py
@@ -0,0 +1,29 @@
+# Copyright 2014-2016 The Distro Tracker Developers
+# See the COPYRIGHT file at the top-level directory of this distribution and
+# at https://deb.li/DTAuthors
+#
+# This file is part of Distro Tracker. It is subject to the license terms
+# in the LICENSE file found in the top-level directory of this
+# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
+# including this file, may be copied, modified, propagated, or distributed
+# except according to the terms contained in the LICENSE file.
+
+from django.conf.urls import url
+
+from .views import ActionItemListAPIView
+from .views import ActionItemDetailAPIView
+
+
+urlpatterns = [
+ url(r'^api/v1/action-items/?$',
+ ActionItemListAPIView.as_view(),
+ name='dtracker-api-v1-action-items'),
+ url(r'^api/v1/action-items/(?P<pk>[0-9]+)/?$',
+ ActionItemDetailAPIView.as_view(),
+ name='dtracker-api-v1-action-items'),
+]
+
+
+frontpagelinks = [
+ ('dtracker-api-v1-action-items', 'GET API endpoint for ActionItem model instances'),
+]
diff --git a/distro_tracker/api/views.py b/distro_tracker/api/views.py
index 91ea44a..c362258 100644
--- a/distro_tracker/api/views.py
+++ b/distro_tracker/api/views.py
@@ -1,3 +1,51 @@
-from django.shortcuts import render
+# Copyright 2014-2016 The Distro Tracker Developers
+# See the COPYRIGHT file at the top-level directory of this distribution and
+# at https://deb.li/DTAuthors
+#
+# This file is part of Distro Tracker. It is subject to the license terms
+# in the LICENSE file found in the top-level directory of this
+# distribution and at https://deb.li/DTLicense. No part of Distro Tracker,
+# including this file, may be copied, modified, propagated, or distributed
+# except according to the terms contained in the LICENSE file.
-# Create your views here.
+from django.http import Http404
+
+from rest_framework import status
+from rest_framework import generics
+from rest_framework.response import Response
+
+from distro_tracker.api.serializers import ActionItemSerializer
+from distro_tracker.core.models import ActionItem
+
+
+class ActionItemListAPIView(generics.ListAPIView):
+ """
+ List all ActionItem instances.
+ """
+
+ serializer_class = ActionItemSerializer
+
+ # this next block assume DRF 2.X (as in debian stable)
+ # and assume pagination will break with DRF 3.X
+ paginate_by = 100
+ paginate_by_param = 'page_size'
+ max_paginate_by = 500
+
+ def get_queryset(self):
+ queryset = ActionItem.objects.all()
+ package_name = self.request.GET.get('package_name', None)
+ if package_name is not None:
+ queryset = queryset.filter(package__name=package_name)
+ return queryset
+
+
+class ActionItemDetailAPIView(generics.RetrieveAPIView):
+ """
+ Retrieve an ActionItem instance.
+ """
+
+ queryset = ActionItem.objects.all()
+ serializer_class = ActionItemSerializer
+
+
+
--
2.1.4
Reply to: