diff --git a/administration/templates/administration/includes/sidebar.html b/administration/templates/administration/includes/sidebar.html index 76be2e9d24d0e05fd64af810c4cacdeefa3ef04f..6f639a5e1be5c11e6aa51de3c22edc30491d636f 100644 --- a/administration/templates/administration/includes/sidebar.html +++ b/administration/templates/administration/includes/sidebar.html @@ -50,6 +50,11 @@ <!-- Divider --> <hr class="sidebar-divider my-0"> + <li class="nav-item"> + <a class="nav-link" href="/administration/kelola-materi"> + <span>Kelola Materi</span></a> + </li> + <li class="nav-item"> <a class="nav-link" href="/administration/news/list"> <span>Kelola Berita</span></a> diff --git a/administration/templates/kelola_materi.html b/administration/templates/kelola_materi.html new file mode 100644 index 0000000000000000000000000000000000000000..0e4a293d5aff71d0f7e42e97f8ff9225100cafed --- /dev/null +++ b/administration/templates/kelola_materi.html @@ -0,0 +1,67 @@ +{% extends 'administration/base_administrasi2.html' %} +{% load static %} + +{% block title %} +<title>Kelola Admin | Digipus</title> +{% endblock %} + +{% block content %} +<!-- Page Heading --> +<h1 class="h3 mb-2 text-gray-800">Kelola Admin</h1> +<p class="mb-4">Tekan tombol detail untuk informasi lebih lanjut tentang admin</ehp> + +<!-- DataTales Example --> +<div class="card shadow mb-4"> + <div class="card-header py-3"> + <div class="d-flex"> + <div class="mr-auto p-2"> + <h6 id="table-description" class="m-0 font-weight-bold text-primary">Tabel Daftar Approved Material</h6> + </div> + </div> + </div> + <div class="card-body"> + <div class="table-responsive"> + <table aria-describedby="table-description" class="table table-bordered" id="dataTable"> + <thead> + <tr> + <th scope="col">Title</th> + <th scope="col">Cover</th> + <th scope="col">Content</th> + <th scope="col">Kontributor</th> + <th scope="col">Status</th> + <th scope="col">Jumlah Like</th> + </tr> + </thead> + <tfoot> + <tr> + <th scope="col">Title</th> + <th scope="col">Cover</th> + <th scope="col">Content</th> + <th scope="col">Kontributor</th> + <th scope="col">Status</th> + <th scope="col">Jumlah Like</th> + </tr> + </tr> + </tfoot> + <tbody> + {% for materi in materi_list %} + <tr> + <td>{{ materi.title }}</td> + <td> + {% if materi.cover %} + <img id="posts-img" src="{{ materi.cover.url }}" alt="cover-picture" style="max-width: 400px;"/> + {% endif %} + </td> + <td> + <a href="/materi/{{materi.id}}/view">Lihat konten</a></td> + <td>{{ materi.uploader }}</td> + <td>{{ materi.status }}</td> + <td>{{ materi.like_count }}</td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + </div> +</div> +{% endblock %} diff --git a/administration/tests.py b/administration/tests.py index 5276b460e8f6b99e66cc46326dcbece0122823c0..fff6daef00396bad3176cbc8c260e3d7f6fd27b4 100644 --- a/administration/tests.py +++ b/administration/tests.py @@ -10,6 +10,8 @@ from app.models import Category, Materi from authentication.models import User from bs4 import BeautifulSoup +from datetime import datetime + EDIT_ENDPOINT = "/edit" ERROR_403_MESSAGE = 'Kamu harus login untuk mengakses halaman ini' @@ -1175,3 +1177,115 @@ class EditAdminStatusTests(TestCase): response = self.client.get(self.edit_url_dummy_superuser) self.assertEqual(response.status_code, 403) + + +class KelolaMateriViewTests(TestCase): + def setUp(self): + self.client = Client() + self.url = "/administration/kelola-materi/" + self.template_name = "kelola_materi.html" + self.view = views.KelolaMateriView + + self.user_credential = { + "email": "user@gov.id", + "password": id_generator() + } + self.admin_credential = { + "email": "admin@gov.id", + "password": id_generator() + } + + self.user = get_user_model().objects.create_user( + **self.user_credential, name="User", is_admin=False) + self.admin = get_user_model().objects.create_user( + **self.admin_credential, name="Admin", is_admin=True) + + self.contributor = User.objects.create( + email="kontributor@gov.id", + password="passwordtest", + name="kontributor", + is_contributor=True + ) + + self.cover = SimpleUploadedFile( + "Cherprang_Areekul40_nJM9dGt.jpg", b"Test file") + self.content = SimpleUploadedFile("Bahan_PA_RKK.pdf", b"Test file") + + def test_kelola_materi_view(self): + found = resolve(self.url) + self.assertEqual(found.func.__name__, self.view.as_view().__name__) + + def test_kelola_materi_template(self): + self.client.login(**self.admin_credential) + response = self.client.get(self.url) + self.assertTemplateUsed(response, self.template_name) + + def test_cannot_access_kelola_materi_as_unauthenticated_user(self): + response = self.client.get(self.url) + + self.assertEqual(response.status_code, 403) + + def test_cannot_access_kelola_materi_as_user_non_admin(self): + self.client.login(**self.user_credential) + response = self.client.get(self.url) + + self.assertEqual(response.status_code, 403) + + def test_can_access_kelola_materi_as_admin(self): + self.client.login(**self.admin_credential) + response = self.client.get(self.url) + + self.assertEqual(response.status_code, 200) + + def test_materi_list_context_return_empty_when_there_is_no_materi(self): + self.client.login(**self.admin_credential) + response = self.client.get(self.url) + + self.assertFalse( + response.context['materi_list'], + "Materi_list not empty when there is no materi" + ) + + def test_materi_list_context_return_correct_amount_of_materi_when_there_is_materi(self): + Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor, + publisher="Kelas SC", descriptions="Deskripsi Materi 1", + status="PENDING", cover=self.cover, content=self.content, + date_modified=datetime.now(), date_created=datetime.now()) + + Materi.objects.create(title="Materi 2", author="Agas", uploader=self.contributor, + publisher="Kelas SC", descriptions="Deskripsi Materi 2", + status="APPROVE", cover=self.cover, content=self.content, + date_modified=datetime.now(), date_created=datetime.now()) + + self.client.login(**self.admin_credential) + response = self.client.get(self.url) + + self.assertEqual(response.context['materi_list'].count(), 2) + + def test_materi_list_context_return_correct_materi_when_there_is_materi(self): + materi = Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor, + publisher="Kelas SC", descriptions="Deskripsi Materi 1", + status="PENDING", cover=self.cover, content=self.content, + date_modified=datetime.now(), date_created=datetime.now()) + + self.client.login(**self.admin_credential) + response = self.client.get(self.url) + + self.assertTrue( + response.context['materi_list'].filter(id=materi.id), + "Materi_list not including created materi" + ) + + def test_materi_list_context_not_return_materi_that_shouldnt_exists(self): + materi = Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor, + publisher="Kelas SC", descriptions="Deskripsi Materi 1", + status="PENDING", cover=self.cover, content=self.content, + date_modified=datetime.now(), date_created=datetime.now()) + invalid_id_materi = materi.id + 1 + + self.client.login(**self.admin_credential) + response = self.client.get(self.url) + self.assertFalse( + response.context['materi_list'].filter(id=invalid_id_materi), + "Materi_list including materi that should not be exists" + ) diff --git a/administration/urls.py b/administration/urls.py index c13a46c75274d3aa69e5f7b7ddc8d9effbcc247c..b6970aa97471877910b11ac5ad026cb5d2b14f50 100644 --- a/administration/urls.py +++ b/administration/urls.py @@ -1,6 +1,15 @@ from django.urls import path -from administration.views import VerificationView, DetailVerificationView, VerificationSettingView, CategorySettingView, KelolaKontributorView, ProfileContributorAdminView, ProfileAdminAdministrationView, KelolaAdminView, RegistrasiAdminView, EditVerificationView, delete_admin, delete_contributor, delete_verification, StatisticsView, StatisticApiView, EditCategoryView, EditAdminStatusView, delete_category, generatedummy +from administration.views import VerificationView, DetailVerificationView, \ + VerificationSettingView, CategorySettingView, \ + KelolaKontributorView, ProfileContributorAdminView, \ + ProfileAdminAdministrationView, KelolaAdminView, \ + RegistrasiAdminView, EditVerificationView, \ + delete_admin, delete_contributor, \ + delete_verification, StatisticsView, \ + StatisticApiView, EditCategoryView, \ + EditAdminStatusView, delete_category, \ + generatedummy, KelolaMateriView app_name = "administration" @@ -26,5 +35,6 @@ urlpatterns = [ EditAdminStatusView.as_view(), name="edit-admin-status"), path("hapus-admin/<int:pk>/", delete_admin), path("hapus-kontributor/<int:pk>/", delete_contributor), + path("kelola-materi/", KelolaMateriView.as_view()), path("generate-dummy", generatedummy), ] diff --git a/administration/views.py b/administration/views.py index 507425066c1600ba66d2f494bf18cc594e393e56..ee97ade6000afb612d6318e07f5a4ec815b91169 100644 --- a/administration/views.py +++ b/administration/views.py @@ -625,4 +625,22 @@ def generatedummy(request): # RUn management command management.call_command('generatedummy', materi) management.call_command('generatetraffic', visitor) - return JsonResponse({"success":True,"materi":materi,"visitor":visitor}) \ No newline at end of file + return JsonResponse({"success":True,"materi":materi,"visitor":visitor}) + +class KelolaMateriView(TemplateView): + template_name = "kelola_materi.html" + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_authenticated or not request.user.is_admin: + raise PermissionDenied(request) + + return super(KelolaMateriView, self).dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(KelolaMateriView, self).get_context_data(**kwargs) + context['materi_list'] = Materi.objects.all() + return context + + def get(self, request, *args, **kwargs): + context = self.get_context_data(**kwargs) + return self.render_to_response(context) diff --git a/app/models.py b/app/models.py index 4164b8443638d80ea89f091d476ef96ff0ce954d..39911d3e01ef2efdba9f0a661c5b0b6ce458ec9f 100644 --- a/app/models.py +++ b/app/models.py @@ -65,6 +65,10 @@ class Materi(models.Model): published_date = report.timestamp return published_date + @property + def like_count(self): + count = Like.objects.filter(materi=self).count() + return count class Comment(models.Model): username = models.CharField(max_length=100) diff --git a/app/tests.py b/app/tests.py index 2b828d3453e63b88a2711f7fac171876054a8423..0ad4321961bcf57956c4d5c2d46249b915126db0 100644 --- a/app/tests.py +++ b/app/tests.py @@ -35,13 +35,9 @@ from .views import (DaftarKatalog, DashboardKontributorView, DetailMateri, from app.forms import SuntingProfilForm from app.utils.fileManagementUtil import get_random_filename, remove_image_exifdata -from datetime import datetime - -import pandas as pd - - ERROR_403_MESSAGE = 'Kamu harus login untuk mengakses halaman ini' + class DaftarKatalogTest(TestCase): def test_daftar_katalog_url_exist(self): url = "/" @@ -144,8 +140,8 @@ class DetailMateriTest(TestCase): **self.anonymous_credential, name="Anonymous" ) self.cover = SimpleUploadedFile( - "Cherprang_Areekul40_nJM9dGt.jpg", b"Test file") - self.content = SimpleUploadedFile("Bahan_PA_RKK.pdf", b"Test file") + "ExampleCover921.jpg", b"Test file") + self.content = SimpleUploadedFile("ExampleFile921.pdf", b"Test file") Materi(title="Materi 1", author="Agas", uploader=self.contributor, publisher="Kelas SC", descriptions="Deskripsi Materi 1", @@ -2022,4 +2018,33 @@ class DownloadHistoryViewTest(TestCase): no_history_msg = "Anda belum mengunduh materi. Silahkan unduh materi yang anda butuhkan" response = self.client.get(self.history_url) resp_html = response.content.decode('utf8') - self.assertIn(no_history_msg, resp_html) \ No newline at end of file + self.assertIn(no_history_msg, resp_html) + + +class MateriModelTest(TestCase): + def setUp(self): + self.contributor = User.objects.create( + email="kontributor@gov.id", + password="passwordtest", + name="kontributor", + is_contributor=True + ) + + self.cover = SimpleUploadedFile( + "ExampleCover221.jpg", b"Test file") + self.content = SimpleUploadedFile("ExampleFile221.pdf", b"Test file") + + self.materi = Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor, + publisher="Kelas SC", descriptions="Deskripsi Materi 1", + status="APPROVE", cover=self.cover, content=self.content, + date_modified=datetime.now(), date_created=datetime.now()) + + def test_like_count_return_zero_when_there_is_no_like(self): + self.assertEqual(0, self.materi.like_count) + + def test_like_count_return_right_value_when_there_is_like(self): + Like.objects.create(timestamp=datetime.now(), materi=self.materi, session_id="dummysessionid1") + self.assertEqual(1, self.materi.like_count) + + Like.objects.create(timestamp=datetime.now(), materi=self.materi, session_id="dummysessionid2") + self.assertEqual(2, self.materi.like_count)