diff --git a/administration/views.py b/administration/views.py index 8f4c8158860895b3f47512630bf581a7a5fe427d..52cb59f2a4a0e4656b0d3ad0113a5533270e3a20 100644 --- a/administration/views.py +++ b/administration/views.py @@ -12,6 +12,7 @@ from administration.services import StatisticService, DetailVerificationService, from app.models import Category, Materi, ViewStatistics, DownloadStatistics, Comment, Like, LaporanMateri, AdminNotification from authentication.models import User from datetime import datetime +from app.models import NotifikasiKontributor from administration.utils import generate_time_step @@ -82,6 +83,10 @@ class DetailVerificationView(TemplateView): verif_report = VerificationReport( report=report, materi=materi, user=self.request.user, status=materi.get_status_display()) verif_report.save() + + new_kontributor_notif = NotifikasiKontributor(materi=materi, user=materi.uploader, feedback=materi.get_status_display()) + new_kontributor_notif.save() + return HttpResponseRedirect("/administration/") @@ -585,6 +590,8 @@ def blok_materi(request, *args, **kwargs): if materi.status == "APPROVE" and LaporanMateri.objects.filter(is_rejected=False, materi_id=materi.id): materi.status = "BLOCKED" materi.save() + new_kontributor_notif = NotifikasiKontributor(materi=materi, user=materi.uploader, feedback=materi.get_status_display()) + new_kontributor_notif.save() return HttpResponseRedirect(ADMINISTRATION_REPORT) diff --git a/app/migrations/0028_notifikasikontributor.py b/app/migrations/0028_notifikasikontributor.py new file mode 100644 index 0000000000000000000000000000000000000000..8b198645300bae7ee7dcf9dd16dc7119de709310 --- /dev/null +++ b/app/migrations/0028_notifikasikontributor.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1 on 2020-10-31 16:29 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('app', '0027_readlater'), + ] + + operations = [ + migrations.CreateModel( + name='NotifikasiKontributor', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('feedback', models.CharField(default='', max_length=20)), + ('materi', models.ForeignKey(max_length=120, on_delete=django.db.models.deletion.CASCADE, to='app.materi')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/app/migrations/0029_merge_20201101_0217.py b/app/migrations/0029_merge_20201101_0217.py new file mode 100644 index 0000000000000000000000000000000000000000..69826d1afcfbd93ecf7643f8109e292879d785b4 --- /dev/null +++ b/app/migrations/0029_merge_20201101_0217.py @@ -0,0 +1,14 @@ +# Generated by Django 3.1 on 2020-10-31 19:17 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0028_notifikasikontributor'), + ('app', '0028_adminnotification'), + ] + + operations = [ + ] diff --git a/app/models.py b/app/models.py index 9af91f66cb8094baf9cce6cf2b4573a98cf3ac58..536b917fc5eee5fd234dceb3419ebaf549080d02 100644 --- a/app/models.py +++ b/app/models.py @@ -331,5 +331,13 @@ class ReadLater(models.Model): class Meta: unique_together = ["materi", "user"] +class NotifikasiKontributor(models.Model): + materi = models.ForeignKey(Materi, on_delete=models.CASCADE, max_length=120) + user = models.ForeignKey(User, on_delete=models.CASCADE) + feedback = models.CharField(max_length=20, default="") + + def __str__(self): + return "Status: {}".format(self.feedback) + class AdminNotification(models.Model): materi = models.ForeignKey(Materi, on_delete=models.CASCADE) diff --git a/app/templates/app/includes/navigation.html b/app/templates/app/includes/navigation.html index 956d34c1041f387dcea48b5b4febb479efe13637..b50f655fbc127d401cf1917f34e195fc55e9b0ec 100644 --- a/app/templates/app/includes/navigation.html +++ b/app/templates/app/includes/navigation.html @@ -11,6 +11,21 @@ <ul class="navbar-nav ml-auto"> {% if request.user.is_contributor %} + <li class="nav-item dropdown"> + <a id="notifBtn" class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">Notifikasi</a> + <div class="dropdown-menu show" aria-labelledby="notifBtn"> + {% if kontributor_notif %} + {% for notif in kontributor_notif %} + <a class="dropdown-item" style="white-space: break-spaces;" href="{% url 'dashboard' %}">Materi "{{notif.materi.title}}" <br>{{ notif }}</a> + <div class="dropdown-divider"></div> + {% endfor %} + {% else %} + <a class="dropdown-item disabled" href="#" style="white-space: break-spaces;">Anda tidak memiliki notifikasi baru</a> + {% endif %} + </div> + </a> + </li> + <li class="nav-item"> <a class="nav-link" href="/dashboard/"> <span class="mr-2 d-none d-lg-inline text-gray-600 small">Dasbor</span> diff --git a/app/tests.py b/app/tests.py index 27bc5b1c74a337568b8d2ae803de2f0558b60fb8..70a6ce3257865de95350ee668681e7d027fb8c2f 100644 --- a/app/tests.py +++ b/app/tests.py @@ -45,7 +45,7 @@ from app.views import UploadMateriHTML, add_rating_materi from .models import (Category, Comment, DislikeComment, DownloadStatistics, Like, LikeComment, Materi, Rating, RatingContributor, - ReadLater, ReqMaterial, Review, ViewStatistics, AdminNotification) + ReadLater, ReqMaterial, Review, ViewStatistics, AdminNotification, NotifikasiKontributor) from .services import DetailMateriService from .views import (DaftarKatalog, DashboardKontributorView, DetailMateri, KatalogPerKontributorView, MateriFavorite, @@ -4024,6 +4024,77 @@ class UploadMateriTest(TestCase): self.assertEqual(Materi.objects.count(), 1) +class NotifikasiKontributorTest(TestCase): + def setUp(self): + self.client = Client() + self.contributor_credential = {"email": "kontributor@gov.id", "password": "passwordtest"} + self.contributor = get_user_model().objects.create_user( + **self.contributor_credential, name="Kontributor", is_contributor=True + ) + + self.admin_credential = { + "email": "admin@gov.id", + "password": "passwordtest" + } + self.admin = get_user_model().objects.create_user( + **self.admin_credential, name="Admin", is_admin=True) + + self.setUpImage() + self.content = SimpleUploadedFile("ExampleFile221.pdf", b"Test file") + self.category = Category.objects.create(id="1", name="medis", description="kategori medis") + VerificationSetting.objects.create(title="Kriteria 1", description="memenuhi kriteria 1", archived=False, pk=1) + + @override_settings(MEDIA_ROOT=tempfile.gettempdir()) + def setUpImage(self): + self.cover = InMemoryUploadedFile( + BytesIO(base64.b64decode(TEST_IMAGE)), + field_name='tempfile', + name='tempfile.png', + content_type='image/png', + size=len(TEST_IMAGE), + charset='utf-8', + ) + + def test_no_notification(self): + self.client.login(**self.contributor_credential) + notifs = NotifikasiKontributor.objects.filter(user=self.contributor) + self.assertEqual(notifs.count(), 0) + self.client.logout() + + def test_notification(self): + # Client as Kontributor posting new Materi + self.client.login(**self.contributor_credential) + self.client.post( + "/unggah/", data={"title":"Materi 1", "author":"Agas", "publisher":"Kelas SC", "release_year":"2000", + "descriptions":"Deskripsi Materi 1", 'categories':"1", + "cover":self.cover, "content":self.content, + "yt_video_id":"jNwz4L9MGVY"} + ) + self.client.logout() + + # Client as Admin disapproving the Materi + self.client.login(**self.admin_credential) + materi = Materi.objects.get(title="Materi 1", uploader=self.contributor) + pk_new_materi = materi.id + self.client.post( + "/administration/detail-verif/"+str(pk_new_materi)+"/", data={ + 'kriteria-1':'0','feedback':"a", 'action':"disapprove" + } + ) + self.client.logout() + self.assertEqual(NotifikasiKontributor.objects.filter(materi=materi, user=self.contributor).count(), 1) + + # Client as Kontributor get notifications + self.client.login(**self.contributor_credential) + notif = NotifikasiKontributor.objects.get(materi=materi, user=self.contributor) + html = self.client.get("/dashboard/").content.decode("utf-8") + self.assertIn(str(notif), html) + + # Client as Kontributor check Materi detail, and the notification should be gone + self.client.get("/materi/"+str(materi.id)+"/") + self.assertEqual(NotifikasiKontributor.objects.filter(materi=materi, user=self.contributor).count(), 0) + + class AdminNotificationTest(TestCase): def setUp(self): diff --git a/app/views.py b/app/views.py index bba8b37f7761fe48dedd0eba481a423f3494d1f1..12bbc08ca1ad98d48615e56838d8bd99cca6b92e 100644 --- a/app/views.py +++ b/app/views.py @@ -35,6 +35,7 @@ from app.models import ( Rating, RatingContributor, SubmitVisitor, ReadLater, + NotifikasiKontributor, AdminNotification ) from authentication.models import User @@ -185,6 +186,9 @@ class DetailMateri(TemplateView): context["review_data"] = query_set_for_review context["has_liked_comment"] = has_liked context["has_disliked_comment"] = has_disliked + if request.user.is_authenticated and request.user.is_contributor: + opened_notif = NotifikasiKontributor.objects.filter(user=request.user, materi=context["materi_data"]) + opened_notif.delete() return self.render_to_response(context=context) diff --git a/authentication/views.py b/authentication/views.py index c33e983e6562b3e40b242cdd54a447a0db57d7ff..852894bf99a187ed02f54d75d4014ef0929c09e9 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -77,3 +77,12 @@ class Login(TemplateView): return self.do_login(context, email, password, request, result) +from app.models import NotifikasiKontributor +def kontributor_notif_context(request): + if request.user.is_authenticated and request.user.is_contributor: + notifs = NotifikasiKontributor.objects.filter(user=request.user) + return { + 'kontributor_notif':notifs + } + else: + return {} \ No newline at end of file diff --git a/digipus/settings.py b/digipus/settings.py index 7b0b547da75fd98b6085d6ba54cd700c68fc4d70..149fd47d1e7cffe34bb483d82aa92296322a6614 100644 --- a/digipus/settings.py +++ b/digipus/settings.py @@ -81,6 +81,8 @@ TEMPLATES = [ "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", + + "authentication.views.kontributor_notif_context" ], }, },