Fakultas Ilmu Komputer UI

Commit cc9557eb authored by Yusuf T Ardho's avatar Yusuf T Ardho
Browse files

[#104] Material: Report Abuse (Admin View)

parent e793c4da
# Generated by Django 3.1 on 2020-10-09 11:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('administration', '0007_auto_20200929_1218'),
]
operations = [
migrations.AlterField(
model_name='verificationreport',
name='status',
field=models.CharField(choices=[('PENDING', 'Diproses'), ('APPROVE', 'Diterima'), ('DISAPPROVE', 'Ditolak'), ('REVISION', 'Perbaikan'), ('BLOCKED', 'Diblokir')], default='PENDING', max_length=30),
),
]
......@@ -21,6 +21,11 @@
<span>Statistik Materi</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/administration/laporan-materi/">
<span>Laporan Materi</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider my-0">
......
{% extends 'administration/base_administrasi2.html' %}
{% load static %}
{% block title %}
<title>Laporan Materi | Digipus</title>
{% endblock %}
{% block content %}
<!-- Page Heading -->
<h1 class="h3 mb-2 text-gray-800">Laporan Materi</h1>
<p class="mb-4">Tekan blokir materi untuk memblokir materi.<br>Klik lihat laporan untuk melihat laporan dari pelapor.</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 class="m-0 font-weight-bold text-primary">Materi yang Dilaporkan</h6>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTable" width="100%" cellspacing="0">
<thead>
<tr>
<th scope="col">Judul</th>
<th scope="col">Jumlah Laporan</th>
<th scope="col">Pilihan</th>
</tr>
</thead>
<tfoot>
<tr>
<th scope="col">Judul</th>
<th scope="col">Jumlah Laporan</th>
<th scope="col">Pilihan</th>
</tr>
</tr>
</tfoot>
<tbody>
{% for materi in materi_dilaporkan %}
<tr>
<td>{{ materi.title }}</td>
<td>{{ materi.jumlah_laporan }}</td>
<td class="verif-buttons">
<a href="{% url 'administration:laporan-materi-detail' materi.id %}" class="accept-button button-decoration">Lihat Laporan</a>
<button type="button" class="reject-button button-decoration" data-toggle="modal" data-target="#confirmModal{{ materi.id }}">Blokir</button>
<div class="modal fade" id="confirmModal{{ materi.id }}" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Konfirmasi Pemblokiran Materi</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>Anda akan memblokir materi
<br><br><span style="text-transform: lowercase; font-weight: 900;">{{ materi.title }}</span><br>
email kontributor: {{ materi.uploader.email }}</p>
</div>
<div class="modal-footer">
<a href="{% url 'administration:blok-materi' materi.id %}" id="btn-hapus-{{ materi.id }}" type="button" class="btn btn-secondary">Blokir</a>
<button type="button" class="btn btn-danger" data-dismiss="modal">Batal</button>
</div>
</div>
</div>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary" id="titleTabelPending">Materi yang Diblokir</h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTablePending" aria-describedby="titleTabelPending">
{% if not materi_diblokir %}
Tidak ada materi yang diblokir
{% else %}
<thead>
<tr>
<th scope="col">Judul</th>
<th scope="col">Kontributor</th>
</tr>
</thead>
<tfoot>
<tr>
<th scope="col">Judul</th>
<th scope="col">Kontributor</th>
</tr>
</tfoot>
<tbody>
{% for materi in materi_diblokir %}
<tr>
<td>{{ materi.title }}</td>
<td><a href="{% url 'katalog-per-kontributor' materi.uploader.email %}">
{{ materi.uploader.name }}
</a></td>
</tr>
{% endfor %}
</tbody>
{% endif %}
</table>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
{% extends 'administration/base_administrasi2.html' %}
{% load static %}
{% block title %}
<title>Laporan Materi | Digipus</title>
{% endblock %}
{% block content %}
<!-- Page Heading -->
<h1 class="h3 mb-2 text-gray-800">Laporan Materi</h1>
<p class="mb-4">Klik tolak untuk menolak laporan.</ehp>
<!-- DataTales Example -->
<div class="card shadow mb-4">
<div class="card-header py-3">
<h6 class="m-0 font-weight-bold text-primary" id="titleTabelPending">
<a href="{% url 'detail-materi' materi.id %}">{{ materi.title }}</a></h6>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered" id="dataTablePending" aria-describedby="titleTabelPending">
{% if not laporan_materi %}
Tidak ada laporan untuk materi {{ materi.title }}
{% else %}
<thead>
<tr>
<th scope="col">Pelapor</th>
<th scope="col">Alasan Melapor</th>
<th scope="col">Pilihan</th>
</tr>
</thead>
<tfoot>
<tr>
<th scope="col">Pelapor</th>
<th scope="col">Alasan Melaporr</th>
<th scope="col">Pilihan</th>
</tr>
</tfoot>
<tbody>
{% for laporan in laporan_materi %}
<tr>
<td><a href="{% url 'katalog-per-kontributor' laporan.user.email %}">{{ laporan.user.name }}</a></td>
<td>{{ laporan.laporan }}</td>
<td class="verif-buttons">
<a href="{% url 'administration:tolak-laporan' laporan.id %}" class="reject-button button-decoration">Tolak</a>
</td>
</tr>
{% endfor %}
</tbody>
{% endif %}
</table>
</div>
</div>
</div>
{% endblock %}
\ No newline at end of file
......@@ -55,6 +55,11 @@
<span>Statistik Materi</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/administration/laporan-materi/">
<span>Laporan Materi</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider my-0">
......
......@@ -64,6 +64,11 @@
<span>Statistik Materi</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="/administration/laporan-materi/">
<span>Laporan Materi</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider my-0">
......
......@@ -69,6 +69,11 @@
>
</li>
<li class="nav-item">
<a class="nav-link" href="/administration/laporan-materi/">
<span>Laporan Materi</span></a>
</li>
<!-- Divider -->
<hr class="sidebar-divider my-0" />
......
......@@ -6,7 +6,7 @@ from django.urls import resolve
from administration import models, views
from administration.utils import id_generator
from administration.forms import EditAdminStatusForm
from app.models import Category, Materi
from app.models import Category, Materi, LaporanMateri
from authentication.models import User
from bs4 import BeautifulSoup
......@@ -1289,3 +1289,291 @@ class KelolaMateriViewTests(TestCase):
response.context['materi_list'].filter(id=invalid_id_materi),
"Materi_list including materi that should not be exists"
)
class LaporanMateriTest(TestCase):
def setUp(self):
self.client = Client()
self.admin_credential = {
"email": "admin@gov.id",
"password": id_generator()
}
self.contributor_credential = {
"email": "kontributor@gov.id",
"password": id_generator()
}
self.admin = get_user_model().objects.create_user(
**self.admin_credential, name="Admin", is_admin=True)
self.contributor = get_user_model().objects.create_user(
**self.contributor_credential, name="Kontributor", is_contributor=True
)
self.cover = SimpleUploadedFile("cover.jpg", b"Test file")
self.content = SimpleUploadedFile("content.txt", b"Test file")
self.materi = Materi.objects.create(
title="Ayat-ayat cinta", author="Axel", uploader=self.contributor,
publisher="X Prod", descriptions="Kisah kasih cinta",
status="APPROVE", cover=self.cover, content=self.content
)
self.materi2 = Materi.objects.create(
title="Cinta ayat-ayat", author="Lexa", uploader=self.contributor,
publisher="Y Prod", descriptions="Cinta kasih kisah",
status="APPROVE", cover=self.cover, content=self.content
)
self.laporan = LaporanMateri.objects.create(
laporan="materi ini kopas orang lain", user_id=self.contributor.id,
materi_id=self.materi.id
)
self.laporan2 = LaporanMateri.objects.create(
laporan="materi ini kopas orang lain", user_id=self.contributor.id,
materi_id=self.materi2.id
)
self.url = "/administration/laporan-materi/"
def test_admin_can_access_laporanmateri_page(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url)
self.assertEqual(response.status_code, 200)
self.client.logout()
def test_contributor_cant_access_laporanmateri_page(self):
self.client.login(**self.contributor_credential)
response = self.client.get(self.url)
self.assertEqual(response.status_code, 403)
self.client.logout()
def test_anonymous_cant_access_laporanmateri_page(self):
response = self.client.get(self.url)
self.assertEqual(response.status_code, 403)
def test_reported_materi_exist(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url)
bs = BeautifulSoup(response.rendered_content, features="html.parser")
el = str(bs.findAll("td"))
self.assertIn(self.materi.title, el)
self.assertIn(self.materi2.title, el)
self.client.logout()
class LaporanMateriDetailTest(TestCase):
def setUp(self):
self.client = Client()
self.admin_credential = {
"email": "admin@gov.id",
"password": id_generator()
}
self.contributor_credential = {
"email": "kontributor@gov.id",
"password": id_generator()
}
self.admin = get_user_model().objects.create_user(
**self.admin_credential, name="Admin", is_admin=True)
self.contributor = get_user_model().objects.create_user(
**self.contributor_credential, name="Kontributor", is_contributor=True
)
self.cover = SimpleUploadedFile("cover.jpg", b"Test file")
self.content = SimpleUploadedFile("content.txt", b"Test file")
self.materi = Materi.objects.create(
title="Ayat-ayat cinta", author="Axel", uploader=self.contributor,
publisher="X Prod", descriptions="Kisah kasih cinta",
status="APPROVE", cover=self.cover, content=self.content
)
self.materi2 = Materi.objects.create(
title="Cinta ayat-ayat", author="Lexa", uploader=self.contributor,
publisher="Y Prod", descriptions="Cinta kasih kisah",
status="APPROVE", cover=self.cover, content=self.content
)
self.laporan = LaporanMateri.objects.create(
laporan="materi ini kopas orang lain", user_id=self.contributor.id,
materi_id=self.materi.id
)
self.laporan2 = LaporanMateri.objects.create(
laporan="materi ini kopas orang lain", user_id=self.contributor.id,
materi_id=self.materi.id
)
self.url = "/administration/laporan-materi/"
def test_admin_can_access_laporanmateridetail_page(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url + str(self.laporan.materi_id) + '/')
self.assertEqual(response.status_code, 200)
self.client.logout()
def test_contributor_cant_access_laporanmateridetail_page(self):
self.client.login(**self.contributor_credential)
response = self.client.get(self.url + str(self.laporan.materi_id) + '/')
self.assertEqual(response.status_code, 403)
self.client.logout()
def test_anonymous_cant_access_laporanmateridetail_page(self):
response = self.client.get(self.url + str(self.laporan.materi_id) + '/')
self.assertEqual(response.status_code, 403)
def test_cant_access_unknown_laporanmaterialdetail_page(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url + '100/')
self.assertEqual(response.status_code, 404)
self.client.logout()
def test_reported_report_exist(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url + str(self.laporan.materi_id) + '/')
bs = BeautifulSoup(response.rendered_content, features="html.parser")
el = str(bs.findAll("td"))
self.assertIn(self.laporan.user.name, el)
self.assertIn(self.laporan.laporan, el)
self.assertIn(self.laporan2.user.name, el)
self.assertIn(self.laporan2.laporan, el)
self.client.logout()
class BlockMateriTest(TestCase):
def setUp(self):
self.client = Client()
self.admin_credential = {
"email": "admin@gov.id",
"password": id_generator()
}
self.contributor_credential = {
"email": "kontributor@gov.id",
"password": id_generator()
}
self.admin = get_user_model().objects.create_user(
**self.admin_credential, name="Admin", is_admin=True
)
self.contributor = get_user_model().objects.create_user(
**self.contributor_credential, name="Kontributor", is_contributor=True
)
self.cover = SimpleUploadedFile("cover.jpg", b"Test file")
self.content = SimpleUploadedFile("content.txt", b"Test file")
self.materi = Materi.objects.create(
title="Ayat-ayat cinta", author="Axel", uploader=self.contributor,
publisher="X Prod", descriptions="Kisah kasih cinta",
status="APPROVE", cover=self.cover, content=self.content
)
self.materi2 = Materi.objects.create(
title="Cinta ayat-ayat", author="Lexa", uploader=self.contributor,
publisher="Y Prod", descriptions="Cinta kasih kisah",
status="APPROVE", cover=self.cover, content=self.content
)
self.materi3 = Materi.objects.create(
title="Ayat cinta ayat", author="ealx", uploader=self.contributor,
publisher="Z Prod", descriptions="Kisah cinta kasih",
status="PENDING", cover=self.cover, content=self.content
)
self.laporan = LaporanMateri.objects.create(
laporan="materi ini kopas orang lain", user_id=self.contributor.id,
materi_id=self.materi.id
)
self.url = "/administration/blok-materi/"
def test_admin_can_block_materi(self):
self.client.login(**self.admin_credential)
self.assertEqual(self.materi.status, "APPROVE")
response = self.client.get(self.url + str(self.materi.id) +'/')
self.assertEqual(response.status_code, 302)
self.materi.refresh_from_db()
self.assertEqual(self.materi.status, "BLOCKED")
self.client.logout()
def test_contributor_cant_block_materi(self):
self.client.login(**self.contributor_credential)
self.assertEqual(self.materi.status, "APPROVE")
response = self.client.get(self.url + str(self.materi.id) +'/')
self.assertEqual(response.status_code, 403)
self.materi.refresh_from_db()
self.assertEqual(self.materi.status, "APPROVE")
self.client.logout()
def test_anonymous_cant_block_materi(self):
self.assertEqual(self.materi.status, "APPROVE")
response = self.client.get(self.url + str(self.materi.id) +'/')
self.assertEqual(response.status_code, 403)
self.materi.refresh_from_db()
self.assertEqual(self.materi.status, "APPROVE")
def test_cant_block_unreported_materi(self):
self.client.login(**self.admin_credential)
self.assertEqual(self.materi2.status, "APPROVE")
response = self.client.get(self.url + str(self.materi2.id) +'/')
self.assertEqual(response.status_code, 302)
self.materi2.refresh_from_db()
self.assertEqual(self.materi2.status, "APPROVE")
self.client.logout()
def test_cant_block_non_approve_status_materi(self):
self.client.login(**self.admin_credential)
self.assertEqual(self.materi3.status, "PENDING")
response = self.client.get(self.url + str(self.materi3.id) +'/')
self.assertEqual(response.status_code, 302)
self.materi3.refresh_from_db()
self.assertEqual(self.materi3.status, "PENDING")
self.client.logout()
def test_cant_block_unknown_materi(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url + '100/')
self.assertEqual(response.status_code, 404)
self.client.logout()
class RejectReportTest(TestCase):
def setUp(self):
self.client = Client()
self.admin_credential = {
"email": "admin@gov.id",
"password": id_generator()
}
self.contributor_credential = {
"email": "kontributor@gov.id",
"password": id_generator()
}
self.admin = get_user_model().objects.create_user(
**self.admin_credential, name="Admin", is_admin=True
)
self.contributor = get_user_model().objects.create_user(
**self.contributor_credential, name="Kontributor", is_contributor=True
)
self.cover = SimpleUploadedFile("cover.jpg", b"Test file")
self.content = SimpleUploadedFile("content.txt", b"Test file")
self.materi = Materi.objects.create(
title="Ayat-ayat cinta", author="Axel", uploader=self.contributor,
publisher="X Prod", descriptions="Kisah kasih cinta",
status="APPROVE", cover=self.cover, content=self.content
)
self.laporan = LaporanMateri.objects.create(
laporan="materi ini kopas orang lain", user_id=self.contributor.id,
materi_id=self.materi.id
)
self.url = "/administration/tolak-laporan/"
def test_admin_can_reject_report(self):
self.client.login(**self.admin_credential)
self.assertEqual(self.laporan.is_rejected, False)
response = self.client.get(self.url + str(self.laporan.id) +'/')
self.assertEqual(response.status_code, 302)
self.laporan.refresh_from_db()
self.assertEqual(self.laporan.is_rejected, True)
self.client.logout()
def test_contributor_cant_reject_report(self):
self.client.login(**self.contributor_credential)
self.assertEqual(self.laporan.is_rejected, False)
response = self.client.get(self.url + str(self.laporan.id) +'/')
self.assertEqual(response.status_code, 403)
self.laporan.refresh_from_db()
self.assertEqual(self.laporan.is_rejected, False)
self.client.logout()
def test_anonymous_cant_reject_report(self):
self.assertEqual(self.laporan.is_rejected, False)
response = self.client.get(self.url + str(self.laporan.id) +'/')
self.assertEqual(response.status_code, 403)
self.laporan.refresh_from_db()
self.assertEqual(self.laporan.is_rejected, False)
def test_cant_reject_unknown_report(self):
self.client.login(**self.admin_credential)
response = self.client.get(self.url + '100/')
self.assertEqual(response.status_code, 404)
self.client.logout()
......@@ -9,7 +9,9 @@ from administration.views import VerificationView, DetailVerificationView, \
delete_verification, StatisticsView, \
StatisticApiView, EditCategoryView, \
EditAdminStatusView, delete_category, \
generatedummy, KelolaMateriView
generatedummy, KelolaMateriView, \
LaporanMateriView, LaporanMateriDetailView, \
tolak_laporan, blok_materi
app_name = "administration"
......@@ -36,5 +38,10 @@ urlpatterns = [
path("hapus-admin/<int:pk>/", delete_admin),
path("hapus-kontributor/<int:pk>/", delete_contributor),
path("kelola-materi/", KelolaMateriView.as_view()),
path("laporan-materi/", LaporanMateriView.as_view()),
path("laporan-materi/<int:pk>/",
LaporanMateriDetailView.as_view(), name="laporan-materi-detail"),
path("tolak-laporan/<int:pk>/", tolak_laporan, name="tolak-laporan"),
path("blok-materi/<int:pk>/", blok_materi, name="blok-materi"),
path("generate-dummy", generatedummy),
]
......@@ -3,6 +3,7 @@ from datetime import datetime, date
from django.core.exceptions import PermissionDenied
from django.contrib.auth.hashers import make_password
from django.db.models import Count
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.views.generic import TemplateView, View
......@@ -11,7 +12,7 @@ from django.utils import timezone, lorem_ipsum
from dateutil.relativedelta import relativedelta
from administration.models import VerificationReport, VerificationSetting, DeletionHistory
from administration.forms import CategoryForm, VerificationSettingForm, RegistrasiAdminForm, PeriodForm, EditAdminStatusForm
from app.models import Category, Materi, ViewStatistics, DownloadStatistics, Comment, Like, getRandomColor
from app.models import Category, Materi, ViewStatistics, DownloadStatistics, Comment, Like, getRandomColor, LaporanMateri
from app.views import permission_denied
from authentication.models import User
from datetime import datetime
......@@ -21,6 +22,7 @@ from administration.utils import generate_time_step
from django.core import management
ADMINISTRATION_MANAGEMENT = "/administration/kelola-admin/"