diff --git a/greg/api/urls.py b/greg/api/urls.py index cf3e904813d8cbe80aec9558118fe63989297cc1..77b91ebc608851cdab1c1479e5bf8a37670a844d 100644 --- a/greg/api/urls.py +++ b/greg/api/urls.py @@ -1,12 +1,7 @@ from django.urls import ( - path, re_path, ) from rest_framework.routers import DefaultRouter -from drf_spectacular.views import ( - SpectacularAPIView, - SpectacularSwaggerView, -) from greg.api.views.consent import ConsentViewSet from greg.api.views.organizational_unit import OrganizationalUnitViewSet @@ -16,7 +11,6 @@ from greg.api.views.person import ( PersonIdentityViewSet, ) from greg.api.views.role import RoleViewSet -from greg.api.views.health import Health from greg.api.views.sponsor import SponsorViewSet, SponsorGuestsViewSet router = DefaultRouter() @@ -30,13 +24,6 @@ router.register(r"orgunit", OrganizationalUnitViewSet, basename="orgunit") urlpatterns = router.urls urlpatterns += [ - path("schema/", SpectacularAPIView.as_view(), name="schema"), - path( - "schema/swagger-ui/", - SpectacularSwaggerView.as_view(url_name="schema"), - name="swagger-ui", - ), - path("health/", Health.as_view()), re_path( r"^persons/(?P<person_id>[0-9]+)/roles/$", PersonRoleViewSet.as_view({"get": "list", "post": "create"}), diff --git a/greg/tests/api/test_consent.py b/greg/tests/api/test_consent.py index 24ae8c837c73054d8edcad98abcefa1f39624e59..dd59ad52e5a87aa7eb7b16d13aeae765eb72e532 100644 --- a/greg/tests/api/test_consent.py +++ b/greg/tests/api/test_consent.py @@ -22,7 +22,7 @@ def consent_foo() -> Consent: @pytest.mark.django_db def test_get_consent(client, consent_foo): - resp = client.get(reverse("consent-detail", kwargs={"id": consent_foo.id})) + resp = client.get(reverse("v1:consent-detail", kwargs={"id": consent_foo.id})) assert resp.status_code == status.HTTP_200_OK data = resp.json() assert data.get("id") == consent_foo.id diff --git a/greg/tests/api/test_person.py b/greg/tests/api/test_person.py index 211f141720cf461a9b43071dcce9ca32b4ee96f8..772c6ee546a8823dc339d19b12495ffe1008a0c6 100644 --- a/greg/tests/api/test_person.py +++ b/greg/tests/api/test_person.py @@ -72,7 +72,7 @@ def consent_foo() -> Consent: @pytest.mark.django_db def test_get_person(client, person_foo): - resp = client.get(reverse("person-detail", kwargs={"id": person_foo.id})) + resp = client.get(reverse("v1:person-detail", kwargs={"id": person_foo.id})) assert resp.status_code == HTTP_200_OK data = resp.json() assert data.get("id") == person_foo.id @@ -82,7 +82,7 @@ def test_get_person(client, person_foo): @pytest.mark.django_db def test_persons(client, person_foo, person_bar): - resp = client.get(reverse("person-list")) + resp = client.get(reverse("v1:person-list")) assert resp.status_code == HTTP_200_OK data = resp.json() assert len(data["results"]) == 2 @@ -92,7 +92,7 @@ def test_persons(client, person_foo, person_bar): def test_persons_verified_filter_include( client, person_bar, person_foo, person_foo_verified ): - url = reverse("person-list") + url = reverse("v1:person-list") response = client.get(url, {"verified": "true"}) results = response.json()["results"] assert len(results) == 1 @@ -104,7 +104,7 @@ def test_persons_verified_filter_include( def test_persons_verified_filter_exclude( client, person_bar, person_foo, person_foo_verified ): - url = reverse("person-list") + url = reverse("v1:person-list") response = client.get(url, {"verified": "false"}) results = response.json()["results"] assert len(results) == 1 @@ -116,7 +116,7 @@ def test_persons_verified_filter_exclude( def test_add_role( client, person_foo, role_visiting_professor, sponsor_guy, unit_human_resources ): - url = reverse("person_role-list", kwargs={"person_id": person_foo.id}) + url = reverse("v1:person_role-list", kwargs={"person_id": person_foo.id}) roles_for_person = client.get(url).json()["results"] # Check that there are no roles for the person, and then add one @@ -143,7 +143,7 @@ def test_add_role( @pytest.mark.django_db def test_update_role(client, person_foo, role_data_guest): - url = reverse("person_role-list", kwargs={"person_id": person_foo.id}) + url = reverse("v1:person_role-list", kwargs={"person_id": person_foo.id}) response = client.post(url, role_data_guest) response_data = response.json() @@ -155,7 +155,7 @@ def test_update_role(client, person_foo, role_data_guest): updated_role["start_date"] = "2021-06-15" url_detail = reverse( - "person_role-detail", kwargs={"person_id": person_foo.id, "id": role_id} + "v1:person_role-detail", kwargs={"person_id": person_foo.id, "id": role_id} ) client.patch(url_detail, updated_role) @@ -168,14 +168,14 @@ def test_update_role(client, person_foo, role_data_guest): @pytest.mark.django_db def test_delete_role(client, person_foo, role_data_guest): - url = reverse("person_role-list", kwargs={"person_id": person_foo.id}) + url = reverse("v1:person_role-list", kwargs={"person_id": person_foo.id}) role_id = client.post(url, role_data_guest).json()["id"] roles_for_person = client.get(url).json()["results"] assert len(roles_for_person) == 1 url_detail = reverse( - "person_role-detail", kwargs={"person_id": person_foo.id, "id": role_id} + "v1:person_role-detail", kwargs={"person_id": person_foo.id, "id": role_id} ) client.delete(url_detail) @@ -187,12 +187,12 @@ def test_identity_list( client, person_foo, person_foo_verified, person_foo_not_verified ): response = client.get( - reverse("person-list"), + reverse("v1:person-list"), data={"first_name": person_foo.first_name, "last_name": person_foo.last_name}, ) person_id = response.json()["results"][0]["id"] response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_id}) ) data = response.json()["results"] assert len(data) == 2 @@ -201,7 +201,7 @@ def test_identity_list( @pytest.mark.django_db def test_identity_add(client, person_foo): response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 0 @@ -212,11 +212,12 @@ def test_identity_add(client, person_foo): "value": "12345", } client.post( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}), + data=data, ) response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 1 @@ -230,12 +231,13 @@ def test_identity_add_duplicate(client, person_foo, person_bar): "value": "12345", } client.post( - reverse("person_identity-list", kwargs={"person_id": person_bar.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_bar.id}), + data=data, ) with pytest.raises(ValidationError): client.post( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}), + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}), data=data, ) @@ -248,18 +250,20 @@ def test_identity_add_valid_duplicate(client, person_foo, person_bar): "value": "12345", } client.post( - reverse("person_identity-list", kwargs={"person_id": person_bar.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_bar.id}), + data=data, ) client.post( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}), + data=data, ) @pytest.mark.django_db def test_identity_delete(client, person_foo): response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 0 @@ -270,7 +274,8 @@ def test_identity_delete(client, person_foo): "value": "12345", } post_response = client.post( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}), + data=data, ) identity_id = post_response.json()["id"] @@ -281,12 +286,13 @@ def test_identity_delete(client, person_foo): "value": "1234413241235", } post_response2 = client.post( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}), + data=data, ) identity_id2 = post_response2.json()["id"] response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 2 @@ -294,14 +300,14 @@ def test_identity_delete(client, person_foo): # Delete the first identity created client.delete( reverse( - "person_identity-detail", + "v1:person_identity-detail", kwargs={"person_id": person_foo.id, "id": identity_id}, ) ) # Check that the other identity is still there response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] @@ -312,7 +318,7 @@ def test_identity_delete(client, person_foo): @pytest.mark.django_db def test_identity_update(client, person_foo): response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 0 @@ -323,11 +329,12 @@ def test_identity_update(client, person_foo): "value": "12345", } client.post( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}), data=data + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}), + data=data, ) response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 1 @@ -345,7 +352,7 @@ def test_identity_update(client, person_foo): } patch_response = client.patch( reverse( - "person_identity-detail", + "v1:person_identity-detail", kwargs={"person_id": person_foo.id, "id": identity_id}, ), data=data_updated, @@ -353,7 +360,7 @@ def test_identity_update(client, person_foo): assert patch_response.status_code == status.HTTP_200_OK response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) results = response.json()["results"] assert len(results) == 1 @@ -367,25 +374,25 @@ def test_identity_update(client, person_foo): def test_remove_person( client, person_foo, role_data_guest, person_foo_verified, person_foo_not_verified ): - url = reverse("person_role-list", kwargs={"person_id": person_foo.id}) + url = reverse("v1:person_role-list", kwargs={"person_id": person_foo.id}) client.post(url, role_data_guest) roles_for_person = client.get(url).json()["results"] assert len(roles_for_person) == 1 response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) assert len(response.json()["results"]) == 2 # Delete the person and check that the data has been removed - client.delete(reverse("person-detail", kwargs={"id": person_foo.id})) + client.delete(reverse("v1:person-detail", kwargs={"id": person_foo.id})) updated_role_data = client.get(url) assert len(updated_role_data.json()["results"]) == 0 response = client.get( - reverse("person_identity-list", kwargs={"person_id": person_foo.id}) + reverse("v1:person_identity-list", kwargs={"person_id": person_foo.id}) ) assert len(response.json()["results"]) == 0 @@ -394,7 +401,7 @@ def test_remove_person( def test_add_duplicate_role_fails( client, person_foo: Person, person_foo_role: PersonRole ): - url = reverse("person_role-list", kwargs={"person_id": person_foo.id}) + url = reverse("v1:person_role-list", kwargs={"person_id": person_foo.id}) roles_for_person = client.get(url).json()["results"] assert len(roles_for_person) == 1 diff --git a/greg/tests/api/test_sponsor.py b/greg/tests/api/test_sponsor.py index 06e5eb0c74045772401d143b3e2f7eb1171e88d4..ce444dbbf5e0dbd58527895c81381a4ffcf1b635 100644 --- a/greg/tests/api/test_sponsor.py +++ b/greg/tests/api/test_sponsor.py @@ -12,13 +12,13 @@ def test_add_sponsor(client): "last_name": "Sponsor", } - post_response = client.post(reverse("sponsor-list"), data=data) + post_response = client.post(reverse("v1:sponsor-list"), data=data) assert post_response.status_code == status.HTTP_201_CREATED response_data = post_response.json() list_response = client.get( - reverse("sponsor-detail", kwargs={"id": response_data["id"]}) + reverse("v1:sponsor-detail", kwargs={"id": response_data["id"]}) ) list_response_data = list_response.json() @@ -29,7 +29,7 @@ def test_add_sponsor(client): @pytest.mark.django_db def test_sponsor_guest_list(client, sponsor_guy, person_foo_role): - url = reverse("sponsor_guests-list", kwargs={"sponsor_id": sponsor_guy.id}) + url = reverse("v1:sponsor_guests-list", kwargs={"sponsor_id": sponsor_guy.id}) guests_for_sponsor = client.get(url).json()["results"] assert len(guests_for_sponsor) == 1 @@ -38,7 +38,7 @@ def test_sponsor_guest_list(client, sponsor_guy, person_foo_role): @pytest.mark.django_db def test_sponsor_empty_guest_list(client, sponsor_guy): - url = reverse("sponsor_guests-list", kwargs={"sponsor_id": sponsor_guy.id}) + url = reverse("v1:sponsor_guests-list", kwargs={"sponsor_id": sponsor_guy.id}) guests_for_sponsor = client.get(url).json()["results"] assert len(guests_for_sponsor) == 0 diff --git a/greg/urls.py b/greg/urls.py index aae406a6ca1128569d8b7efd1140e97e1b912da4..b378dd77e8b70f451eedd24b350543662a8c8c71 100644 --- a/greg/urls.py +++ b/greg/urls.py @@ -16,9 +16,25 @@ Including another URLconf from typing import List from django.urls import path, include from django.urls.resolvers import URLResolver +from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView +from rest_framework.versioning import NamespaceVersioning from greg.api import urls as api_urls +from greg.api.views.health import Health urlpatterns: List[URLResolver] = [ - path("api/", include(api_urls.urlpatterns)), + path( + "schema/", + SpectacularAPIView.as_view(versioning_class=NamespaceVersioning), + name="schema", + ), # type: ignore + path( + "schema/swagger-ui/", + SpectacularSwaggerView.as_view( + url_name="schema", versioning_class=NamespaceVersioning + ), # type: ignore + name="swagger-ui", + ), + path("health/", Health.as_view()), # type: ignore + path("api/v1/", include((api_urls.urlpatterns, "greg"), namespace="v1")), ] diff --git a/gregsite/settings/base.py b/gregsite/settings/base.py index fb28c3b132d1a5df72cc2eeb3abe08bc02b9ca4b..11236a8a01cee893538b3e94dea43b32bfa6d865 100644 --- a/gregsite/settings/base.py +++ b/gregsite/settings/base.py @@ -58,6 +58,9 @@ MIDDLEWARE = [ ] REST_FRAMEWORK = { + "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.NamespaceVersioning", + "DEFAULT_VERSION": "v1", + "ALLOWED_VERSIONS": ("v1",), "DEFAULT_AUTHENTICATION_CLASSES": ( "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.SessionAuthentication",