diff --git a/administration/templates/kelola_materi.html b/administration/templates/kelola_materi.html index 0e4a293d5aff71d0f7e42e97f8ff9225100cafed..24f5020d86d243a51ec7156e029b0115fb1bdd0a 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 a4cdab81fc557da42e75d73185dab0936dd81f49..8c96ead8fc43209b0e2db647ddb6aa483667d1f2 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/migrations/0023_materi_deleted_at.py b/app/migrations/0023_materi_deleted_at.py new file mode 100644 index 0000000000000000000000000000000000000000..2a695fcfe8cfa105ee5b2b04ba7b163460267b26 --- /dev/null +++ b/app/migrations/0023_materi_deleted_at.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1 on 2020-10-23 03:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0022_merge_20201011_1122'), + ] + + operations = [ + migrations.AddField( + model_name='materi', + name='deleted_at', + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/app/models.py b/app/models.py index e9342e03f9a505c772a6b65a21dcde6175ed425a..9d99924f653b7786c23a836f6236bfa198b7c9b7 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/tests.py b/app/tests.py index 1c4b142dde16abb5e1901bad43debbbbaba3f26b..4456943ab43c951546e4cf9e381eca85ff09c31e 100644 --- a/app/tests.py +++ b/app/tests.py @@ -1071,26 +1071,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 ProfilViewTest(TestCase): @classmethod def setUpTestData(cls): diff --git a/app/views.py b/app/views.py index 8716ee98e74d6bd72d3b73671a9e6fcfa254ddd0..fb82515ab3a48edd9880fa75e1aac9117347fa58 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/") diff --git a/digipus/__pycache__/settings.cpython-36.pyc b/digipus/__pycache__/settings.cpython-36.pyc index ee0772144662d7457ede232e8137ab9041115ac7..1cf78ac5dc695e4dca1c09a4b10db034aec54534 100644 Binary files a/digipus/__pycache__/settings.cpython-36.pyc and b/digipus/__pycache__/settings.cpython-36.pyc differ