From de1ba7c9f2423af63eb7390f117a39ac65bd193a Mon Sep 17 00:00:00 2001 From: Aarni Halinen Date: Thu, 14 Jan 2021 22:05:04 +0200 Subject: [PATCH] Add soft delete functionality for Event, SignupForm, Feed & JobAd --- webapp/migrations/0075_auto_20210114_2155.py | 33 +++++++++++++ webapp/models.py | 4 ++ webapp/tests/test_event.py | 6 ++- webapp/views.py | 50 +++++++++++++++++--- 4 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 webapp/migrations/0075_auto_20210114_2155.py diff --git a/webapp/migrations/0075_auto_20210114_2155.py b/webapp/migrations/0075_auto_20210114_2155.py new file mode 100644 index 0000000..ce68abd --- /dev/null +++ b/webapp/migrations/0075_auto_20210114_2155.py @@ -0,0 +1,33 @@ +# Generated by Django 2.1.5 on 2021-01-14 19:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('webapp', '0074_signup_deleted'), + ] + + operations = [ + migrations.AddField( + model_name='event', + name='deleted', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='feed', + name='deleted', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='jobad', + name='deleted', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='signupform', + name='deleted', + field=models.BooleanField(default=False), + ), + ] diff --git a/webapp/models.py b/webapp/models.py index 36be46f..f7db2a4 100644 --- a/webapp/models.py +++ b/webapp/models.py @@ -55,6 +55,7 @@ class Feed(BaseFeed): publish_time = models.DateTimeField(default=timezone.now) autohide = models.DateTimeField(default=month_from_now) autohide_enabled = models.BooleanField(default=False) + deleted = models.BooleanField(default=False) def __str__(self): return _('Feed: {}').format(self.title) @@ -72,6 +73,7 @@ class Event(BaseFeed): signupForm = models.ManyToManyField( 'SignupForm', blank=True, related_name="event") location = models.CharField(max_length=255, blank=True) + deleted = models.BooleanField(default=False) def __str__(self): return _('Event: {}').format(self.title) @@ -109,6 +111,7 @@ class SignupForm(models.Model): visible = models.BooleanField(default=True) quota = models.PositiveIntegerField(blank=True, null=True) email_content = models.TextField(blank=True) + deleted = models.BooleanField(default=False) def __str__(self): return _('#{} {}').format(self.id, self.title) @@ -185,6 +188,7 @@ class JobAd(models.Model): created_at = models.DateTimeField(default=timezone.now) autohide_at = models.DateTimeField(default=month_from_now) autohide_enabled = models.BooleanField(default=False) + deleted = models.BooleanField(default=False) auditlog.register(Tag) diff --git a/webapp/tests/test_event.py b/webapp/tests/test_event.py index d00cb98..f3b4f9d 100644 --- a/webapp/tests/test_event.py +++ b/webapp/tests/test_event.py @@ -171,5 +171,7 @@ class EventTestCase(APITestCase): # Authenticate self.client.force_authenticate(user=self.authClient) response = self.client.delete(f"{URL}{self.testEventId}/") - self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) - self.assertEqual(Event.objects.count(), 3) + # Soft delete + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(Event.objects.count(), 4) + self.assertEqual(Event.objects.get(id=self.testEventId).deleted, True) diff --git a/webapp/views.py b/webapp/views.py index 3331d3e..97b57c6 100644 --- a/webapp/views.py +++ b/webapp/views.py @@ -39,7 +39,7 @@ class RootView(routers.APIRootView): class EventViewSet(ModelViewSet): - queryset = Event.objects.all() + queryset = Event.objects.filter(deleted=False) ordering = ["start_time"] serializer_class = EventSerializer permission_classes = [IsAuthenticatedOrReadOnly] @@ -54,16 +54,16 @@ class EventViewSet(ModelViewSet): self.request.method == 'POST' or \ self.request.method == 'PUT': return Event.objects.all().prefetch_related( - Prefetch('signupForm', queryset=SignupForm.objects.all(), to_attr='filtered_signup_forms') + Prefetch('signupForm', queryset=SignupForm.objects.filter(deleted=False), to_attr='filtered_signup_forms') ) since = self.request.query_params.get('since', None) if since: return Event.objects.filter(visible=True, end_time__gt=since).order_by('start_time').prefetch_related( - Prefetch('signupForm', queryset=SignupForm.objects.filter(visible=True), to_attr='filtered_signup_forms') + Prefetch('signupForm', queryset=SignupForm.objects.filter(deleted=False, visible=True), to_attr='filtered_signup_forms') ) return Event.objects.filter(visible=True, end_time__gt=timezone.now()).order_by('start_time').prefetch_related( - Prefetch('signupForm', queryset=SignupForm.objects.filter(visible=True), to_attr='filtered_signup_forms') + Prefetch('signupForm', queryset=SignupForm.objects.filter(deleted=False, visible=True), to_attr='filtered_signup_forms') ) def create(self, request, *args, **kwargs): @@ -84,9 +84,18 @@ class EventViewSet(ModelViewSet): }) return super().update(request, *args, **kwargs) + def destroy(self, request, pk=None, *args, **kwargs): + try: + event = self.get_object() + event.deleted = True + event.save() + return JsonResponse(status=200, data={"message": "OK"}) + except ObjectDoesNotExist: + return JsonResponse(status=404, data={"error": f"Event {pk} not found"}) + class SignupFormViewSet(ModelViewSet): - queryset = SignupForm.objects.all() + queryset = SignupForm.objects.filter(deleted=False) ordering = ["start_time"] serializer_class = SignupFormSerializer permission_classes = [IsAuthenticatedOrReadOnly] @@ -106,6 +115,15 @@ class SignupFormViewSet(ModelViewSet): return SignupForm.objects.all().order_by('start_time') return SignupForm.objects.filter(visible=True, end_time__gt=timezone.now()).order_by('start_time') + def destroy(self, request, pk=None, *args, **kwargs): + try: + form = self.get_object() + form.deleted = True + form.save() + return JsonResponse(status=200, data={"message": "OK"}) + except ObjectDoesNotExist: + return JsonResponse(status=404, data={"error": f"SignupForm {pk} not found"}) + @action(detail=True, methods=['post'], permission_classes=[IsAuthenticated]) def sendemail(self, request, pk=None, *args, **kwargs): subject = request.data["subject"] @@ -203,7 +221,7 @@ class SavedQuestionsViewSet(ModelViewSet): class FeedViewSet(ModelViewSet): - queryset = Feed.objects.all() + queryset = Feed.objects.filter(deleted=False) serializer_class = FeedSerializer permission_classes = [IsAuthenticatedOrReadOnly] # filter_backends = (filters.DjangoFilterBackend, SearchFilter, OrderingFilter) @@ -227,6 +245,15 @@ class FeedViewSet(ModelViewSet): return Feed.objects.filter(id__in=result_ids) + def destroy(self, request, pk=None, *args, **kwargs): + try: + post = self.get_object() + post.deleted = True + post.save() + return JsonResponse(status=200, data={"message": "OK"}) + except ObjectDoesNotExist: + return JsonResponse(status=404, data={"error": f"Post {pk} not found"}) + class TagsViewSet(ReadOnlyModelViewSet): queryset = Tag.objects.all() @@ -235,7 +262,7 @@ class TagsViewSet(ReadOnlyModelViewSet): class JobAdViewSet(ModelViewSet): - queryset = JobAd.objects.all() + queryset = JobAd.objects.filter(deleted=False) serializer_class = JobAdSerializer permission_classes = [IsAuthenticatedOrReadOnly] @@ -244,6 +271,15 @@ class JobAdViewSet(ModelViewSet): return JobAd.objects.all() return JobAd.objects.filter(visible=True, autohide_at__gt=timezone.now()) + def destroy(self, request, pk=None, *args, **kwargs): + try: + ad = self.get_object() + ad.deleted = True + ad.save() + return JsonResponse(status=200, data={"message": "OK"}) + except ObjectDoesNotExist: + return JsonResponse(status=404, data={"error": f"Job Ad {pk} not found"}) + @require_http_methods(["GET"]) def about_view(request, *args, **kwargs):