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