From b48708652fa6934b44238163c5d97687c1d7f519 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Wed, 17 Mar 2021 00:27:53 +0100 Subject: [PATCH] delete model check fixes + sync log --- .../migrations/0112_remove_synclog_space.py | 17 +++ cookbook/models.py | 3 +- cookbook/provider/dropbox.py | 3 +- cookbook/provider/local.py | 1 - cookbook/provider/nextcloud.py | 1 - cookbook/tests/api/test_api_sync_log.py | 70 ------------ .../tests/pytest/api/test_api_meal_type.py | 2 +- cookbook/tests/pytest/api/test_api_storage.py | 2 +- .../tests/pytest/api/test_api_supermarket.py | 2 +- cookbook/tests/pytest/api/test_api_sync.py | 2 +- .../tests/pytest/api/test_api_sync_log.py | 105 ++++++++++++++++++ cookbook/views/api.py | 2 +- 12 files changed, 129 insertions(+), 81 deletions(-) create mode 100644 cookbook/migrations/0112_remove_synclog_space.py delete mode 100644 cookbook/tests/api/test_api_sync_log.py create mode 100644 cookbook/tests/pytest/api/test_api_sync_log.py diff --git a/cookbook/migrations/0112_remove_synclog_space.py b/cookbook/migrations/0112_remove_synclog_space.py new file mode 100644 index 000000000..37bf97592 --- /dev/null +++ b/cookbook/migrations/0112_remove_synclog_space.py @@ -0,0 +1,17 @@ +# Generated by Django 3.1.7 on 2021-03-16 23:21 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('cookbook', '0111_space_created_by'), + ] + + operations = [ + migrations.RemoveField( + model_name='synclog', + name='space', + ), + ] diff --git a/cookbook/models.py b/cookbook/models.py index cd335f7ca..acfdb7ab8 100644 --- a/cookbook/models.py +++ b/cookbook/models.py @@ -220,8 +220,7 @@ class SyncLog(models.Model, PermissionModelMixin): msg = models.TextField(default="") created_at = models.DateTimeField(auto_now_add=True) - space = models.ForeignKey(Space, on_delete=models.CASCADE) - objects = ScopedManager(space='space') + objects = ScopedManager(space='sync__space') def __str__(self): return f"{self.created_at}:{self.sync} - {self.status}" diff --git a/cookbook/provider/dropbox.py b/cookbook/provider/dropbox.py index af3d410ee..ca6994b9b 100644 --- a/cookbook/provider/dropbox.py +++ b/cookbook/provider/dropbox.py @@ -27,7 +27,7 @@ class Dropbox(Provider): try: recipes = r.json() except ValueError: - log_entry = SyncLog(status='ERROR', msg=str(r), sync=monitor, space=monitor.space) + log_entry = SyncLog(status='ERROR', msg=str(r), sync=monitor) log_entry.save() return r @@ -51,7 +51,6 @@ class Dropbox(Provider): status='SUCCESS', msg='Imported ' + str(import_count) + ' recipes', sync=monitor, - space=monitor.space, ) log_entry.save() diff --git a/cookbook/provider/local.py b/cookbook/provider/local.py index 1298e3e48..d24c4eb14 100644 --- a/cookbook/provider/local.py +++ b/cookbook/provider/local.py @@ -33,7 +33,6 @@ class Local(Provider): status='SUCCESS', msg='Imported ' + str(import_count) + ' recipes', sync=monitor, - space=monitor.space, ) log_entry.save() diff --git a/cookbook/provider/nextcloud.py b/cookbook/provider/nextcloud.py index f11109ede..d67c02446 100644 --- a/cookbook/provider/nextcloud.py +++ b/cookbook/provider/nextcloud.py @@ -49,7 +49,6 @@ class Nextcloud(Provider): status='SUCCESS', msg='Imported ' + str(import_count) + ' recipes', sync=monitor, - space=monitor.space ) log_entry.save() diff --git a/cookbook/tests/api/test_api_sync_log.py b/cookbook/tests/api/test_api_sync_log.py deleted file mode 100644 index 0efaaabdb..000000000 --- a/cookbook/tests/api/test_api_sync_log.py +++ /dev/null @@ -1,70 +0,0 @@ -import json - -from cookbook.models import Storage, Sync, SyncLog -from cookbook.tests.views.test_views import TestViews -from django.contrib import auth -from django.urls import reverse - - -class TestApiSyncLog(TestViews): - - def setUp(self): - super(TestApiSyncLog, self).setUp() - self.storage = Storage.objects.create( - name='Test Storage', - username='test', - password='password', - token='token', - url='url', - created_by=auth.get_user(self.admin_client_1) - ) - - self.sync = Sync.objects.create( - storage=self.storage, - path='path' - ) - - self.sync_log = SyncLog.objects.create( - sync=self.sync, status='success' - ) - - def test_sync_log_list(self): - # verify view permissions are applied accordingly - self.batch_requests( - [ - (self.anonymous_client, 403), - (self.guest_client_1, 403), - (self.user_client_1, 403), - (self.admin_client_1, 200), - (self.superuser_client, 200) - ], - reverse('api:synclog-list') - ) - - # verify log entry is returned - r = self.admin_client_1.get(reverse('api:synclog-list')) - self.assertEqual(r.status_code, 200) - response = json.loads(r.content) - self.assertEqual(len(response), 1) - self.assertEqual(response[0]['status'], self.sync_log.status) - - def test_sync_log_update(self): - # read only view - r = self.admin_client_1.patch( - reverse( - 'api:synclog-detail', - args={self.sync.id} - ), - {'path': 'new'}, - content_type='application/json' - ) - self.assertEqual(r.status_code, 405) - - def test_sync_log_delete(self): - # read only view - r = self.admin_client_1.delete( - reverse( - 'api:synclog-detail', - args={self.sync.id}) - ) - self.assertEqual(r.status_code, 405) diff --git a/cookbook/tests/pytest/api/test_api_meal_type.py b/cookbook/tests/pytest/api/test_api_meal_type.py index 17e0a7ea3..de3c73da2 100644 --- a/cookbook/tests/pytest/api/test_api_meal_type.py +++ b/cookbook/tests/pytest/api/test_api_meal_type.py @@ -129,4 +129,4 @@ def test_delete(u1_s1, u1_s2, obj_1): assert r.status_code == 204 with scopes_disabled(): - assert Food.objects.count() == 0 + assert MealType.objects.count() == 0 diff --git a/cookbook/tests/pytest/api/test_api_storage.py b/cookbook/tests/pytest/api/test_api_storage.py index 0fac895ae..b1302a58c 100644 --- a/cookbook/tests/pytest/api/test_api_storage.py +++ b/cookbook/tests/pytest/api/test_api_storage.py @@ -119,4 +119,4 @@ def test_delete(a1_s1, a1_s2, obj_1): assert r.status_code == 204 with scopes_disabled(): - assert RecipeBook.objects.count() == 0 + assert Storage.objects.count() == 0 diff --git a/cookbook/tests/pytest/api/test_api_supermarket.py b/cookbook/tests/pytest/api/test_api_supermarket.py index 318ad9e9d..76c7cf41b 100644 --- a/cookbook/tests/pytest/api/test_api_supermarket.py +++ b/cookbook/tests/pytest/api/test_api_supermarket.py @@ -127,4 +127,4 @@ def test_delete(u1_s1, u1_s2, obj_1): assert r.status_code == 204 with scopes_disabled(): - assert RecipeBook.objects.count() == 0 + assert Supermarket.objects.count() == 0 diff --git a/cookbook/tests/pytest/api/test_api_sync.py b/cookbook/tests/pytest/api/test_api_sync.py index 90bd75ae7..7a7d9d46e 100644 --- a/cookbook/tests/pytest/api/test_api_sync.py +++ b/cookbook/tests/pytest/api/test_api_sync.py @@ -112,4 +112,4 @@ def test_delete(a1_s1, a1_s2, obj_1): assert r.status_code == 204 with scopes_disabled(): - assert RecipeBook.objects.count() == 0 + assert Sync.objects.count() == 0 diff --git a/cookbook/tests/pytest/api/test_api_sync_log.py b/cookbook/tests/pytest/api/test_api_sync_log.py new file mode 100644 index 000000000..579699dd1 --- /dev/null +++ b/cookbook/tests/pytest/api/test_api_sync_log.py @@ -0,0 +1,105 @@ +import json + +import pytest +from django.contrib import auth +from django.urls import reverse +from django_scopes import scopes_disabled + +from cookbook.models import RecipeBook, Storage, Sync, SyncLog + +LIST_URL = 'api:synclog-list' +DETAIL_URL = 'api:synclog-detail' + + +@pytest.fixture() +def obj_1(space_1, u1_s1): + s = Storage.objects.create(name='Test Storage 1', username='test', password='password', token='token', url='url', created_by=auth.get_user(u1_s1), space=space_1, ) + sy = Sync.objects.create(storage=s, path='path', space=space_1, ) + return SyncLog.objects.create(sync=sy, status=1) + + +@pytest.fixture +def obj_2(space_1, u1_s1): + s = Storage.objects.create(name='Test Storage 2', username='test', password='password', token='token', url='url', created_by=auth.get_user(u1_s1), space=space_1, ) + sy = Sync.objects.create(storage=s, path='path', space=space_1, ) + return SyncLog.objects.create(sync=sy, status=1) + + +@pytest.mark.parametrize("arg", [ + ['a_u', 403], + ['g1_s1', 403], + ['u1_s1', 403], + ['a1_s1', 200], +]) +def test_list_permission(arg, request): + c = request.getfixturevalue(arg[0]) + assert c.get(reverse(LIST_URL)).status_code == arg[1] + + +def test_list_space(obj_1, obj_2, a1_s1, a1_s2, space_2): + assert len(json.loads(a1_s1.get(reverse(LIST_URL)).content)) == 2 + assert len(json.loads(a1_s2.get(reverse(LIST_URL)).content)) == 0 + + obj_1.sync.space = space_2 + obj_1.sync.save() + + assert len(json.loads(a1_s1.get(reverse(LIST_URL)).content)) == 1 + assert len(json.loads(a1_s2.get(reverse(LIST_URL)).content)) == 1 + + +@pytest.mark.parametrize("arg", [ + ['a_u', 403], + ['g1_s1', 403], + ['u1_s1', 403], + ['a1_s1', 405], + ['g1_s2', 403], + ['u1_s2', 403], + ['a1_s2', 405], +]) +def test_update(arg, request, obj_1): + c = request.getfixturevalue(arg[0]) + r = c.patch( + reverse( + DETAIL_URL, + args={obj_1.id} + ), + {'msg': 'new'}, + content_type='application/json' + ) + assert r.status_code == arg[1] + + +@pytest.mark.parametrize("arg", [ + ['a_u', 403], + ['g1_s1', 403], + ['u1_s1', 403], + ['a1_s1', 405], +]) +def test_add(arg, request, a1_s2, obj_1): + c = request.getfixturevalue(arg[0]) + r = c.post( + reverse(LIST_URL), + {'msg': 'test'}, + content_type='application/json' + ) + response = json.loads(r.content) + assert r.status_code == arg[1] + + +def test_delete(a1_s1, a1_s2, obj_1): + r = a1_s2.delete( + reverse( + DETAIL_URL, + args={obj_1.id} + ) + ) + assert r.status_code == 405 + + r = a1_s1.delete( + reverse( + DETAIL_URL, + args={obj_1.id} + ) + ) + + assert r.status_code == 405 diff --git a/cookbook/views/api.py b/cookbook/views/api.py index d95ae482e..301be9ec9 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -136,7 +136,7 @@ class SyncLogViewSet(viewsets.ReadOnlyModelViewSet): permission_classes = [CustomIsAdmin, ] def get_queryset(self): - return self.queryset.filter(space=self.request.user.userpreference.space) + return self.queryset.filter(sync__space=self.request.user.userpreference.space) class SupermarketViewSet(viewsets.ModelViewSet, StandardFilterMixin):