diff --git a/backend/src/baserow/api/v0/applications/errors.py b/backend/src/baserow/api/v0/applications/errors.py new file mode 100644 index 000000000..a6d2b0e6d --- /dev/null +++ b/backend/src/baserow/api/v0/applications/errors.py @@ -0,0 +1 @@ +ERROR_USER_NOT_IN_GROUP = 'ERROR_USER_NOT_IN_GROUP' diff --git a/backend/src/baserow/api/v0/applications/serializers.py b/backend/src/baserow/api/v0/applications/serializers.py index 0159757c2..8d87124a0 100644 --- a/backend/src/baserow/api/v0/applications/serializers.py +++ b/backend/src/baserow/api/v0/applications/serializers.py @@ -27,3 +27,10 @@ class ApplicationCreateSerializer(serializers.ModelSerializer): class Meta: model = Application fields = ('name', 'type') + + + +class ApplicationUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = Application + fields = ('name',) diff --git a/backend/src/baserow/api/v0/applications/urls.py b/backend/src/baserow/api/v0/applications/urls.py index aaaec1f02..bdb9f24b1 100644 --- a/backend/src/baserow/api/v0/applications/urls.py +++ b/backend/src/baserow/api/v0/applications/urls.py @@ -1,10 +1,11 @@ from django.conf.urls import url -from .views import ApplicationsView +from .views import ApplicationsView, ApplicationView app_name = 'baserow.api.v0.group' urlpatterns = [ - url(r'(?P<group_id>[0-9]+)/$', ApplicationsView.as_view(), name='list') + url(r'group/(?P<group_id>[0-9]+)/$', ApplicationsView.as_view(), name='list'), + url(r'(?P<application_id>[0-9]+)/$', ApplicationView.as_view(), name='item'), ] diff --git a/backend/src/baserow/api/v0/applications/views.py b/backend/src/baserow/api/v0/applications/views.py index 36cef62c9..e35a0282e 100644 --- a/backend/src/baserow/api/v0/applications/views.py +++ b/backend/src/baserow/api/v0/applications/views.py @@ -5,11 +5,15 @@ from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated -from baserow.api.v0.decorators import validate_body +from baserow.api.v0.decorators import validate_body, map_exceptions from baserow.core.models import GroupUser, Application from baserow.core.handler import CoreHandler +from baserow.core.exceptions import UserNotIngroupError -from .serializers import ApplicationSerializer, ApplicationCreateSerializer +from .serializers import ( + ApplicationSerializer, ApplicationCreateSerializer, ApplicationUpdateSerializer +) +from .errors import ERROR_USER_NOT_IN_GROUP class ApplicationsView(APIView): @@ -45,3 +49,38 @@ class ApplicationsView(APIView): request.user, group_user.group, data['type'], name=data['name']) return Response(ApplicationSerializer(application).data) + + +class ApplicationView(APIView): + permission_classes = (IsAuthenticated,) + core_handler = CoreHandler() + + @transaction.atomic + @validate_body(ApplicationUpdateSerializer) + @map_exceptions({ + UserNotIngroupError: ERROR_USER_NOT_IN_GROUP + }) + def patch(self, request, data, application_id): + """Updates the application if it belongs to a user.""" + application = get_object_or_404( + Application.objects.select_related('group').select_for_update(), + pk=application_id + ) + application = self.core_handler.update_application( + request.user, application, name=data['name']) + + return Response(ApplicationSerializer(application).data) + + @transaction.atomic + @map_exceptions({ + UserNotIngroupError: ERROR_USER_NOT_IN_GROUP + }) + def delete(self, request, application_id): + """Deletes an existing application if the user belongs to the group.""" + application = get_object_or_404( + Application.objects.select_related('group'), + pk=application_id + ) + self.core_handler.delete_application(request.user, application) + + return Response(status=204) diff --git a/backend/tests/baserow/api/v0/applications/test_application_views.py b/backend/tests/baserow/api/v0/applications/test_application_views.py index 1819f601e..7f0a8272d 100644 --- a/backend/tests/baserow/api/v0/applications/test_application_views.py +++ b/backend/tests/baserow/api/v0/applications/test_application_views.py @@ -92,3 +92,74 @@ def test_create_application(api_client, data_fixture): assert response_json['id'] == database.id assert response_json['name'] == database.name assert response_json['order'] == database.order + + +@pytest.mark.django_db +def test_update_application(api_client, data_fixture): + user, token = data_fixture.create_user_and_token() + user_2, token_2 = data_fixture.create_user_and_token() + group = data_fixture.create_group(user=user) + group_2 = data_fixture.create_group(user=user_2) + application = data_fixture.create_database_application(group=group) + application_2 = data_fixture.create_database_application(group=group_2) + + url = reverse('api_v0:applications:item', + kwargs={'application_id': application_2.id}) + response = api_client.patch( + url, + {'name': 'Test 1'}, + format='json', + HTTP_AUTHORIZATION=f'JWT {token}' + ) + response_json = response.json() + assert response.status_code == 400 + assert response_json['error'] == 'ERROR_USER_NOT_IN_GROUP' + + url = reverse('api_v0:applications:item', kwargs={'application_id': application.id}) + response = api_client.patch( + url, + {'UNKNOWN_FIELD': 'Test 1'}, + format='json', + HTTP_AUTHORIZATION=f'JWT {token}' + ) + response_json = response.json() + assert response.status_code == 400 + assert response_json['error'] == 'ERROR_REQUEST_BODY_VALIDATION' + + url = reverse('api_v0:applications:item', kwargs={'application_id': application.id}) + response = api_client.patch( + url, + {'name': 'Test 1'}, + format='json', + HTTP_AUTHORIZATION=f'JWT {token}' + ) + response_json = response.json() + assert response.status_code == 200 + assert response_json['id'] == application.id + assert response_json['name'] == 'Test 1' + + application.refresh_from_db() + assert application.name == 'Test 1' + + +@pytest.mark.django_db +def test_delete_application(api_client, data_fixture): + user, token = data_fixture.create_user_and_token() + user_2, token_2 = data_fixture.create_user_and_token() + group = data_fixture.create_group(user=user) + group_2 = data_fixture.create_group(user=user_2) + application = data_fixture.create_database_application(group=group) + application_2 = data_fixture.create_database_application(group=group_2) + + url = reverse('api_v0:applications:item', + kwargs={'application_id': application_2.id}) + response = api_client.delete(url, HTTP_AUTHORIZATION=f'JWT {token}') + response_json = response.json() + assert response.status_code == 400 + assert response_json['error'] == 'ERROR_USER_NOT_IN_GROUP' + + url = reverse('api_v0:applications:item', kwargs={'application_id': application.id}) + response = api_client.delete(url, HTTP_AUTHORIZATION=f'JWT {token}') + assert response.status_code == 204 + + assert Database.objects.all().count() == 1