From 74532b8dcd4ece236ead41a6c6fe5d7645aa1b23 Mon Sep 17 00:00:00 2001 From: Rizkhi PH Date: Fri, 23 Oct 2020 13:34:22 +0700 Subject: [PATCH 1/2] [RED] add unit test for delete materi (soft delete) --- app/tests.py | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/app/tests.py b/app/tests.py index 653a373..70779ab 100644 --- a/app/tests.py +++ b/app/tests.py @@ -1059,26 +1059,57 @@ class DashboardKontributorViewTest(TestCase): html = response.content.decode("utf-8") self.assertIn(ERROR_403_MESSAGE, html) - class DeleteMateriTest(TestCase): def setUp(self): self.client = Client() + self.admin_credential = { + "email": "admin@gov.id", + "password": id_generator() + } + self.superuser_credential = { + "email": "superuser@gov.id", + "password": id_generator() + } + self.contributor_credential = { + "email": "contributor@gov.id", + "password": id_generator() + } + + self.admin = get_user_model().objects.create_user( + **self.admin_credential, name="Admin", is_admin=True) + self.superuser = get_user_model().objects.create_user( + **self.superuser_credential, name="Superuser", is_admin=True, is_superuser=True) + self.content = SimpleUploadedFile( "content.txt", b"Test") self.cover = SimpleUploadedFile( "flower.jpg", b"Test file") - self.contributor = User.objects.create_contributor(email="kontributor@gov.id", - password="kontributor") + self.contributor = User.objects.create_contributor(**self.contributor_credential) Materi(title="Materi 1", author="Agas", uploader=self.contributor, publisher="Kelas SC", descriptions="Deskripsi Materi 1", status="APPROVE", cover=self.cover, content=self.content).save() self.materi1 = Materi.objects.first() self.url = "/materi/" + str(self.materi1.id) + "/delete" - def test_url_delete_materi_is_success(self): + def test_url_delete_materi_is_success_as_contributor(self): + self.client.login(**self.contributor_credential) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 302) + + def test_url_soft_delete_materi_is_success_as_admin(self): + self.client.login(**self.admin_credential) response = self.client.get(self.url) self.assertEqual(response.status_code, 302) - + self.materi1.refresh_from_db() + self.assertNotEqual(self.materi1.deleted_at, None) + + def test_url_soft_delete_materi_is_success_as_superuser(self): + self.client.login(**self.superuser_credential) + response = self.client.get(self.url) + self.assertEqual(response.status_code, 302) + self.materi1.refresh_from_db() + self.assertNotEqual(self.materi1.deleted_at, None) + class ProfilAdminTest(TestCase): def setUp(self): self.client = Client() -- GitLab From 1fdcbe584128f68b59c6dde364bf39ffbc7fcb98 Mon Sep 17 00:00:00 2001 From: Rizkhi PH Date: Fri, 23 Oct 2020 13:38:17 +0700 Subject: [PATCH 2/2] [GREEN] implement delete materi (soft delete) --- administration/templates/kelola_materi.html | 7 ++++++ administration/views.py | 2 +- app/models.py | 28 +++++++++++++++++++-- app/views.py | 3 +++ 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/administration/templates/kelola_materi.html b/administration/templates/kelola_materi.html index 0e4a293..24f5020 100644 --- a/administration/templates/kelola_materi.html +++ b/administration/templates/kelola_materi.html @@ -30,6 +30,7 @@ Kontributor Status Jumlah Like + Pilihan @@ -40,6 +41,7 @@ Kontributor Status Jumlah Like + Pilihan @@ -57,6 +59,11 @@ {{ materi.uploader }} {{ materi.status }} {{ materi.like_count }} + + {% if not materi.deleted_at %}Hapus + {% endif %} + {% endfor %} diff --git a/administration/views.py b/administration/views.py index a4cdab8..8c96ead 100644 --- a/administration/views.py +++ b/administration/views.py @@ -505,7 +505,7 @@ class KelolaMateriView(TemplateView): def get_context_data(self, **kwargs): context = super(KelolaMateriView, self).get_context_data(**kwargs) - context['materi_list'] = Materi.objects.all() + context['materi_list'] = Materi.all_objects.all() return context def get(self, request, *args, **kwargs): diff --git a/app/models.py b/app/models.py index a656e06..1f2cbb9 100644 --- a/app/models.py +++ b/app/models.py @@ -39,6 +39,15 @@ class Category(models.Model): class MateriManager(models.Manager): + def __init__(self, *args, **kwargs): + self.alive_only = kwargs.pop('alive_only', True) + super(MateriManager, self).__init__(*args, **kwargs) + + def get_queryset(self): + if self.alive_only: + return SoftDeletionQuerySet(self.model).filter(deleted_at=None) + return SoftDeletionQuerySet(self.model) + def search(self, search_text): search_vector = search.SearchVector("title", weight="A") search_query = search.SearchQuery(search_text) @@ -51,8 +60,23 @@ class MateriManager(models.Manager): return search_result +class SoftDeletionQuerySet(models.query.QuerySet): + def delete(self): + return super(SoftDeletionQuerySet, self).update(deleted_at=timezone.now()) -class Materi(models.Model): +class SoftDeleteModel(models.Model): + deleted_at = models.DateTimeField(blank=True, null=True) + + all_objects = MateriManager(alive_only=False) + + class Meta: + abstract = True + + def soft_delete(self): + self.deleted_at = timezone.now() + self.save() + +class Materi(SoftDeleteModel): cover = models.ImageField() content = models.FileField() title = models.CharField(max_length=50, default="Judul") @@ -61,7 +85,7 @@ class Materi(models.Model): publisher = models.CharField(max_length=30, default="Penerbit") release_year = models.IntegerField(default=current_year) pages = models.IntegerField(default=0) - descriptions = models.TextField(default="Deskripsi") + descriptions = models.TextField(default="Deskripsi") status = models.CharField(max_length=30, choices=VERIFICATION_STATUS, default=VERIFICATION_STATUS[0][0]) categories = models.ManyToManyField(Category) date_created = models.DateTimeField(default=timezone.now) diff --git a/app/views.py b/app/views.py index b0f703e..8ad14dd 100644 --- a/app/views.py +++ b/app/views.py @@ -259,6 +259,9 @@ def view_materi(request, pk): def delete_materi(request, pk): materi = get_object_or_404(Materi, pk=pk) + if request.user.is_superuser or request.user.is_admin: + materi.soft_delete() + return HttpResponseRedirect("/administration/") materi.delete() return HttpResponseRedirect("/dashboard/") -- GitLab