From aa0bb9fd0d02e00d504f332f1503b8fc9d1f8a20 Mon Sep 17 00:00:00 2001 From: jedi Date: Mon, 20 Nov 2023 15:56:32 +0100 Subject: [PATCH] remove trailing slash requirement in api v1 --- core/files/api_v1.py | 2 +- core/files/tests.py | 8 ++++---- core/inventory/api_v1.py | 26 ++++++++++++++----------- core/inventory/models.py | 8 +++++--- core/inventory/tests/test_api.py | 8 ++++---- core/inventory/tests/test_containers.py | 12 ++++++------ core/inventory/tests/test_events.py | 12 ++++++------ core/inventory/tests/test_items.py | 22 ++++++++++----------- 8 files changed, 52 insertions(+), 46 deletions(-) diff --git a/core/files/api_v1.py b/core/files/api_v1.py index be6fd6d..b0386da 100644 --- a/core/files/api_v1.py +++ b/core/files/api_v1.py @@ -18,7 +18,7 @@ class FileViewSet(viewsets.ModelViewSet): lookup_field = 'hash' -router = routers.SimpleRouter() +router = routers.SimpleRouter(trailing_slash=False) router.register(r'files', FileViewSet, basename='files') router.register(r'file', FileViewSet, basename='files') diff --git a/core/files/tests.py b/core/files/tests.py index 98c0ea8..ca475fb 100644 --- a/core/files/tests.py +++ b/core/files/tests.py @@ -16,7 +16,7 @@ class FileTestCase(TestCase): def test_list_files(self): import base64 item = File.objects.create(data=base64.b64encode(b"foo").decode('utf-8')) - response = client.get('/api/1/files/') + response = client.get('/api/1/files') self.assertEqual(response.status_code, 200) self.assertEqual(response.json()[0]['hash'], item.hash) self.assertEqual(len(response.json()[0]['hash']), 64) @@ -24,7 +24,7 @@ class FileTestCase(TestCase): def test_one_file(self): import base64 item = File.objects.create(data=base64.b64encode(b"foo").decode('utf-8')) - response = client.get(f'/api/1/file/{item.hash}/') + response = client.get(f'/api/1/file/{item.hash}') self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['hash'], item.hash) self.assertEqual(len(response.json()['hash']), 64) @@ -33,7 +33,7 @@ class FileTestCase(TestCase): import base64 Item.objects.create(container=self.box, event=self.event, description='1') item = Item.objects.create(container=self.box, event=self.event, description='2') - response = client.post('/api/1/file/', {'data': base64.b64encode(b"foo").decode('utf-8')}, content_type='application/json') + response = client.post('/api/1/file', {'data': base64.b64encode(b"foo").decode('utf-8')}, content_type='application/json') self.assertEqual(response.status_code, 201) self.assertEqual(len(response.json()['hash']), 64) @@ -43,5 +43,5 @@ class FileTestCase(TestCase): File.objects.create(item=item, data=base64.b64encode(b"foo").decode('utf-8')) file = File.objects.create(item=item, data=base64.b64encode(b"bar").decode('utf-8')) self.assertEqual(len(File.objects.all()), 2) - response = client.delete(f'/api/1/file/{file.hash}/') + response = client.delete(f'/api/1/file/{file.hash}') self.assertEqual(response.status_code, 204) diff --git a/core/inventory/api_v1.py b/core/inventory/api_v1.py index cc9d291..3f3ece7 100644 --- a/core/inventory/api_v1.py +++ b/core/inventory/api_v1.py @@ -1,6 +1,6 @@ from datetime import datetime -from django.urls import path +from django.urls import re_path from rest_framework import routers, viewsets, serializers from rest_framework.decorators import api_view, permission_classes, authentication_classes from rest_framework.response import Response @@ -148,14 +148,18 @@ def item_by_id(request, event_slug, id): return Response(status=404) -router = routers.SimpleRouter() -router.register(r'events', EventViewSet, basename='events') -router.register(r'boxes', ContainerViewSet, basename='boxes') -router.register(r'box', ContainerViewSet, basename='boxes') - -urlpatterns = router.urls + [ - path('/items/', item), - path('/items//', search_items), - path('/item/', item), - path('/item//', item_by_id), +urlpatterns = [ + re_path('events/?$', EventViewSet.as_view({'get': 'list', 'post': 'create'})), + re_path('events/(?P[0-9]+)/?$', + EventViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), + re_path('boxes/?$', ContainerViewSet.as_view({'get': 'list', 'post': 'create'})), + re_path('boxes/(?P[0-9]+)/?$', + ContainerViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), + re_path('box/?$', ContainerViewSet.as_view({'get': 'list', 'post': 'create'})), + re_path('box/(?P[0-9]+)/?$', + ContainerViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), + re_path('(?P[a-zA-Z0-9]+)/items/?$', item), + re_path('(?P[a-zA-Z0-9]+)/items/(?P[^/]+)/?$', search_items), + re_path('(?P[a-zA-Z0-9]+)/item/?$', item), + re_path('(?P[a-zA-Z0-9]+)/item/(?P[0-9]+)/?$', item_by_id), ] diff --git a/core/inventory/models.py b/core/inventory/models.py index 85eee8a..6f5bb1e 100644 --- a/core/inventory/models.py +++ b/core/inventory/models.py @@ -1,14 +1,15 @@ from django.core.files.base import ContentFile from django.db import models, IntegrityError -from django_softdelete.models import SoftDeleteModel +from django_softdelete.models import SoftDeleteModel, SoftDeleteManager -class ItemManager(models.Manager): +class ItemManager(SoftDeleteManager): def create(self, **kwargs): if 'uid' in kwargs: raise ValueError('uid must not be set manually') - uid = Item.objects.filter(event=kwargs['event']).count() + 1 + #uid = Item.objects.filter(event=kwargs['event']).count() + 1 + uid = Item.all_objects.filter(event=kwargs['event']).count() + 1 kwargs['uid'] = uid return super().create(**kwargs) @@ -24,6 +25,7 @@ class Item(SoftDeleteModel): updated_at = models.DateTimeField(blank=True, null=True) objects = ItemManager() + all_objects = models.Manager() class Meta: unique_together = (('uid', 'event'),) diff --git a/core/inventory/tests/test_api.py b/core/inventory/tests/test_api.py index 2f75224..db1df0a 100644 --- a/core/inventory/tests/test_api.py +++ b/core/inventory/tests/test_api.py @@ -12,23 +12,23 @@ class ApiTest(TestCase): self.assertEqual(response.json()["framework_version"], SYSTEM3_VERSION) def test_events(self): - response = client.get('/api/1/events/') + response = client.get('/api/1/events') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), []) def test_containers(self): - response = client.get('/api/1/boxes/') + response = client.get('/api/1/boxes') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), []) def test_files(self): - response = client.get('/api/1/files/') + response = client.get('/api/1/files') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), []) def test_items(self): from inventory.models import Event Event.objects.create(slug='TEST1', name='Event') - response = client.get('/api/1/TEST1/items/') + response = client.get('/api/1/TEST1/items') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), []) diff --git a/core/inventory/tests/test_containers.py b/core/inventory/tests/test_containers.py index 70268b7..78b82c1 100644 --- a/core/inventory/tests/test_containers.py +++ b/core/inventory/tests/test_containers.py @@ -7,13 +7,13 @@ client = Client() class ContainerTestCase(TestCase): def test_empty(self): - response = client.get('/api/1/boxes/') + response = client.get('/api/1/boxes') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), []) def test_members(self): Container.objects.create(name='BOX') - response = client.get('/api/1/boxes/') + response = client.get('/api/1/boxes') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['cid'], 1) @@ -24,12 +24,12 @@ class ContainerTestCase(TestCase): Container.objects.create(name='BOX 1') Container.objects.create(name='BOX 2') Container.objects.create(name='BOX 3') - response = client.get('/api/1/boxes/') + response = client.get('/api/1/boxes') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 3) def test_create_container(self): - response = client.post('/api/1/box/', {'name': 'BOX'}) + response = client.post('/api/1/box', {'name': 'BOX'}) self.assertEqual(response.status_code, 201) self.assertEqual(response.json()['cid'], 1) self.assertEqual(response.json()['name'], 'BOX') @@ -41,7 +41,7 @@ class ContainerTestCase(TestCase): def test_update_container(self): from rest_framework.test import APIClient box = Container.objects.create(name='BOX 1') - response = APIClient().put(f'/api/1/box/{box.cid}/', {'name': 'BOX 2'}) + response = APIClient().put(f'/api/1/box/{box.cid}', {'name': 'BOX 2'}) self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['cid'], 1) self.assertEqual(response.json()['name'], 'BOX 2') @@ -54,6 +54,6 @@ class ContainerTestCase(TestCase): box = Container.objects.create(name='BOX 1') Container.objects.create(name='BOX 2') self.assertEqual(len(Container.objects.all()), 2) - response = client.delete(f'/api/1/box/{box.cid}/') + response = client.delete(f'/api/1/box/{box.cid}') self.assertEqual(response.status_code, 204) self.assertEqual(len(Container.objects.all()), 1) diff --git a/core/inventory/tests/test_events.py b/core/inventory/tests/test_events.py index f2655ea..a861f12 100644 --- a/core/inventory/tests/test_events.py +++ b/core/inventory/tests/test_events.py @@ -7,13 +7,13 @@ client = Client() class EventTestCase(TestCase): def test_empty(self): - response = client.get('/api/1/events/') + response = client.get('/api/1/events') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), []) def test_members(self): Event.objects.create(slug='EVENT', name='Event') - response = client.get('/api/1/events/') + response = client.get('/api/1/events') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['slug'], 'EVENT') @@ -23,12 +23,12 @@ class EventTestCase(TestCase): Event.objects.create(slug='EVENT1', name='Event 1') Event.objects.create(slug='EVENT2', name='Event 2') Event.objects.create(slug='EVENT3', name='Event 3') - response = client.get('/api/1/events/') + response = client.get('/api/1/events') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 3) def test_create_event(self): - response = client.post('/api/1/events/', {'slug': 'EVENT', 'name': 'Event'}) + response = client.post('/api/1/events', {'slug': 'EVENT', 'name': 'Event'}) self.assertEqual(response.status_code, 201) self.assertEqual(response.json()['slug'], 'EVENT') self.assertEqual(response.json()['name'], 'Event') @@ -39,7 +39,7 @@ class EventTestCase(TestCase): def test_update_event(self): from rest_framework.test import APIClient event = Event.objects.create(slug='EVENT1', name='Event 1') - response = APIClient().put(f'/api/1/events/{event.eid}/', {'slug': 'EVENT2', 'name': 'Event 2 new'}) + response = APIClient().put(f'/api/1/events/{event.eid}', {'slug': 'EVENT2', 'name': 'Event 2 new'}) self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['slug'], 'EVENT2') self.assertEqual(response.json()['name'], 'Event 2 new') @@ -51,6 +51,6 @@ class EventTestCase(TestCase): event = Event.objects.create(slug='EVENT1', name='Event 1') Event.objects.create(slug='EVENT2', name='Event 2') self.assertEqual(len(Event.objects.all()), 2) - response = client.delete(f'/api/1/events/{event.eid}/') + response = client.delete(f'/api/1/events/{event.eid}') self.assertEqual(response.status_code, 204) self.assertEqual(len(Event.objects.all()), 1) diff --git a/core/inventory/tests/test_items.py b/core/inventory/tests/test_items.py index 80d9828..942b9ae 100644 --- a/core/inventory/tests/test_items.py +++ b/core/inventory/tests/test_items.py @@ -14,13 +14,13 @@ class ItemTestCase(TestCase): self.box = Container.objects.create(name='BOX') def test_empty(self): - response = client.get(f'/api/1/{self.event.slug}/item/') + response = client.get(f'/api/1/{self.event.slug}/item') self.assertEqual(response.status_code, 200) self.assertEqual(response.content, b'[]') def test_members(self): item = Item.objects.create(container=self.box, event=self.event, description='1') - response = client.get(f'/api/1/{self.event.slug}/item/') + response = client.get(f'/api/1/{self.event.slug}/item') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), [{'uid': 1, 'description': '1', 'box': 'BOX', 'cid': self.box.cid, 'file': None}]) @@ -28,7 +28,7 @@ class ItemTestCase(TestCase): import base64 item = Item.objects.create(container=self.box, event=self.event, description='1') file = File.objects.create(item=item, data=base64.b64encode(b"foo").decode('utf-8')) - response = client.get(f'/api/1/{self.event.slug}/item/') + response = client.get(f'/api/1/{self.event.slug}/item') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), [{'uid': 1, 'description': '1', 'box': 'BOX', 'cid': self.box.cid, 'file': file.hash}]) @@ -37,12 +37,12 @@ class ItemTestCase(TestCase): Item.objects.create(container=self.box, event=self.event, description='1') Item.objects.create(container=self.box, event=self.event, description='2') Item.objects.create(container=self.box, event=self.event, description='3') - response = client.get(f'/api/1/{self.event.slug}/item/') + response = client.get(f'/api/1/{self.event.slug}/item') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 3) def test_create_item(self): - response = client.post(f'/api/1/{self.event.slug}/item/', {'cid': self.box.cid, 'description': '1'}) + response = client.post(f'/api/1/{self.event.slug}/item', {'cid': self.box.cid, 'description': '1'}) self.assertEqual(response.status_code, 201) self.assertEqual(response.json(), {'uid': 1, 'description': '1', 'box': 'BOX', 'cid': self.box.cid, 'file': None}) self.assertEqual(len(Item.objects.all()), 1) @@ -56,7 +56,7 @@ class ItemTestCase(TestCase): def test_update_item(self): item = Item.objects.create(container=self.box, event=self.event, description='1') - response = client.put(f'/api/1/{self.event.slug}/item/{item.uid}/', {'description': '2'}, content_type='application/json') + response = client.put(f'/api/1/{self.event.slug}/item/{item.uid}', {'description': '2'}, content_type='application/json') self.assertEqual(response.status_code, 200) self.assertEqual(response.json(), {'uid': 1, 'description': '2', 'box': 'BOX', 'cid': self.box.cid, 'file': None}) @@ -69,7 +69,7 @@ class ItemTestCase(TestCase): item = Item.objects.create(container=self.box, event=self.event, description='1') Item.objects.create(container=self.box, event=self.event, description='2') self.assertEqual(len(Item.objects.all()), 2) - response = client.delete(f'/api/1/{self.event.slug}/item/{item.uid}/') + response = client.delete(f'/api/1/{self.event.slug}/item/{item.uid}') self.assertEqual(response.status_code, 204) self.assertEqual(len(Item.objects.all()), 1) @@ -77,22 +77,22 @@ class ItemTestCase(TestCase): Item.objects.create(container=self.box, event=self.event, description='1') item2 = Item.objects.create(container=self.box, event=self.event, description='2') self.assertEqual(len(Item.objects.all()), 2) - response = client.delete(f'/api/1/{self.event.slug}/item/{item2.uid}/') + response = client.delete(f'/api/1/{self.event.slug}/item/{item2.uid}') self.assertEqual(response.status_code, 204) self.assertEqual(len(Item.objects.all()), 1) item3 = Item.objects.create(container=self.box, event=self.event, description='3') - self.assertEqual(item3.uid, 2) + self.assertEqual(item3.uid, 3) self.assertEqual(len(Item.objects.all()), 2) def test_item_count(self): Item.objects.create(container=self.box, event=self.event, description='1') Item.objects.create(container=self.box, event=self.event, description='2') - response = client.get('/api/1/boxes/') + response = client.get('/api/1/boxes') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['itemCount'], 2) def test_item_nonexistent(self): - response = client.get(f'/api/1/NOEVENT/item/') + response = client.get(f'/api/1/NOEVENT/item') self.assertEqual(response.status_code, 404)