diff --git a/app/forms.py b/app/forms.py index 266720e86f912083e2c1335923114cc5c21c4bd3..7f22c130a7bd62a0d90ceb8e4fc88037f0f33eeb 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,18 +1,22 @@ from django import forms -from app.models import Materi, Category, RatingContributor +from app.models import Materi, Category, RatingContributor, GuestBook from authentication.models import User import datetime + def year_choices(): - return[(r,r) for r in range(2000, datetime.date.today().year+1)] + return[(r, r) for r in range(2000, datetime.date.today().year+1)] + class UploadMateriForm(forms.ModelForm): - - categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all(),widget=forms.CheckboxSelectMultiple(attrs={'style' : 'column-count:2'}),required=True) - release_year = forms.TypedChoiceField(coerce=int, choices=year_choices, initial=datetime.date.today().year) - yt_video_id = forms.CharField(label="Youtube Video Id", \ - help_text="This is not required.<br>\ + + categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all( + ), widget=forms.CheckboxSelectMultiple(attrs={'style': 'column-count:2'}), required=True) + release_year = forms.TypedChoiceField( + coerce=int, choices=year_choices, initial=datetime.date.today().year) + yt_video_id = forms.CharField(label="Youtube Video Id", + help_text="This is not required.<br>\ Please insert only Youtube link videos! Take a note for the video id!<br>\ Example : https://www.youtube.com/watch?v=DkJ-50GLi2I <br> has video id DkJ-50GLi2I", required=False) @@ -29,14 +33,13 @@ class UploadMateriForm(forms.ModelForm): field.widget.attrs["class"] = "form-control" field.widget.attrs["placeholder"] = field.initial field.initial = "" - self.fields['categories'].widget.attrs.update({'class' : "native"}) - + self.fields['categories'].widget.attrs.update({'class': "native"}) class SuntingProfilForm(forms.ModelForm): class Meta: model = User - fields = ["email","name","instansi", "nik", "alamat", "nomor_telpon", + fields = ["email", "name", "instansi", "nik", "alamat", "nomor_telpon", "profile_picture", "linkedin", "facebook", "twitter", "instagram", "biography", "is_subscribing_to_material_comments"] @@ -50,7 +53,6 @@ class SuntingProfilForm(forms.ModelForm): if any(self.errors): key = list(self.errors)[0] self.fields[key].widget.attrs["autofocus"] = "" - self.fields["email"].widget.attrs["readonly"] = True @@ -61,14 +63,43 @@ class RatingContributorForm(forms.ModelForm): fields = ['score', 'user', 'contributor'] SCORE_CHOICE = ( ('', 'Select score'), - ('1', '1'), # First one is the value of select option and second is the displayed value in option + # First one is the value of select option and second is the displayed value in option + ('1', '1'), ('2', '2'), ('3', '3'), ('4', '4'), ('5', '5'), ) widgets = { - 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control', 'id':'form-rating'},), + 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control', 'id': 'form-rating'},), 'user': forms.HiddenInput(), 'contributor': forms.HiddenInput() } + + +class GuestBookForm(forms.models.ModelForm): + class Meta: + model = GuestBook + fields = ['name', 'job', 'gender'] + gender_choices = ( + ('Male', 'Male'), + ('Female', 'Female') + ) + widgets = { + 'name': forms.fields.TextInput(attrs={ + 'placeholder': 'Input your name', + 'class': 'form-control input-lg' + }), + 'job': forms.fields.TextInput(attrs={ + 'placeholder': 'Input your job', + 'class': 'form-control input-lg' + }), + 'gender': forms.fields.Select(choices=gender_choices, attrs={ + 'class': 'form-control input-lg' + }) + } + error_messages = { + 'name': {'required': 'Name is required'}, + 'job': {'required': 'Job is required'}, + 'gender': {'required': 'Gender is required'} + } diff --git a/app/migrations/0029_guestbook.py b/app/migrations/0029_guestbook.py new file mode 100644 index 0000000000000000000000000000000000000000..57fc440f8a0ba208b54902b0259221c854158c99 --- /dev/null +++ b/app/migrations/0029_guestbook.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1 on 2020-10-31 18:19 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0028_adminnotification'), + ] + + operations = [ + migrations.CreateModel( + name='GuestBook', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.TextField(default='')), + ('job', models.TextField(default='')), + ('gender', models.CharField(default='Male', max_length=6)), + ], + ), + ] diff --git a/app/migrations/0029_merge_20201101_0217.py b/app/migrations/0030_merge_20201101_0621.py similarity index 66% rename from app/migrations/0029_merge_20201101_0217.py rename to app/migrations/0030_merge_20201101_0621.py index 69826d1afcfbd93ecf7643f8109e292879d785b4..e4e725f5d7b212a3eec1de8bb51575762eb79218 100644 --- a/app/migrations/0029_merge_20201101_0217.py +++ b/app/migrations/0030_merge_20201101_0621.py @@ -1,4 +1,4 @@ -# Generated by Django 3.1 on 2020-10-31 19:17 +# Generated by Django 3.1 on 2020-10-31 23:21 from django.db import migrations @@ -6,8 +6,8 @@ from django.db import migrations class Migration(migrations.Migration): dependencies = [ + ('app', '0029_guestbook'), ('app', '0028_notifikasikontributor'), - ('app', '0028_adminnotification'), ] operations = [ diff --git a/app/models.py b/app/models.py index 536b917fc5eee5fd234dceb3419ebaf549080d02..3386646a5856d39ed5eb4252cdb892f5c8057144 100644 --- a/app/models.py +++ b/app/models.py @@ -26,9 +26,11 @@ def get_random_color(): color = "%06x" % random.randint(0, 0xFFFFFF) return color + def current_year(): return datetime.date.today().year + class Category(models.Model): name = models.CharField(max_length=20) description = models.TextField(blank=False, default="") @@ -48,7 +50,7 @@ class MateriManager(models.Manager): if self.alive_only: return SoftDeletionQuerySet(self.model).filter(deleted_at=None) return SoftDeletionQuerySet(self.model) - + def search(self, search_text): search_vector = None for field, weight in Materi.SEARCH_INDEX: @@ -75,18 +77,20 @@ class SoftDeletionQuerySet(models.query.QuerySet): def delete(self): return super(SoftDeletionQuerySet, self).update(deleted_at=timezone.now()) + 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() @@ -96,8 +100,9 @@ class Materi(SoftDeleteModel): 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") - status = models.CharField(max_length=30, choices=VERIFICATION_STATUS, default=VERIFICATION_STATUS[0][0]) + 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) date_modified = models.DateTimeField(auto_now=True) @@ -117,7 +122,8 @@ class Materi(SoftDeleteModel): def save(self, *args, **kwargs): super().save(*args, **kwargs) - search_index = {field: weight for (field, weight) in Materi.SEARCH_INDEX} + search_index = {field: weight for ( + field, weight) in Materi.SEARCH_INDEX} if "update_fields" in kwargs: is_search_index_updated = bool( set(search_index.keys()) & set(kwargs["update_fields"]) @@ -127,9 +133,11 @@ class Materi(SoftDeleteModel): self._search_vector = None for field, weight in search_index.items(): if self._search_vector is None: - self._search_vector = search.SearchVector(field, weight=weight) + self._search_vector = search.SearchVector( + field, weight=weight) else: - self._search_vector += search.SearchVector(field, weight=weight) + self._search_vector += search.SearchVector( + field, weight=weight) self.save(update_fields=["_search_vector"]) @@ -154,7 +162,7 @@ class Materi(SoftDeleteModel): def like_count(self): count = Like.objects.filter(materi=self).count() return count - + @property def comment_count(self): count = Comment.objects.filter(materi=self).count() @@ -181,7 +189,7 @@ class Materi(SoftDeleteModel): @property def hot_score(self): view_score = math.log(max(self.view_count, 1), 10) - time_score = self.seconds_since_earliest_materi / 604800 # 1 week + time_score = self.seconds_since_earliest_materi / 604800 # 1 week return round(view_score + time_score, 7) @property @@ -197,7 +205,8 @@ class Comment(models.Model): profile = models.CharField(max_length=100, default=get_random_color) comment = models.CharField(max_length=240, default="comments") materi = models.ForeignKey(Materi, models.SET_NULL, null=True) - user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) + user = models.ForeignKey( + User, on_delete=models.SET_NULL, blank=True, null=True) timestamp = models.DateTimeField(default=timezone.now) def __str__(self): @@ -207,18 +216,20 @@ class Comment(models.Model): def like_count(self): count = LikeComment.objects.filter(comment=self).count() return count - + @property def dislike_count(self): count = DislikeComment.objects.filter(comment=self).count() return count + class Review(models.Model): username = models.CharField(max_length=100) profile = models.CharField(max_length=100, default=get_random_color) review = models.TextField(default="review") materi = models.ForeignKey(Materi, models.SET_NULL, null=True) - user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) + user = models.ForeignKey( + User, on_delete=models.SET_NULL, blank=True, null=True) timestamp = models.DateTimeField(default=timezone.now) def __str__(self): @@ -247,6 +258,7 @@ class ReqMaterial(models.Model): title = models.CharField(max_length=100) timestamp = models.DateTimeField(default=timezone.now) + class SubmitVisitor(models.Model): user_id = models.CharField(max_length=50) email = models.CharField(max_length=50) @@ -255,13 +267,16 @@ class SubmitVisitor(models.Model): class ViewStatistics(models.Model): - materi = models.ForeignKey(Materi, models.SET_NULL, null=True, related_name="baca") + materi = models.ForeignKey( + Materi, models.SET_NULL, null=True, related_name="baca") timestamp = models.DateTimeField(default=timezone.now) class DownloadStatistics(models.Model): - materi = models.ForeignKey(Materi, models.SET_NULL, null=True, related_name="unduh") - downloader = models.ForeignKey(User, models.SET_NULL, blank=True, null=True, related_name="riwayat_unduh") + materi = models.ForeignKey( + Materi, models.SET_NULL, null=True, related_name="unduh") + downloader = models.ForeignKey( + User, models.SET_NULL, blank=True, null=True, related_name="riwayat_unduh") timestamp = models.DateTimeField(default=timezone.now) @@ -302,27 +317,39 @@ class Rating(models.Model): class RatingContributor(models.Model): timestamp = models.DateTimeField(auto_now=True) - score = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) - contributor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='contributor') - user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user') + score = models.PositiveIntegerField( + validators=[MinValueValidator(1), MaxValueValidator(5)]) + contributor = models.ForeignKey( + User, on_delete=models.CASCADE, related_name='contributor') + user = models.ForeignKey( + User, on_delete=models.CASCADE, related_name='user') def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if 1 <= self.score <= 5: super().save(force_insert, force_update, using, update_fields) else: raise ValidationError("Rating score must be integer between 1-5") - + class Meta: unique_together = ["contributor", "user"] class LaporanMateri(models.Model): - materi = models.ForeignKey(Materi, on_delete=models.CASCADE, max_length=120) + materi = models.ForeignKey( + Materi, on_delete=models.CASCADE, max_length=120) user = models.ForeignKey(User, on_delete=models.CASCADE) - laporan = models.TextField(validators=[MinValueValidator(30), MaxValueValidator(120)], default="") + laporan = models.TextField( + validators=[MinValueValidator(30), MaxValueValidator(120)], default="") timestamp = models.DateTimeField(default=timezone.now) is_rejected = models.BooleanField(default=False) + +class GuestBook(models.Model): + name = models.TextField(default='') + job = models.TextField(default='') + gender = models.CharField(max_length=6, default="Male") + + class ReadLater(models.Model): materi = models.ForeignKey(Materi, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) @@ -331,13 +358,16 @@ 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) + 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/static/app/css/guest_book.css b/app/static/app/css/guest_book.css new file mode 100644 index 0000000000000000000000000000000000000000..681d4f1d307a052b538c5d576c5650f5362f0c09 --- /dev/null +++ b/app/static/app/css/guest_book.css @@ -0,0 +1,63 @@ + +.form-style-6{ + font: 95% Arial, Helvetica, sans-serif; + max-width: 500px; + margin: 25px auto; + padding: 16px; + background: #F7F7F7; + align-content: center; + justify-content: center; +} +.form-style-6 h1{ + background: #43D1AF; + padding: 20px 0; + font-size: 140%; + font-weight: 300; + text-align: center; + color: #fff; + margin: -16px -16px 16px -16px; +} +.form-style-6 input[type="text"], +.form-style-6 select +{ + -webkit-transition: all 0.30s ease-in-out; + -moz-transition: all 0.30s ease-in-out; + -ms-transition: all 0.30s ease-in-out; + -o-transition: all 0.30s ease-in-out; + outline: none; + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + width: 100%; + background: #fff; + margin-bottom: 4%; + border: 1px solid #ccc; + color: #555; + font: 95% Arial, Helvetica, sans-serif; +} +.form-style-6 input[type="text"]:focus, +.form-style-6 textarea:focus, +.form-style-6 select:focus +{ + box-shadow: 0 0 5px #43D1AF; + padding: 3%; + border: 1px solid #43D1AF; +} + +.form-style-6 button[type="submit"]{ + box-sizing: border-box; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + width: 100%; + padding: 3%; + background: #1da1f2; + border-bottom: 2px solid #1da1f2; + border-top-style: none; + border-right-style: none; + border-left-style: none; + color: #fff; +} +.form-style-6 input[type="submit"]:hover, +.form-style-6 input[type="button"]:hover{ + background: #2EBC99; +} \ No newline at end of file diff --git a/app/templates/guest_book.html b/app/templates/guest_book.html new file mode 100644 index 0000000000000000000000000000000000000000..b2d32fce5267d65a487a12d6b0bc9612cee1a30c --- /dev/null +++ b/app/templates/guest_book.html @@ -0,0 +1,31 @@ +{% extends 'base.html' %} +{% load static %} +{% block title %}Digipus Home{% endblock %} +{% block header %} + +<!DOCTYPE html> +<html lang="en"> + +<head> + <title>Digipus Home</title> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, inital-scale=1"> + + <link rel="stylesheet" type="text/css" href="{% static 'app/css/guest_book.css' %}"> + {% endblock header %} + +</head> + +<!-- Page Content --> +{% block content %} +<div class="form-group form-style-6" id="myForm"> + <form method="POST"> + <h3 style="text-align: center;">Buku Tamu Non Anggota</h3> + {% csrf_token %} + {{form}} + <button type="submit" class="btn btn-success">Submit</button> + </form> +</div> +{% endblock %} + +</html> \ No newline at end of file diff --git a/app/tests.py b/app/tests.py index 70a6ce3257865de95350ee668681e7d027fb8c2f..75c6aaa7774aad2c4b4149b933e763e2609cdd79 100644 --- a/app/tests.py +++ b/app/tests.py @@ -1,3 +1,11 @@ +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.chrome.options import Options +from selenium.common.exceptions import NoSuchElementException +from selenium import webdriver +from django.test import LiveServerTestCase +import requests +from statistics import mean import mock import pandas as pd import base64 @@ -37,7 +45,7 @@ from django.test import (Client, RequestFactory, TestCase, TransactionTestCase, from django.urls import resolve, reverse from django.utils import timezone -from app.forms import SuntingProfilForm, year_choices +from app.forms import SuntingProfilForm, year_choices, GuestBookForm from app.utils.fileManagementUtil import (get_random_filename, remove_image_exifdata) from app.utils.PasswordValidator import PasswordPolicyValidator @@ -45,7 +53,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, NotifikasiKontributor) + ReadLater, ReqMaterial, Review, ViewStatistics, GuestBook, AdminNotification, NotifikasiKontributor) from .services import DetailMateriService from .views import (DaftarKatalog, DashboardKontributorView, DetailMateri, KatalogPerKontributorView, MateriFavorite, @@ -57,16 +65,6 @@ from .views import (DaftarKatalog, DashboardKontributorView, DetailMateri, ERROR_403_MESSAGE = "Kamu harus login untuk mengakses halaman ini" -from statistics import mean - -import requests -from django.test import LiveServerTestCase -from selenium import webdriver -from selenium.common.exceptions import NoSuchElementException -from selenium.webdriver.chrome.options import Options -from selenium.webdriver.common.keys import Keys -from webdriver_manager.chrome import ChromeDriverManager - class DaftarKatalogTest(TestCase): def test_daftar_katalog_url_exist(self): @@ -98,14 +96,14 @@ class DaftarKatalogSortingByJumlahUnduhTest(TestCase): self.client = Client() self.contributor_credential = { - "email": "kontributor@gov.id", - "password": "passwordtest" - } + "email": "kontributor@gov.id", + "password": "passwordtest" + } self.contributor_credential_2 = { - "email": "kontributor2@gov.id", - "password": "passwordtest" - } + "email": "kontributor2@gov.id", + "password": "passwordtest" + } self.contributor = get_user_model().objects.create_user( **self.contributor_credential, name="Kontributor 1", is_contributor=True) @@ -133,6 +131,7 @@ class DaftarKatalogSortingByJumlahUnduhTest(TestCase): response = self.client.get("/?sort=jumlah_unduh") self.assertRegex(str(response.content), rf'.*Materi 2.*Materi 1.*') + class DaftarKatalogSortingByJumlahTampilanTest(TestCase): def setUp(self): self.contributor_credential = { @@ -176,7 +175,7 @@ class DaftarKatalogSortingByTerhangatTest(TestCase): def get_displayed_materi_in_number(self): response = self.client.get("/?sort=terhangat") - lst = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", + lst = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", response.content.decode())] return lst @@ -188,7 +187,7 @@ class DaftarKatalogSortingByTerhangatTest(TestCase): self.contributor = get_user_model().objects.create_user( name="Kontributor", is_contributor=True, - **self.contributor_credential, + **self.contributor_credential, ) self.client = Client() content = b"Test file" @@ -272,7 +271,7 @@ class DaftarKatalogSortingByTerhangatTest(TestCase): self.generate_view_materi(materi2, 1) self.assertAlmostEqual(materi1.hot_score, materi2.hot_score) - + def test_page_has_option_sort_by_hottest(self): response = self.client.get("/") self.assertIn("terhangat", response.content.decode()) @@ -329,9 +328,9 @@ class DaftarKatalogSortingByJumlahKomentarTest(TestCase): self.client = Client() self.contributor_credential = { - "email": "kontributor@gov.id", - "password": "passwordtest" - } + "email": "kontributor@gov.id", + "password": "passwordtest" + } self.contributor_credential_2 = { "email": "kontributor2@gov.id", @@ -359,25 +358,27 @@ class DaftarKatalogSortingByJumlahKomentarTest(TestCase): url = f"/materi/{self.last_uploaded_material.id}/" self.client.login(**self.contributor_credential_2) - self.client.post(url, {"comment": "This is new comment by Kontributor 2"}) + self.client.post( + url, {"comment": "This is new comment by Kontributor 2"}) def test_sorting_by_jumlah_komentar(self): response = self.client.get("/?sort=jumlah_komentar") self.assertRegex(str(response.content), rf'.*Materi 2.*Materi 1.*') + class DaftarKatalogPerKontributorTest(TestCase): def setUp(self): self.client = Client() self.contributor_credential = { - "email": "kontributor@gov.id", - "password": "passwordtest" - } + "email": "kontributor@gov.id", + "password": "passwordtest" + } self.contributor_credential_2 = { - "email": "kontributor2@gov.id", - "password": "passwordtest" - } + "email": "kontributor2@gov.id", + "password": "passwordtest" + } self.contributor = get_user_model().objects.create_user( **self.contributor_credential, name="Kontributor 1", is_contributor=True) @@ -410,7 +411,8 @@ class DaftarKatalogPerKontributorTest(TestCase): def test_katalog_per_kontributor_using_katalog_per_kontributor_func(self): found = resolve(self.url) - self.assertEqual(found.func.__name__, KatalogPerKontributorView.as_view().__name__) + self.assertEqual(found.func.__name__, + KatalogPerKontributorView.as_view().__name__) # def test_katalog_per_kontributor_show_daftar_materi_kontributor(self): # response = self.client.get(self.url) @@ -425,20 +427,22 @@ class DaftarKatalogPerKontributorTest(TestCase): jumlah = response.context_data["materi_list"] self.assertEqual(len(list_materi), len(jumlah)) + class DetailMateriTest(TestCase): def _get_materi_info_html(self, info_name, info_value): info_html = '<div class="info" id="1"><dl class="col col-4">' info_html += f'<dt class="info-name">{info_name}</dt>' + '</dl><dd>' - info_html += f'<p class="info-content">{info_value}</p>' + '</dd></div>' + info_html += f'<p class="info-content">{info_value}</p>' + \ + '</dd></div>' return info_html def check_materi_info_in_html(self, info_name, info_value, html_content): expected_content = self._get_materi_info_html(info_name, info_value) - self.assertIn(expected_content, re.sub(">\s*<","><", html_content)) + self.assertIn(expected_content, re.sub(">\s*<", "><", html_content)) def check_materi_info_not_in_html(self, info_name, info_value, html_content): expected_content = self._get_materi_info_html(info_name, info_value) - self.assertNotIn(expected_content, re.sub(">\s*<","><", html_content)) + self.assertNotIn(expected_content, re.sub(">\s*<", "><", html_content)) def setUp(self): self.client = Client() @@ -465,14 +469,14 @@ class DetailMateriTest(TestCase): "ExampleCover921.jpg", b"Test file") self.content = SimpleUploadedFile("ExampleFile921.pdf", b"Test file") - self.materi1 = 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) - self.materi2 = Materi.objects.create(title="Materi 2", author="Agad", - uploader=self.contributor, publisher="Kelas SM", - descriptions="Deskripsi Materi 2", status="APPROVE", - cover=self.cover, content=self.content) + self.materi1 = 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) + self.materi2 = Materi.objects.create(title="Materi 2", author="Agad", + uploader=self.contributor, publisher="Kelas SM", + descriptions="Deskripsi Materi 2", status="APPROVE", + cover=self.cover, content=self.content) self.url = "/materi/" + str(self.materi1.id) + "/" self.download_url1 = self.url + "unduh" self.url2 = "/materi/" + str(self.materi2.id) + "/" @@ -482,14 +486,15 @@ class DetailMateriTest(TestCase): self.lcount_info_name = "Jumlah Like" self.materi_with_published_date = 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=timezone.now(), date_created=timezone.now()) - self.materi_with_published_date_url = "/materi/" + str(self.materi_with_published_date.id) + "/" - VerificationReport.objects.create(report='{"feedback": "Something", "kriteria": [{"title": "Kriteria 1", "status": true},' + \ - ' {"title": "Kriteria 2", "status": true}, {"title": "Kriteria 3", "status": true}]}', \ - timestamp="2020-10-09 06:21:33", status="Diterima", materi= self.materi_with_published_date, \ - user=self.materi_with_published_date.uploader) + publisher="Kelas SC", descriptions="Deskripsi Materi 1", + status="APPROVE", cover=self.cover, content=self.content, + date_modified=timezone.now(), date_created=timezone.now()) + self.materi_with_published_date_url = "/materi/" + \ + str(self.materi_with_published_date.id) + "/" + VerificationReport.objects.create(report='{"feedback": "Something", "kriteria": [{"title": "Kriteria 1", "status": true},' + + ' {"title": "Kriteria 2", "status": true}, {"title": "Kriteria 3", "status": true}]}', + timestamp="2020-10-09 06:21:33", status="Diterima", materi=self.materi_with_published_date, + user=self.materi_with_published_date.uploader) def test_detail_materi_url_exist(self): response = Client().get(self.url) @@ -580,14 +585,17 @@ class DetailMateriTest(TestCase): self.client.get("/logout/") self.client.login(**self.anonymous_credential) - self.client.post(url_materi, {"comment": "This is new comment by Anonymous"}) - comment = Comment.objects.get(comment="This is new comment by Anonymous").id + self.client.post( + url_materi, {"comment": "This is new comment by Anonymous"}) + comment = Comment.objects.get( + comment="This is new comment by Anonymous").id response = self.client.get(url_materi) session_id = response.context["session_id"] payload = {"comment": comment, "session_id": session_id} self.client.post("/comment/dislike/", payload) - num_of_comment_dislikes = DislikeComment.objects.filter(comment=comment).count() + num_of_comment_dislikes = DislikeComment.objects.filter( + comment=comment).count() self.assertEqual(num_of_comment_dislikes, 0) def test_comment_liked_by_anonymous(self): @@ -595,14 +603,17 @@ class DetailMateriTest(TestCase): self.client.get("/logout/") self.client.login(**self.anonymous_credential) - self.client.post(url_materi, {"comment": "This is new comment by Anonymous"}) - comment = Comment.objects.get(comment="This is new comment by Anonymous").id + self.client.post( + url_materi, {"comment": "This is new comment by Anonymous"}) + comment = Comment.objects.get( + comment="This is new comment by Anonymous").id response = self.client.get(url_materi) session_id = response.context["session_id"] payload = {"comment": comment, "session_id": session_id} self.client.post("/comment/like/", payload) - num_of_comment_likes = LikeComment.objects.filter(comment=comment).count() + num_of_comment_likes = LikeComment.objects.filter( + comment=comment).count() self.assertEqual(num_of_comment_likes, 0) def test_comment_undisliked_by_anonymous(self): @@ -610,16 +621,19 @@ class DetailMateriTest(TestCase): self.client.get("/logout/") self.client.login(**self.anonymous_credential) - self.client.post(url_materi, {"comment": "This is new comment by Anonymous"}) - comment = Comment.objects.get(comment="This is new comment by Anonymous") + self.client.post( + url_materi, {"comment": "This is new comment by Anonymous"}) + comment = Comment.objects.get( + comment="This is new comment by Anonymous") response = self.client.get(url_materi) session_id = response.context["session_id"] - + payload = {"comment": comment, "session_id": session_id} self.client.post("/comment/dislike/", payload) - + self.client.post("/comment/dislike/", payload) - num_of_comment_dislikes = DislikeComment.objects.filter(comment=comment, session_id=session_id).count() + num_of_comment_dislikes = DislikeComment.objects.filter( + comment=comment, session_id=session_id).count() self.assertEqual(num_of_comment_dislikes, 0) def test_comment_unliked_by_anonymous(self): @@ -627,16 +641,19 @@ class DetailMateriTest(TestCase): self.client.get("/logout/") self.client.login(**self.anonymous_credential) - self.client.post(url_materi, {"comment": "This is new comment by Anonymous"}) - comment = Comment.objects.get(comment="This is new comment by Anonymous") + self.client.post( + url_materi, {"comment": "This is new comment by Anonymous"}) + comment = Comment.objects.get( + comment="This is new comment by Anonymous") response = self.client.get(url_materi) session_id = response.context["session_id"] - + payload = {"comment": comment, "session_id": session_id} self.client.post("/comment/like/", payload) - + self.client.post("/comment/like/", payload) - num_of_comment_likes = LikeComment.objects.filter(comment=comment, session_id=session_id).count() + num_of_comment_likes = LikeComment.objects.filter( + comment=comment, session_id=session_id).count() self.assertEqual(num_of_comment_likes, 0) def test_comment_new_does_not_have_dislike(self): @@ -646,10 +663,13 @@ class DetailMateriTest(TestCase): response = self.client.get(url_materi) session_id = response.context["session_id"] - self.client.post(url_materi, {"comment": "This is new comment by Anonymous"}) + self.client.post( + url_materi, {"comment": "This is new comment by Anonymous"}) - comment = Comment.objects.get(comment="This is new comment by Anonymous") - comment_dislike_counter = DislikeComment.objects.filter(comment=comment, session_id=session_id).count() + comment = Comment.objects.get( + comment="This is new comment by Anonymous") + comment_dislike_counter = DislikeComment.objects.filter( + comment=comment, session_id=session_id).count() self.assertEqual(comment_dislike_counter, 0) def test_comment_new_does_not_have_like(self): @@ -659,10 +679,13 @@ class DetailMateriTest(TestCase): response = self.client.get(url_materi) session_id = response.context["session_id"] - self.client.post(url_materi, {"comment": "This is new comment by Anonymous"}) + self.client.post( + url_materi, {"comment": "This is new comment by Anonymous"}) - comment = Comment.objects.get(comment="This is new comment by Anonymous") - comment_like_counter = LikeComment.objects.filter(comment=comment, session_id=session_id).count() + comment = Comment.objects.get( + comment="This is new comment by Anonymous") + comment_like_counter = LikeComment.objects.filter( + comment=comment, session_id=session_id).count() self.assertEqual(comment_like_counter, 0) def test_comment_sends_email_to_contributor_that_subscribes(self): @@ -674,12 +697,13 @@ class DetailMateriTest(TestCase): is_subscribing_to_material_comments=True ) - material = Materi.objects.create(title="Materi-subscribed", author="Tester", - uploader=contributor_subscribed, publisher="Kelas PMPL", - descriptions="Deskripsi Materi subscribed", status="APPROVE", - cover=self.cover, content=self.content) + material = Materi.objects.create(title="Materi-subscribed", author="Tester", + uploader=contributor_subscribed, publisher="Kelas PMPL", + descriptions="Deskripsi Materi subscribed", status="APPROVE", + cover=self.cover, content=self.content) url = "/materi/" + str(material.id) + "/" - self.client.login(**self.contributor_credential) # comment with other user + # comment with other user + self.client.login(**self.contributor_credential) prev_outbox_count = len(mail.outbox) @@ -701,12 +725,13 @@ class DetailMateriTest(TestCase): is_subscribing_to_material_comments=False ) - material = Materi.objects.create(title="Materi-not-subscribed", author="Tester", - uploader=contributor_not_subscribed, publisher="Kelas PMPL", - descriptions="Deskripsi Materi non-subscribed", status="APPROVE", - cover=self.cover, content=self.content) + material = Materi.objects.create(title="Materi-not-subscribed", author="Tester", + uploader=contributor_not_subscribed, publisher="Kelas PMPL", + descriptions="Deskripsi Materi non-subscribed", status="APPROVE", + cover=self.cover, content=self.content) url = "/materi/" + str(material.id) + "/" - self.client.login(**self.contributor_credential) # comment with other user + # comment with other user + self.client.login(**self.contributor_credential) prev_outbox_count = len(mail.outbox) @@ -731,12 +756,13 @@ class DetailMateriTest(TestCase): is_subscribing_to_material_comments=True ) - material = Materi.objects.create(title="Materi-subscribed", author="Tester", - uploader=contributor_subscribed, publisher="Kelas PMPL", - descriptions="Deskripsi Materi subscribed", status="APPROVE", - cover=self.cover, content=self.content) + material = Materi.objects.create(title="Materi-subscribed", author="Tester", + uploader=contributor_subscribed, publisher="Kelas PMPL", + descriptions="Deskripsi Materi subscribed", status="APPROVE", + cover=self.cover, content=self.content) url = "/materi/" + str(material.id) + "/" - self.client.login(**contributor_subscribed_credentials) # comment with the same user + # comment with the same user + self.client.login(**contributor_subscribed_credentials) prev_outbox_count = len(mail.outbox) @@ -771,7 +797,8 @@ class DetailMateriTest(TestCase): def test_detail_materi_not_contains_form_comment(self): response = self.client.get(self.url) self.assertNotContains(response, "Beri komentar...") - self.assertContains(response, "Login terlebih dahulu untuk berkomentar") + self.assertContains( + response, "Login terlebih dahulu untuk berkomentar") def create_and_delete_comment(self, is_admin=False, is_contributor=False): url = self.url @@ -790,7 +817,8 @@ class DetailMateriTest(TestCase): def test_delete_comments_by_admin(self): self.create_and_delete_comment(is_admin=True) - count = Comment.objects.all().filter(comment="This is new comment by Anonymous").count() + count = Comment.objects.all().filter( + comment="This is new comment by Anonymous").count() self.assertEqual(count, 0) def test_delete_comments_by_contributor(self): @@ -799,7 +827,8 @@ class DetailMateriTest(TestCase): self.assertRaises(PermissionDenied) self.assertEqual(response.status_code, 403) - count = Comment.objects.all().filter(comment="This is new comment by Anonymous").count() + count = Comment.objects.all().filter( + comment="This is new comment by Anonymous").count() self.assertEqual(count, 1) def test_delete_comments_by_anonymous(self): @@ -808,10 +837,10 @@ class DetailMateriTest(TestCase): self.assertRaises(PermissionDenied) self.assertEqual(response.status_code, 403) - count = Comment.objects.all().filter(comment="This is new comment by Anonymous").count() + count = Comment.objects.all().filter( + comment="This is new comment by Anonymous").count() self.assertEqual(count, 1) - def test_review_models_can_create_new_object(self): test = Review.objects.create( username="saul", profile="121212", review="232323") @@ -905,7 +934,7 @@ class DetailMateriTest(TestCase): self.assertContains(response, "Review (0)") self.client.post( - url, {"review": review }) + url, {"review": review}) self.client.post( url, {"review": review}) response = self.client.get(url) @@ -919,7 +948,8 @@ class DetailMateriTest(TestCase): def test_detail_materi_not_contains_form_review(self): response = self.client.get(self.url) self.assertNotContains(response, "Beri Review") - self.assertContains(response, "Login terlebih dahulu untuk Membuat review") + self.assertContains( + response, "Login terlebih dahulu untuk Membuat review") def test_tombol_citasiAPA(self): response = self.client.get(self.url) @@ -927,25 +957,27 @@ class DetailMateriTest(TestCase): def test_hasil_citasi_APA_materi_has_no_published_date(self): response = self.client.get(self.url) - expected = self.materi1.author + " . (n.d) . " + self.materi1.title + " . " + self.materi1.publisher + expected = self.materi1.author + \ + " . (n.d) . " + self.materi1.title + " . " + self.materi1.publisher self.assertIn(expected, response.context["citationAPA"]) self.assertIn(expected, response.context["citationAPA"]) def test_hasil_citasi_APA_materi_has_published_date(self): response = self.client.get(self.materi_with_published_date_url) - published_date = self.materi_with_published_date.published_date.strftime("%Y-%m-%d %H:%M") - expected = ( - self.materi_with_published_date.author - + " . (" - + published_date - + ") . " - + self.materi_with_published_date.title - + " . " - + self.materi_with_published_date.publisher - ) + published_date = self.materi_with_published_date.published_date.strftime( + "%Y-%m-%d %H:%M") + expected = ( + self.materi_with_published_date.author + + " . (" + + published_date + + ") . " + + self.materi_with_published_date.title + + " . " + + self.materi_with_published_date.publisher + ) self.assertIn(expected, response.context["citationAPA"]) - + def test_citation_IEEE_button(self): response = self.client.get(self.url) self.assertContains(response, "Citate IEEE") @@ -957,19 +989,19 @@ class DetailMateriTest(TestCase): current_month = current_date.strftime("%b") current_year = str(current_date.year) - expected = ( - "Agas, " - + "Materi 1. " - + "Kelas SC, n.d. " - + "Accessed on: " - + current_month - + ". " - + current_day - + ", " - + current_year - + ". [Online]. " - + "Available: http://testserver" - + self.url + expected = ( + "Agas, " + + "Materi 1. " + + "Kelas SC, n.d. " + + "Accessed on: " + + current_month + + ". " + + current_day + + ", " + + current_year + + ". [Online]. " + + "Available: http://testserver" + + self.url ) self.assertIn(expected, response.context["citationIEEE"]) @@ -979,7 +1011,8 @@ class DetailMateriTest(TestCase): current_day = str(current_date.day) current_month = current_date.strftime("%b") current_year = str(current_date.year) - published_date = self.materi_with_published_date.published_date.strftime('%Y') + published_date = self.materi_with_published_date.published_date.strftime( + '%Y') expected = "Agas, " + \ "Materi 1. " + \ @@ -1049,10 +1082,11 @@ class DetailMateriTest(TestCase): context2 = {} DetailMateriService.init_materi_download_count(context1, self.materi1) DetailMateriService.init_materi_download_count(context2, self.materi2) - self.assertNotEqual(context1['materi_download_count'], context2['materi_download_count']) + self.assertNotEqual( + context1['materi_download_count'], context2['materi_download_count']) self.assertEqual(context1['materi_download_count'], 3) self.assertEqual(context2['materi_download_count'], 2) - + def test_download_count_displayed_on_template_when_no_download(self): response = self.client.get(self.url) html = response.content.decode("utf-8") @@ -1093,16 +1127,20 @@ class DetailMateriTest(TestCase): dcount_materi1 = self.materi1.unduh.all().count() dcount_materi2 = self.materi2.unduh.all().count() - self.check_materi_info_in_html(self.dcount_info_name, dcount_materi1, html) - self.check_materi_info_not_in_html(self.dcount_info_name, dcount_materi2, html) - self.check_materi_info_in_html(self.dcount_info_name, dcount_materi2, html2) - self.check_materi_info_not_in_html(self.dcount_info_name, dcount_materi1, html2) - + self.check_materi_info_in_html( + self.dcount_info_name, dcount_materi1, html) + self.check_materi_info_not_in_html( + self.dcount_info_name, dcount_materi2, html) + self.check_materi_info_in_html( + self.dcount_info_name, dcount_materi2, html2) + self.check_materi_info_not_in_html( + self.dcount_info_name, dcount_materi1, html2) + def test_like_count_displayed_on_template_when_no_like(self): response = self.client.get(self.url) html = response.content.decode("utf-8") self.check_materi_info_in_html(self.lcount_info_name, 0, html) - + def test_like_count_displayed_on_template_when_single_like(self): payload = { 'materi_id': self.materi1.id, @@ -1112,8 +1150,8 @@ class DetailMateriTest(TestCase): response = self.client.get(self.url) html = response.content.decode("utf-8") - self.check_materi_info_in_html(self.lcount_info_name, 1, html) - + self.check_materi_info_in_html(self.lcount_info_name, 1, html) + def test_like_count_displayed_on_template_when_multiple_like(self): payload1 = { 'materi_id': self.materi1.id, @@ -1125,17 +1163,17 @@ class DetailMateriTest(TestCase): } self.client.post(self.like_url, payload1) self.client.post(self.like_url, payload2) - + response = self.client.get(self.url) html = response.content.decode("utf-8") self.check_materi_info_in_html(self.lcount_info_name, 2, html) - + def test_like_count_displayed_on_template_when_unlike(self): payload = { 'materi_id': self.materi1.id, 'session_id': "dummysession" } - + # Like materi once self.client.post(self.like_url, payload) response = self.client.get(self.url) @@ -1148,6 +1186,7 @@ class DetailMateriTest(TestCase): html = response.content.decode("utf-8") self.check_materi_info_in_html(self.lcount_info_name, 0, html) + class PostsViewTest(TestCase): @classmethod @@ -1175,14 +1214,14 @@ class PostsViewTest(TestCase): "comments": [], } - for j in range (LIKES_COUNT_PER_POST[i]): + for j in range(LIKES_COUNT_PER_POST[i]): Like.objects.create( - timestamp=timezone.now(), - materi=post, + timestamp=timezone.now(), + materi=post, session_id=("dummysession-" + str(i) + '-' + str(j)) ) time.sleep(0.1) - + for i, post_id in enumerate(post_comment_group_dict): post = post_comment_group_dict[post_id]["data"] @@ -1202,7 +1241,8 @@ class PostsViewTest(TestCase): "email": "user@email.com", "password": "justpass" } - cls.user = User.objects.create_user(**cls.user_credentials, is_contributor=True) + cls.user = User.objects.create_user( + **cls.user_credentials, is_contributor=True) cls.data = cls.generate_posts_data(cls.user) def _request_as_user(self): @@ -1252,12 +1292,12 @@ class PostsViewTest(TestCase): self.assertRegex( str(response.content), - rf'.*(<div id="post-{posts[2]}">)' + \ - rf'.*(<div id="post-{posts[2]}-comment-{comments[2][0]}">)' + \ - rf'.*(<div id="post-{posts[2]}-comment-{comments[2][1]}">)' + \ - rf'.*(<div id="post-{posts[2]}-comment-{comments[2][2]}">)' + \ - rf'.*(<div id="post-{posts[1]}">)' + \ - rf'.*(<div id="post-{posts[0]}">)' + \ + rf'.*(<div id="post-{posts[2]}">)' + + rf'.*(<div id="post-{posts[2]}-comment-{comments[2][0]}">)' + + rf'.*(<div id="post-{posts[2]}-comment-{comments[2][1]}">)' + + rf'.*(<div id="post-{posts[2]}-comment-{comments[2][2]}">)' + + rf'.*(<div id="post-{posts[1]}">)' + + rf'.*(<div id="post-{posts[0]}">)' + rf'.*(<div id="post-{posts[0]}-comment-{comments[0][0]}">)' ) @@ -1269,9 +1309,11 @@ class PostsViewTest(TestCase): self.assertContains( response, - '<span id="post-like-count-' + str(post.id) + '">' + str(post.like_count) + '</span>', + '<span id="post-like-count-' + + str(post.id) + '">' + str(post.like_count) + '</span>', ) + class TemplateLoaderTest(TestCase): def test_template_loader_url_exist(self): url = "/test-page.html" @@ -1324,13 +1366,13 @@ class UploadPageTest(TestCase): response = Client().get("/fake/") self.assertEqual(response.status_code, 404) - def test_upload_page_url_admin_doesnt_exist(self): + def test_upload_page_url_admin_doesnt_exist(self): self.client.login(email="admin@gov.id", password="admin") response = self.client.get("/unggah/") self.assertEqual(response.status_code, 403) - def test_upload_page_url_admin_cant_upload(self): + def test_upload_page_url_admin_cant_upload(self): self.client.login(email="admin@gov.id", password="admin") response = self.client.post("/unggah/") @@ -1366,6 +1408,7 @@ class UploadPageTest(TestCase): # Negative tests self.assertNotContains(response, "anything") + class UploadExcelPageTest(TestCase): def setUp(self): self.client = Client() @@ -1449,7 +1492,9 @@ class UploadExcelPageTest(TestCase): file_path = os.path.join(settings.MEDIA_ROOT, 'dummy.xlsx') - writer = pd.ExcelWriter(file_path, engine='xlsxwriter') #pylint: disable=abstract-class-instantiated + # pylint: disable=abstract-class-instantiated + writer = pd.ExcelWriter( + file_path, engine='xlsxwriter') data_frame.to_excel(writer, index=0) writer.save() @@ -1460,14 +1505,15 @@ class UploadExcelPageTest(TestCase): password="kontributor") field_lengths = { - 'author':30, - 'publisher':30, + 'author': 30, + 'publisher': 30, } - file_name, data_frame = self.create_dummy_excel(field_lengths=field_lengths) + file_name, data_frame = self.create_dummy_excel( + field_lengths=field_lengths) with open(file_name, 'rb') as fp: response = self.client.post("/unggah_excel/", {'excel': fp}) - + messages = list(dj_messages.get_messages(response.wsgi_request)) msg_text = messages[0].message @@ -1478,33 +1524,34 @@ class UploadExcelPageTest(TestCase): password="kontributor") field_lengths = { - 'title':50, - 'publisher':30, + 'title': 50, + 'publisher': 30, } - file_name, data_frame = self.create_dummy_excel(field_lengths=field_lengths) + file_name, data_frame = self.create_dummy_excel( + field_lengths=field_lengths) with open(file_name, 'rb') as fp: response = self.client.post("/unggah_excel/", {'excel': fp}) - + messages = list(dj_messages.get_messages(response.wsgi_request)) msg_text = messages[0].message self.assertIn('Author', msg_text) - def test_upload_excel_upload_file_publisher_error(self): self.client.login(email="kontributor@gov.id", password="kontributor") field_lengths = { - 'title':50, - 'author':30, + 'title': 50, + 'author': 30, } - file_name, data_frame = self.create_dummy_excel(field_lengths=field_lengths) + file_name, data_frame = self.create_dummy_excel( + field_lengths=field_lengths) with open(file_name, 'rb') as fp: response = self.client.post("/unggah_excel/", {'excel': fp}) - + messages = list(dj_messages.get_messages(response.wsgi_request)) msg_text = messages[0].message @@ -1515,15 +1562,16 @@ class UploadExcelPageTest(TestCase): password="kontributor") field_lengths = { - 'title':50, - 'author':30, - 'publisher':30, + 'title': 50, + 'author': 30, + 'publisher': 30, } - file_name, data_frame = self.create_dummy_excel(field_lengths=field_lengths) + file_name, data_frame = self.create_dummy_excel( + field_lengths=field_lengths) with open(file_name, 'rb') as fp: response = self.client.post("/unggah_excel/", {'excel': fp}) - + messages = list(dj_messages.get_messages(response.wsgi_request)) msg_text = messages[0].message @@ -1538,37 +1586,38 @@ class UploadExcelPageTest(TestCase): Category(name='Deep Learning').save() field_lengths = { - 'title':50, - 'author':30, - 'publisher':30, + 'title': 50, + 'author': 30, + 'publisher': 30, } - categories = ['Computer Science','Machine Learning','Deep Learning'] - - file_name, data_frame = self.create_dummy_excel(field_lengths=field_lengths, categories=categories) + categories = ['Computer Science', 'Machine Learning', 'Deep Learning'] + + file_name, data_frame = self.create_dummy_excel( + field_lengths=field_lengths, categories=categories) with open(file_name, 'rb') as fp: self.client.post("/unggah_excel/", {'excel': fp}) - + title = data_frame['Title'][0] materi = Materi.objects.get(title=title) default_path = 'book-cover-placeholder.png' self.assertTrue(materi) self.assertEquals(materi.cover.name, default_path) - self.assertTrue(os.path.exists(os.path.join(settings.MEDIA_ROOT, default_path))) + self.assertTrue(os.path.exists( + os.path.join(settings.MEDIA_ROOT, default_path))) def test_upload_excel_download_template(self): self.client.login(email="kontributor@gov.id", password="kontributor") response = self.client.get("/unggah_excel/?template=1") - - self.assertEquals(response['Content-Type'],'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') - self.assertEquals(response['Content-Disposition'],'attachment; filename=template.xlsx') - - + self.assertEquals( + response['Content-Type'], 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + self.assertEquals(response['Content-Disposition'], + 'attachment; filename=template.xlsx') class DashboardKontributorViewTest(TestCase): @@ -1638,6 +1687,7 @@ class DashboardKontributorViewTest(TestCase): html = response.content.decode("utf-8") self.assertIn(ERROR_403_MESSAGE, html) + class DeleteMateriTest(TestCase): def setUp(self): self.client = Client() @@ -1663,7 +1713,8 @@ class DeleteMateriTest(TestCase): "content.txt", b"Test") self.cover = SimpleUploadedFile( "flower.jpg", b"Test file") - self.contributor = User.objects.create_contributor(**self.contributor_credential) + 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() @@ -1674,14 +1725,14 @@ class DeleteMateriTest(TestCase): 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.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) @@ -1689,6 +1740,7 @@ class DeleteMateriTest(TestCase): self.materi1.refresh_from_db() self.assertNotEqual(self.materi1.deleted_at, None) + class ProfilViewTest(TestCase): @classmethod def setUpTestData(cls): @@ -1697,10 +1749,13 @@ class ProfilViewTest(TestCase): cls.template_name = "profil.html" cls.view = ProfilView - cls.contributor_credentials = {"email": "contributor@gov.id", "password": "justpass"} - cls.contributor = User.objects.create_contributor(**cls.contributor_credentials) + cls.contributor_credentials = { + "email": "contributor@gov.id", "password": "justpass"} + cls.contributor = User.objects.create_contributor( + **cls.contributor_credentials) - cls.admin_credentials = {"email": "admin@gov.id", "password": "justpass"} + cls.admin_credentials = { + "email": "admin@gov.id", "password": "justpass"} cls.admin = User.objects.create_admin(**cls.admin_credentials) def test_returns_correct_profile_view(self): @@ -1708,7 +1763,7 @@ class ProfilViewTest(TestCase): self.assertEqual(found.func.__name__, self.view.as_view().__name__) def _request_as_user(self, credentials): - self.client = Client() + self.client = Client() self.client.login(**credentials) return self.client.get(self.url) @@ -1739,10 +1794,13 @@ class SuntingProfilViewTest(TestCase): cls.template_name = "sunting.html" cls.view = SuntingProfilView - cls.contributor_credentials = {"email": "contributor@gov.id", "password": "justpass"} - cls.contributor = User.objects.create_contributor(**cls.contributor_credentials) + cls.contributor_credentials = { + "email": "contributor@gov.id", "password": "justpass"} + cls.contributor = User.objects.create_contributor( + **cls.contributor_credentials) - cls.admin_credentials = {"email": "admin@gov.id", "password": "justpass"} + cls.admin_credentials = { + "email": "admin@gov.id", "password": "justpass"} cls.admin = User.objects.create_admin(**cls.admin_credentials) def test_sunting_profile_view(self): @@ -1750,7 +1808,7 @@ class SuntingProfilViewTest(TestCase): self.assertEqual(found.func.__name__, self.view.as_view().__name__) def _request_as_user(self, credentials): - self.client = Client() + self.client = Client() self.client.login(**credentials) return self.client.get(self.url) @@ -1785,8 +1843,10 @@ class SuntingProfilViewTest(TestCase): } form = SuntingProfilForm(data=form_data) - self.assertEqual(form.fields["twitter"].widget.attrs.get("autofocus"), "") - self.assertEqual(form.fields["instagram"].widget.attrs.get("autofocus"), None) + self.assertEqual( + form.fields["twitter"].widget.attrs.get("autofocus"), "") + self.assertEqual( + form.fields["instagram"].widget.attrs.get("autofocus"), None) class SuksesLoginKontributorTest(TestCase): @@ -2131,7 +2191,7 @@ class RevisiMateriTest(TestCase): # Logout self.client.logout() - + class GenerateDummyCommandTest(TestCase): def setUp(self): @@ -2167,7 +2227,8 @@ class RemoveDummyCommandTest(TestCase): call_command("removedummy", stdout=stdout) - self.assertIn("Successfully remove all dummy object", stdout.getvalue()) + self.assertIn("Successfully remove all dummy object", + stdout.getvalue()) self.assertEqual(User.objects.count(), 0) self.assertEqual(Category.objects.count(), 0) self.assertEqual(Materi.objects.count(), 0) @@ -2192,8 +2253,10 @@ class RatingMateriTest(TestCase): self.contributor = get_user_model().objects.create_user( **self.contributor_credential, name="Kontributor", is_contributor=True ) - self.user_one = get_user_model().objects.create_user(**self.user_one_credential, name="User One") - self.user_two = get_user_model().objects.create_user(**self.user_two_credential, name="User Two") + self.user_one = get_user_model().objects.create_user( + **self.user_one_credential, name="User One") + self.user_two = get_user_model().objects.create_user( + **self.user_two_credential, name="User Two") self.cover = SimpleUploadedFile( "cover.jpg", b"Test file" @@ -2219,17 +2282,20 @@ class RatingMateriTest(TestCase): self.assertEqual(rating.materi, self.materi1) self.assertEqual(rating.user, self.user_one) self.assertTrue(0 < rating.score < 6) - self.assertEqual(rating.__str__(), "Material:Materi 1 | User:User One | Rating:5") + self.assertEqual(rating.__str__(), + "Material:Materi 1 | User:User One | Rating:5") def test_rating_model_should_not_be_created_with_rating_more_than_5(self): with self.assertRaises(ValidationError) as context: Rating(materi=self.materi1, user=self.user_one, score=6).save() - self.assertTrue('Rating score must be integer between 1-5' in str(context.exception)) + self.assertTrue( + 'Rating score must be integer between 1-5' in str(context.exception)) def test_rating_model_should_not_be_created_with_rating_less_than_1(self): with self.assertRaises(ValidationError) as context: Rating(materi=self.materi1, user=self.user_one, score=0).save() - self.assertTrue('Rating score must be integer between 1-5' in str(context.exception)) + self.assertTrue( + 'Rating score must be integer between 1-5' in str(context.exception)) def test_one_materi_should_be_able_to_be_related_to_multiple_rating(self): Rating(materi=self.materi1, user=self.user_one, score=1).save() @@ -2281,7 +2347,8 @@ class RatingMateriTest(TestCase): self.assertEqual(response.status_code, 403) def test_rating_materi_post_not_authenticated_should_return_403_forbidden(self): - response = self.client.post(self.url_rate, {'materi_id': 1, 'rating_score': 5}) + response = self.client.post( + self.url_rate, {'materi_id': 1, 'rating_score': 5}) response_json = json.loads(response.content) self.assertEqual(response_json.get("success", None), False) self.assertEqual(response_json.get("msg", None), "Forbidden") @@ -2306,52 +2373,65 @@ class RatingMateriTest(TestCase): def test_rating_materi_authenticated_materi_id_doesnt_exist_should_return_422(self): self.client.login(**self.user_one_credential) - response = self.client.post(self.url_rate, {'materi_id': 123456, 'rating_score': 5}) + response = self.client.post( + self.url_rate, {'materi_id': 123456, 'rating_score': 5}) response_json = json.loads(response.content) self.assertEqual(response_json.get("success", None), False) - self.assertEqual(response_json.get("msg", None), "Materi does not exist") + self.assertEqual(response_json.get( + "msg", None), "Materi does not exist") self.assertEqual(response.status_code, 422) def test_rating_materi_authenticated_param_wrong_data_type_should_return_422(self): self.client.login(**self.user_one_credential) - response = self.client.post(self.url_rate, {'materi_id': "STRING", 'rating_score': 5}) + response = self.client.post( + self.url_rate, {'materi_id': "STRING", 'rating_score': 5}) response_json = json.loads(response.content) self.assertEqual(response_json.get("success", None), False) - self.assertEqual(response_json.get("msg", None), "materi_id must be an integer") + self.assertEqual(response_json.get("msg", None), + "materi_id must be an integer") self.assertEqual(response.status_code, 422) - response = self.client.post(self.url_rate, {'materi_id': 1, 'rating_score': "STRING"}) + response = self.client.post( + self.url_rate, {'materi_id': 1, 'rating_score': "STRING"}) response_json = json.loads(response.content) self.assertEqual(response_json.get("success", None), False) - self.assertEqual(response_json.get("msg", None), "rating_score must be an integer") + self.assertEqual(response_json.get("msg", None), + "rating_score must be an integer") self.assertEqual(response.status_code, 422) def test_rating_score_should_be_between_1_and_5(self): self.client.login(**self.user_one_credential) for i in range(1, 6): Rating.objects.all().delete() - response = self.client.post(self.url_rate, {'materi_id': self.materi1.id, 'rating_score': i}) + response = self.client.post( + self.url_rate, {'materi_id': self.materi1.id, 'rating_score': i}) response_json = json.loads(response.content) # self.assertEqual(response_json.get("success", None), True) - self.assertEqual(response_json.get("msg", None), "Rating successfully created") + self.assertEqual(response_json.get("msg", None), + "Rating successfully created") self.assertEqual(response.status_code, 201) for i in [-100, -7, -6, -1, 0, 6, 7, 100]: Rating.objects.all().delete() - response = self.client.post(self.url_rate, {'materi_id': self.materi1.id, 'rating_score': i}) + response = self.client.post( + self.url_rate, {'materi_id': self.materi1.id, 'rating_score': i}) response_json = json.loads(response.content) # self.assertEqual(response_json.get("success", None), False) - self.assertEqual(response_json.get("msg", None), "Rating must be an integer from 1 to 5") + self.assertEqual(response_json.get("msg", None), + "Rating must be an integer from 1 to 5") self.assertEqual(response.status_code, 422) def test_user_should_not_able_to_rate_materi_twice(self): self.client.login(**self.user_one_credential) Rating.objects.all().delete() - self.client.post(self.url_rate, {'materi_id': self.materi1.id, 'rating_score': 1}) - response = self.client.post(self.url_rate, {'materi_id': self.materi1.id, 'rating_score': 2}) + self.client.post( + self.url_rate, {'materi_id': self.materi1.id, 'rating_score': 1}) + response = self.client.post( + self.url_rate, {'materi_id': self.materi1.id, 'rating_score': 2}) response_json = json.loads(response.content) # self.assertEqual(response_json.get("success", None), False) - self.assertEqual(response_json.get("msg", None), "Rating already exist") + self.assertEqual(response_json.get( + "msg", None), "Rating already exist") self.assertEqual(response.status_code, 409) def test_user_authenticated_visit_unrated_should_get_0_materi_rating_score_context(self): @@ -2369,11 +2449,12 @@ class RatingMateriTest(TestCase): response = self.client.get(self.url_materi) self.assertEqual(1, response.context.get('materi_rating_score')) + class FileManagementUtilTest(TestCase): def setUp(self): self.filename = "image_with_exif_data.gif" self.file_content = open(settings.BASE_DIR + "/app/test_files/" + - self.filename, "rb").read() + self.filename, "rb").read() def test_get_random_filename_isCorrect(self): generated_name = get_random_filename(self.filename) @@ -2396,6 +2477,7 @@ class FileManagementUtilTest(TestCase): self.assertTrue(len(sanitized_img) < len(self.file_content)) self.assertTrue(b'<exif:' not in sanitized_img) + class RequestMateriTest(TestCase): def setUp(self): self.client = Client() @@ -2447,15 +2529,16 @@ class RequestMateriTest(TestCase): self.client.login(**self.contributor_credential) response = self.client.post(self.url, - data={ - 'title': 'Requested Material' - }) + data={ + 'title': 'Requested Material' + }) self.assertEqual(ReqMaterial.objects.count(), 1) new_material_request = ReqMaterial.objects.first() self.assertEqual(new_material_request.title, 'Requested Material') - self.assertIn('Permintaan materi berhasil dikirimkan', response.content.decode()) + self.assertIn('Permintaan materi berhasil dikirimkan', + response.content.decode()) self.client.logout() def test_given_no_title_should_not_save_request_and_return_correct_response_message(self): @@ -2502,62 +2585,77 @@ class RatingContributorTest(TransactionTestCase): self.url = f"/profil/{self.contributor.email}/" def test_add_rating_contributor(self): - RatingContributor.objects.create(score=3, contributor=self.contributor, user=self.anonymous) + RatingContributor.objects.create( + score=3, contributor=self.contributor, user=self.anonymous) self.assertEqual(1, RatingContributor.objects.count()) def test_add_rating_contributor_should_failed_when_negative(self): with self.assertRaises(ValidationError): - RatingContributor.objects.create(score=-1, contributor=self.contributor, user=self.anonymous) + RatingContributor.objects.create( + score=-1, contributor=self.contributor, user=self.anonymous) self.assertEqual(0, RatingContributor.objects.count()) def test_add_rating_contributor_should_failed_when_bigger_than_five(self): with self.assertRaises(ValidationError): - RatingContributor.objects.create(score=6, contributor=self.contributor, user=self.anonymous) + RatingContributor.objects.create( + score=6, contributor=self.contributor, user=self.anonymous) self.assertEqual(0, RatingContributor.objects.count()) def test_submit_form_correct_rating_contributor_should_added(self): self.client.login(**self.anonymous_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 5}) - self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor.id).count()) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous.id, "score": 5}) + self.assertEqual(1, RatingContributor.objects.filter( + contributor=self.contributor.id).count()) self.client.logout() self.client.login(**self.admin_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": 1}) - self.assertEqual(2, RatingContributor.objects.filter(contributor=self.contributor.id).count()) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.admin.id, "score": 1}) + self.assertEqual(2, RatingContributor.objects.filter( + contributor=self.contributor.id).count()) def test_submit_form_not_correct_rating_contributor_should__not_added(self): self.client.login(**self.anonymous_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 6}) - self.assertEqual(0, RatingContributor.objects.filter(contributor=self.contributor.id).count()) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous.id, "score": 6}) + self.assertEqual(0, RatingContributor.objects.filter( + contributor=self.contributor.id).count()) self.client.logout() self.client.login(**self.admin_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": 0}) - self.assertEqual(0, RatingContributor.objects.filter(contributor=self.contributor.id).count()) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.admin.id, "score": 0}) + self.assertEqual(0, RatingContributor.objects.filter( + contributor=self.contributor.id).count()) def test_average_rating_score_empty(self): response = self.client.get(self.url) - self.assertTemplateUsed(response=response, template_name="app/katalog_kontri.html") + self.assertTemplateUsed( + response=response, template_name="app/katalog_kontri.html") self.assertContains(response=response, text="Rating: 0", count=1) self.assertContains(response=response, text="oleh: 0 orang", count=1) def test_average_rating_correct(self): self.client.login(**self.anonymous_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 5}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous.id, "score": 5}) response = self.client.get(self.url) self.assertContains(response=response, text="Rating: 5", count=1) self.assertContains(response=response, text="oleh: 1 orang", count=1) def test_average_rating_form_incorrect_correct(self): self.client.login(**self.anonymous_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 6}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous.id, "score": 6}) response = self.client.get(self.url) self.assertContains(response=response, text="Rating: 0", count=1) self.assertContains(response=response, text="oleh: 0 orang", count=1) self.client.logout() self.client.login(**self.admin_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": -1}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.admin.id, "score": -1}) response = self.client.get(self.url) self.assertContains(response=response, text="Rating: 0", count=1) self.assertContains(response=response, text="oleh: 0 orang", count=1) @@ -2566,10 +2664,13 @@ class RatingContributorTest(TransactionTestCase): score = 5 avg = [score] self.client.login(**self.anonymous_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": score}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous.id, "score": score}) response = self.client.get(self.url) - self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) - self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.assertContains(response=response, + text=f"Rating: {mean(avg)}", count=1) + self.assertContains(response=response, + text=f"oleh: {len(avg)} orang", count=1) self.client.logout() self.anonymous2 = get_user_model().objects.create_user( @@ -2578,10 +2679,13 @@ class RatingContributorTest(TransactionTestCase): score = 4 avg.append(score) self.client.login(email=self.anonymous2.email, password="test") - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous2.id, "score": score}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous2.id, "score": score}) response = self.client.get(self.url) - self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) - self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.assertContains(response=response, + text=f"Rating: {mean(avg)}", count=1) + self.assertContains(response=response, + text=f"oleh: {len(avg)} orang", count=1) self.client.logout() self.anonymous3 = get_user_model().objects.create_user( @@ -2590,10 +2694,13 @@ class RatingContributorTest(TransactionTestCase): score = 3 avg.append(score) self.client.login(email=self.anonymous3.email, password="test") - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous3.id, "score": score}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous3.id, "score": score}) response = self.client.get(self.url) - self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) - self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.assertContains(response=response, + text=f"Rating: {mean(avg)}", count=1) + self.assertContains(response=response, + text=f"oleh: {len(avg)} orang", count=1) self.client.logout() self.anonymous4 = get_user_model().objects.create_user( @@ -2602,120 +2709,131 @@ class RatingContributorTest(TransactionTestCase): score = 2 avg.append(score) self.client.login(email=self.anonymous4.email, password="test") - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous4.id, "score": score}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.anonymous4.id, "score": score}) response = self.client.get(self.url) - self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) - self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.assertContains(response=response, + text=f"Rating: {mean(avg)}", count=1) + self.assertContains(response=response, + text=f"oleh: {len(avg)} orang", count=1) self.client.logout() score = 1 avg.append(score) self.client.login(**self.admin_credential) - self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": score}) + self.client.post(self.url, data={ + "contributor": self.contributor.id, "user": self.admin.id, "score": score}) response = self.client.get(self.url) - self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) - self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) - + self.assertContains(response=response, + text=f"Rating: {mean(avg)}", count=1) + self.assertContains(response=response, + text=f"oleh: {len(avg)} orang", count=1) + def test_not_authenticated_user_should_not_able_to_add_rating(self): response_post = self.client.post(self.url, data={ - "contributor":self.contributor.id, - "user":self.anonymous.id, - "score":3 + "contributor": self.contributor.id, + "user": self.anonymous.id, + "score": 3 }) response_get = self.client.get(self.url) self.assertEqual(response_post.status_code, 403) - self.assertContains(response_get, "Kamu harus login untuk memberi rating") - + self.assertContains( + response_get, "Kamu harus login untuk memberi rating") + def test_not_authenticated_user_should_not_able_to_delete_rating(self): - response_post = self.client.post(self.url, data={"delete":True}) + response_post = self.client.post(self.url, data={"delete": True}) self.assertEqual(response_post.status_code, 403) - + def test_authenticated_user_should_not_delete_rating_if_has_not_been_rated(self): self.client.login(**self.admin_credential) self.client.post(self.url, data={ - "contributor":self.contributor.id, - "user":self.admin.id, - "score":3 + "contributor": self.contributor.id, + "user": self.admin.id, + "score": 3 }) - - self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor).count()) + + self.assertEqual(1, RatingContributor.objects.filter( + contributor=self.contributor).count()) self.client.logout() self.client.login(**self.anonymous_credential) - self.client.post(self.url, data={"delete":True}) - - self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor).count()) - + self.client.post(self.url, data={"delete": True}) + + self.assertEqual(1, RatingContributor.objects.filter( + contributor=self.contributor).count()) + def test_authenticated_user_should_delete_rating_if_has_been_rated(self): self.client.login(**self.admin_credential) self.client.post(self.url, data={ - "contributor":self.contributor.id, - "user":self.admin.id, - "score":3 + "contributor": self.contributor.id, + "user": self.admin.id, + "score": 3 }) response = self.client.get(self.url) self.assertContains(response, 'Rating: 3') self.assertContains(response, 'oleh: 1 orang') - self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor).count()) + self.assertEqual(1, RatingContributor.objects.filter( + contributor=self.contributor).count()) - self.client.post(self.url, data={"delete":True}) + self.client.post(self.url, data={"delete": True}) response = self.client.get(self.url) self.assertContains(response, 'Rating: 0') self.assertContains(response, 'oleh: 0 orang') - self.assertEqual(0, RatingContributor.objects.filter(contributor=self.contributor).count()) - + self.assertEqual(0, RatingContributor.objects.filter( + contributor=self.contributor).count()) + def test_average_still_be_correct_when_rating_was_deleted(self): - scores = [2,4] + scores = [2, 4] self.client.login(**self.admin_credential) self.client.post(self.url, data={ - "contributor":self.contributor.id, - "user":self.admin.id, - "score":scores[0] + "contributor": self.contributor.id, + "user": self.admin.id, + "score": scores[0] }) self.client.logout() self.client.login(**self.anonymous_credential) self.client.post(self.url, data={ - "contributor":self.contributor.id, - "user":self.anonymous.id, - "score":scores[1] + "contributor": self.contributor.id, + "user": self.anonymous.id, + "score": scores[1] }) response = self.client.get(self.url) self.assertContains(response, f'Rating: {mean(scores)}') self.assertContains(response, 'oleh: 2 orang') - self.client.post(self.url, data={"delete":True}) + self.client.post(self.url, data={"delete": True}) response = self.client.get(self.url) self.assertContains(response, f'Rating: {scores[0]}') self.assertContains(response, 'oleh: 1 orang') - + def test_authenticated_user_should_update_rating_if_has_been_rated(self): self.client.login(**self.anonymous_credential) self.client.post(self.url, data={ - "contributor":self.contributor.id, - "user":self.anonymous.id, - "score":5 + "contributor": self.contributor.id, + "user": self.anonymous.id, + "score": 5 }) response = self.client.get(self.url) self.assertContains(response, 'Rating: 5') self.assertContains(response, 'oleh: 1 orang') - self.client.post(self.url, data={"update":True, "score":3}) + self.client.post(self.url, data={"update": True, "score": 3}) response = self.client.get(self.url) self.assertContains(response, 'Rating: 3') self.assertContains(response, 'oleh: 1 orang') - + def test_authenticated_user_should_not_update_rating_if_has_not_been_rated(self): self.client.login(**self.anonymous_credential) response = self.client.get(self.url) self.assertContains(response, 'Rating: 0') self.assertContains(response, 'oleh: 0 orang') - self.client.post(self.url, data={"update":True, "score":3}) + self.client.post(self.url, data={"update": True, "score": 3}) response = self.client.get(self.url) self.assertContains(response, 'Rating: 0') self.assertContains(response, 'oleh: 0 orang') - + class UserDownloadHistoryTest(TestCase): def setUp(self): @@ -2754,26 +2872,30 @@ class UserDownloadHistoryTest(TestCase): self.materi1 = Materi.objects.first() self.download_url = f"/materi/{self.materi1.id}/unduh" self.history_url = "/download-history/" - + def test_multiple_insert_download_statistic_with_user(self): - DownloadStatistics(materi=self.materi1, downloader=self.user1_anonim).save() + DownloadStatistics(materi=self.materi1, + downloader=self.user1_anonim).save() num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 1) - - DownloadStatistics(materi=self.materi1, downloader=self.user1_anonim).save() + + DownloadStatistics(materi=self.materi1, + downloader=self.user1_anonim).save() num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 2) - + def test_download_statistics_bound_to_specific_user(self): - DownloadStatistics(materi=self.materi1, downloader=self.user1_anonim).save() + DownloadStatistics(materi=self.materi1, + downloader=self.user1_anonim).save() num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 1) - + DownloadStatistics(materi=self.materi1).save() num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 1) - - DownloadStatistics(materi=self.materi1, downloader=self.user2_anonim).save() + + DownloadStatistics(materi=self.materi1, + downloader=self.user2_anonim).save() user1_num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() user2_num_of_downloads = self.user2_anonim.riwayat_unduh.all().count() self.assertEqual(user1_num_of_downloads, 1) @@ -2782,19 +2904,19 @@ class UserDownloadHistoryTest(TestCase): def test_registered_user_download(self): # Login self.client.login(**self.user1_credential) - + self.client.get(self.download_url) num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 1) - + # Logout self.client.logout() - + def test_unregistered_user_download(self): self.client.get(self.download_url) downloaded_materi = self.client.session['downloaded_materi'] num_of_downloads = DownloadStatistics.objects.filter( - pk__in=downloaded_materi).count() + pk__in=downloaded_materi).count() self.assertEqual(num_of_downloads, 1) def test_registered_user_multiple_download(self): @@ -2807,53 +2929,53 @@ class UserDownloadHistoryTest(TestCase): self.client.get(self.download_url) num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 2) - + # Logout self.client.logout() - + def test_unregistered_user_multiple_download(self): self.client.get(self.download_url) downloaded_materi = self.client.session['downloaded_materi'] num_of_downloads = DownloadStatistics.objects.filter( - pk__in=downloaded_materi).count() + pk__in=downloaded_materi).count() self.assertEqual(num_of_downloads, 1) self.client.get(self.download_url) downloaded_materi = self.client.session['downloaded_materi'] num_of_downloads = DownloadStatistics.objects.filter( - pk__in=downloaded_materi).count() + pk__in=downloaded_materi).count() self.assertEqual(num_of_downloads, 2) - + def test_registered_user_doesnt_use_session_when_download(self): # Login self.client.login(**self.user1_credential) - + self.client.get(self.download_url) self.assertFalse('downloaded_materi' in self.client.session) - + # Logout self.client.logout() - + def test_download_history_bound_to_specific_user(self): # Login Anonym 1 self.client.login(**self.user1_credential) self.client.get(self.download_url) num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() self.assertEqual(num_of_downloads, 1) - + # Logout Anonym 1 self.client.logout() - - # Unregistered User download + + # Unregistered User download self.client.get(self.download_url) user1_num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() downloaded_materi = self.client.session['downloaded_materi'] guest_num_of_downloads = DownloadStatistics.objects.filter( - pk__in=downloaded_materi).count() + pk__in=downloaded_materi).count() self.assertEqual(user1_num_of_downloads, 1) self.assertEqual(guest_num_of_downloads, 1) - - # Login Anonym 2 + + # Login Anonym 2 self.client.login(**self.user2_credential) self.client.get(self.download_url) user1_num_of_downloads = self.user1_anonim.riwayat_unduh.all().count() @@ -2861,10 +2983,11 @@ class UserDownloadHistoryTest(TestCase): self.assertEqual(user1_num_of_downloads, 1) self.assertEqual(guest_num_of_downloads, 1) self.assertEqual(user2_num_of_downloads, 1) - + # Logout Anonym 2 self.client.logout() + class DownloadHistoryViewTest(TestCase): def setUp(self): self.user_credential = { @@ -2881,42 +3004,42 @@ class DownloadHistoryViewTest(TestCase): **self.contributor_credential, name="Kontributor", is_contributor=True ) self.client = Client() - + content1 = b"Test file" content2 = b"File Test" - - self.cover1 = SimpleUploadedFile("cover1.jpg",content1) - self.content1 = SimpleUploadedFile("content1.txt",content1) - - self.cover2 = SimpleUploadedFile("cover2.jpg",content2) - self.content2 = SimpleUploadedFile("content2.txt",content2) - + + self.cover1 = SimpleUploadedFile("cover1.jpg", content1) + self.content1 = SimpleUploadedFile("content1.txt", content1) + + self.cover2 = SimpleUploadedFile("cover2.jpg", content2) + self.content2 = SimpleUploadedFile("content2.txt", content2) + self.materi1 = Materi.objects.create(title="Materi 1", author="Agas", uploader=self.contributor, - publisher="Kelas SC", descriptions="Deskripsi Materi 1", - status="PENDING", cover=self.cover1, content=self.content1) + publisher="Kelas SC", descriptions="Deskripsi Materi 1", + status="PENDING", cover=self.cover1, content=self.content1) self.materi2 = Materi.objects.create(title="Materi 2", author="Danin", uploader=self.contributor, - publisher="Kelas DDP", descriptions="Deskripsi Materi 2", - status="PENDING", cover=self.cover2, content=self.content2) - + publisher="Kelas DDP", descriptions="Deskripsi Materi 2", + status="PENDING", cover=self.cover2, content=self.content2) + self.download_url1 = f"/materi/{self.materi1.id}/unduh" self.download_url2 = f"/materi/{self.materi2.id}/unduh" self.history_url = "/download-history/" - + # Login self.client.login(**self.user_credential) def tearDown(self): # Logout self.client.logout() - + def test_allow_registered_user(self): response = self.client.get(self.history_url) self.assertEqual(response.status_code, 200) - + def test_allow_unregistered_user(self): - # Forced Logout + # Forced Logout self.client.logout() - + response = self.client.get(self.history_url) self.assertEqual(response.status_code, 200) @@ -2928,14 +3051,14 @@ class DownloadHistoryViewTest(TestCase): response = self.client.get(self.history_url) resp_html = response.content.decode('utf8') self.assertIn(self.user_anonim.name, resp_html) - + def test_registered_user_download_history_correctly_displayed(self): self.client.get(self.download_url1) self.client.get(self.download_url2) self.client.get(self.download_url1) - + jkt_timezone = pytz.timezone(TIME_ZONE) - + download_history = self.user_anonim.riwayat_unduh.all() response = self.client.get(self.history_url) resp_html = response.content.decode('utf8') @@ -2943,19 +3066,20 @@ class DownloadHistoryViewTest(TestCase): downloaded_materi = riwayat.materi self.assertIn(downloaded_materi.title, resp_html) self.assertIn(downloaded_materi.author, resp_html) - + jkt_timestamp = riwayat.timestamp.astimezone(jkt_timezone) - self.assertIn(jkt_timestamp.strftime("%d %B %Y %H:%M:%S"), resp_html) - + self.assertIn(jkt_timestamp.strftime( + "%d %B %Y %H:%M:%S"), resp_html) + def test_unregistered_user_download_history_correctly_displayed(self): self.client.logout() self.client.get(self.download_url1) self.client.get(self.download_url2) self.client.get(self.download_url1) - + jkt_timezone = pytz.timezone(TIME_ZONE) - + response = self.client.get(self.history_url) resp_html = response.content.decode('utf8') for riwayat_id in self.client.session['downloaded_materi']: @@ -2963,19 +3087,20 @@ class DownloadHistoryViewTest(TestCase): downloaded_materi = riwayat.materi self.assertIn(downloaded_materi.title, resp_html) self.assertIn(downloaded_materi.author, resp_html) - + jkt_timestamp = riwayat.timestamp.astimezone(jkt_timezone) - self.assertIn(jkt_timestamp.strftime("%d %B %Y %H:%M:%S"), resp_html) - + self.assertIn(jkt_timestamp.strftime( + "%d %B %Y %H:%M:%S"), resp_html) + def test_download_history_not_display_if_user_changed(self): self.client.get(self.download_url1) self.client.get(self.download_url2) self.client.get(self.download_url1) self.client.logout() - + jkt_timezone = pytz.timezone(TIME_ZONE) - + download_history = self.user_anonim.riwayat_unduh.all() response = self.client.get(self.history_url) resp_html = response.content.decode('utf8') @@ -2983,25 +3108,26 @@ class DownloadHistoryViewTest(TestCase): downloaded_materi = riwayat.materi self.assertNotIn(downloaded_materi.title, resp_html) self.assertNotIn(downloaded_materi.author, resp_html) - + jkt_timestamp = riwayat.timestamp.astimezone(jkt_timezone) - self.assertNotIn(jkt_timestamp.strftime("%d %B %Y %H:%M:%S"), resp_html) - + self.assertNotIn(jkt_timestamp.strftime( + "%d %B %Y %H:%M:%S"), resp_html) + def test_unregistered_user_download_history_wont_be_saved_if_user_changes(self): self.client.logout() self.client.get(self.download_url1) self.client.get(self.download_url2) self.client.get(self.download_url1) - + self.client.get(self.history_url) self.client.login(**self.user_credential) self.client.logout() self.assertFalse('downloaded_materi' in self.client.session) - + def test_download_history_sorted_by_download_time(self): - # download with 1 second interval to differ download time + # download with 1 second interval to differ download time self.client.get(self.download_url1) sleep(1) self.client.get(self.download_url2) @@ -3009,23 +3135,25 @@ class DownloadHistoryViewTest(TestCase): self.client.get(self.download_url1) sleep(1) self.client.get(self.download_url2) - + response = self.client.get(self.history_url) resp_html = response.content.decode('utf8') - - table_html = ("<table" + resp_html.split("<table")[1]).split("</table>")[0] + "</table>" + + table_html = ("<table" + resp_html.split("<table") + [1]).split("</table>")[0] + "</table>" soup = BeautifulSoup(table_html, 'html.parser') histories_html = soup.find('tbody').find_all('tr') prev_timestamp = None - + for riwayat_html in histories_html: materi_data = riwayat_html.find_all("td") date_format = "%d %B %Y %H:%M:%S" - materi_timestamp = datetime.strptime(materi_data[2].get_text(), date_format) + materi_timestamp = datetime.strptime( + materi_data[2].get_text(), date_format) if prev_timestamp: self.assertTrue(prev_timestamp > materi_timestamp) prev_timestamp = materi_timestamp - + def test_no_history_display_message(self): no_history_msg = "Anda belum mengunduh materi. Silahkan unduh materi yang anda butuhkan" response = self.client.get(self.history_url) @@ -3034,9 +3162,9 @@ class DownloadHistoryViewTest(TestCase): class MateriModelTest(TestCase): - + def setUp(self): - self.contributor = User.objects.create( + self.contributor = User.objects.create( email="kontributor@gov.id", password="passwordtest", name="kontributor", @@ -3056,12 +3184,15 @@ class MateriModelTest(TestCase): self.assertEqual(0, self.materi.like_count) def test_like_count_return_right_value_when_there_is_like(self): - Like.objects.create(timestamp=timezone.now(), materi=self.materi, session_id="dummysessionid1") + Like.objects.create(timestamp=timezone.now(), + materi=self.materi, session_id="dummysessionid1") self.assertEqual(1, self.materi.like_count) - Like.objects.create(timestamp=timezone.now(), materi=self.materi, session_id="dummysessionid2") + Like.objects.create(timestamp=timezone.now(), + materi=self.materi, session_id="dummysessionid2") self.assertEqual(2, self.materi.like_count) + class MateriFavoriteTest(TestCase): @classmethod def setUpTestData(cls): @@ -3070,7 +3201,8 @@ class MateriFavoriteTest(TestCase): "email": "user@email.com", "password": "justpass" } - cls.user = User.objects.create_user(**cls.user_credentials, is_contributor=True) + cls.user = User.objects.create_user( + **cls.user_credentials, is_contributor=True) def _request_as_user(self): self.client.login(**self.user_credentials) @@ -3078,7 +3210,9 @@ class MateriFavoriteTest(TestCase): def test_url_resolves_to_favorite_view(self): found = resolve(self.url) - self.assertEqual(found.func.__name__, MateriFavorite.as_view().__name__) + self.assertEqual(found.func.__name__, + MateriFavorite.as_view().__name__) + class RandomizedMateriTest(TestCase): def setUp(self): @@ -3123,7 +3257,8 @@ class RandomizedMateriTest(TestCase): response = Client().get("/?random=1") self.assertIn("Materi 1", response.content.decode()) self.assertIn("Materi 2", response.content.decode()) - + + class YearChoicesTest(TestCase): def test_release_year_contains_the_right_current_year(self): now = dt.date.today().year @@ -3137,6 +3272,7 @@ class YearChoicesTest(TestCase): self.assertEqual((2000, 2000), choices[0]) + TEST_IMAGE = ''' iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI WXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAABfElEQVQ4y52TvUuCURTGf5Zg @@ -3176,20 +3312,24 @@ cpnR0WOUSiVEhLVKhbXXa7xcXqHyaoV6o0Hqd1MxUjqu7XYLMFkaNXtXYC09+R5UwbkYEcVaizFm P/LWGsLJydMs3VvCWkP3gzxK7OKu7Bl81/tEhKmpKVhYWNCJiQkNglDDMKdhLpf1/0AQhDo+Pq5z c3NKmqa6uLios7MXtFgsahRFGhUKHUS7KBQ0iiIdGhrS8+dndH5+XpMk0X8AMTVx/inpU4cAAAAl dEVYdGNyZWF0ZS1kYXRlADIwMTAtMTItMjZUMTQ6NDk6MjErMDk6MDAHHBB1AAAAJXRFWHRtb2Rp -ZnktZGF0ZQAyMDEwLTEyLTI2VDE0OjQ5OjIxKzA5OjAwWK1mQQAAAABJRU5ErkJggg== +ZnktZGF0ZQAyMDEwLTEyLTI2VDE0OjQ5OjIxKzA5OjAwWK1mQQAAAABJRU5ErkJggg == '''.strip() + + class YTUrlVideoTest(TestCase): def setUp(self): self.client = Client() - self.contributor_credential = {"email": "kontributor@gov.id", "password": "passwordtest"} + 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.setUpImage() self.content = SimpleUploadedFile("ExampleFile221.pdf", b"Test file") - self.category = Category.objects.create(id="1", name="medis", description="kategori medis") - + self.category = Category.objects.create( + id="1", name="medis", description="kategori medis") + @override_settings(MEDIA_ROOT=tempfile.gettempdir()) def setUpImage(self): self.cover = InMemoryUploadedFile( @@ -3214,23 +3354,23 @@ class YTUrlVideoTest(TestCase): def test_upload_materi_with_valid_yt_video_id(self): 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"} + "/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.assertTrue(Materi.objects.get(title="Materi 1")) - + def test_upload_materi_with_invalid_yt_video_id(self): self.client.login(**self.contributor_credential) self.client.post( - "/unggah/", data={"title":"Materi 2", "author":"Agas", "publisher":"Kelas SC", "release_year":"2000", - "descriptions":"Deskripsi Materi 1", 'categories':"1", - "cover":self.cover, "content":self.content, - "yt_video_id":"randomId"} + "/unggah/", data={"title": "Materi 2", "author": "Agas", "publisher": "Kelas SC", "release_year": "2000", + "descriptions": "Deskripsi Materi 1", 'categories': "1", + "cover": self.cover, "content": self.content, + "yt_video_id": "randomId"} ) self.assertEqual(Materi.objects.filter(title="Materi 2").count(), 0) - + def test_detail_materi_has_video_if_yt_video_id_not_empty(self): self.test_upload_materi_with_valid_yt_video_id() pk = Materi.objects.get(title="Materi 1").pk @@ -3241,20 +3381,23 @@ class YTUrlVideoTest(TestCase): def test_detail_materi_has_no_video_if_yt_video_id_empty(self): self.client.login(**self.contributor_credential) self.client.post( - "/unggah/", data={"title":"Materi 2", "author":"Agas", "publisher":"Kelas SC", "release_year":"2000", - "descriptions":"Deskripsi Materi 1", 'categories':"1", - "cover":self.cover, "content":self.content,} + "/unggah/", data={"title": "Materi 2", "author": "Agas", "publisher": "Kelas SC", "release_year": "2000", + "descriptions": "Deskripsi Materi 1", 'categories': "1", + "cover": self.cover, "content": self.content, } ) pk = Materi.objects.get(title="Materi 2").pk response = self.client.get("/materi/"+str(pk)+"/") html = response.content.decode("utf-8") self.assertNotIn("Video", html) + class ChangePasswordTest(TestCase): def setUp(self): self.client = Client() - self.kontributor = User.objects.create_contributor(email="kontributor@gov.id", password="kontributor") - self.admin = User.objects.create_admin(email="admin@gov.id", password="admin") + self.kontributor = User.objects.create_contributor( + email="kontributor@gov.id", password="kontributor") + self.admin = User.objects.create_admin( + email="admin@gov.id", password="admin") self.url = "/change-password/" self.view = PasswordChangeViews self.template_name = "change-password.html" @@ -3281,7 +3424,7 @@ class ChangePasswordTest(TestCase): # Logout self.client.logout() - + class SeeRatedMateriByUser(TestCase): def setUp(self): self.client = Client() @@ -3293,7 +3436,8 @@ class SeeRatedMateriByUser(TestCase): "email": "admin@gov.id", "password": id_generator() } - self.kontributor = User.objects.create_contributor(**self.contributor_credential) + self.kontributor = User.objects.create_contributor( + **self.contributor_credential) self.admin = User.objects.create_admin(**self.admin_credential) self.given_rating_url = "/given-rating/" @@ -3318,13 +3462,17 @@ class SeeRatedMateriByUser(TestCase): self.materi2 = Materi.objects.all()[1] self.materi3 = Materi.objects.all()[2] time.sleep(5) - self.rating_test_1 = Rating(materi=self.materi1, user=self.kontributor, score=5) + self.rating_test_1 = Rating( + materi=self.materi1, user=self.kontributor, score=5) time.sleep(5) - self.rating_test_2 = Rating(materi=self.materi2, user=self.kontributor, score=4) + self.rating_test_2 = Rating( + materi=self.materi2, user=self.kontributor, score=4) time.sleep(5) - self.rating_test_3 = Rating(materi=self.materi3, user=self.kontributor, score=3) + self.rating_test_3 = Rating( + materi=self.materi3, user=self.kontributor, score=3) time.sleep(5) - self.rating_test_4 = Rating(materi=self.materi3, user=self.admin, score=3) + self.rating_test_4 = Rating( + materi=self.materi3, user=self.admin, score=3) self.rating_test_1.save() self.rating_test_2.save() @@ -3364,12 +3512,14 @@ class SeeRatedMateriByUser(TestCase): self.assertNotIn(self.rating_test_4, response.context['rating_list']) def test_given_rating_page_no_rating_should_display_message(self): - user_credential = {"email": "user@mail.com", "password": id_generator()} + user_credential = {"email": "user@mail.com", + "password": id_generator()} User.objects.create_contributor(**user_credential) self.client.login(**user_credential) response = self.client.get(self.given_rating_url) self.assertEqual(len(response.context['rating_list']), 0) - self.assertIn("Anda belum pernah memberikan rating ke materi", response.content.decode("utf-8")) + self.assertIn("Anda belum pernah memberikan rating ke materi", + response.content.decode("utf-8")) self.assertNotIn(self.materi1.title, response.content.decode("utf-8")) def test_given_rating_page_order_should_give_default_parameter(self): @@ -3385,24 +3535,28 @@ class SeeRatedMateriByUser(TestCase): self.assertEqual(response.context['order_by_key'], 'timestamp') # No order_by parameter, should default to asc - response = self.client.get(self.given_rating_url + '?order_by_key=score') + response = self.client.get( + self.given_rating_url + '?order_by_key=score') self.assertEqual(response.context['order_by'], 'dsc') self.assertEqual(response.context['order_by_key'], 'score') # INVALID PARAMETERS # Starts with negative - response = self.client.get(self.given_rating_url + '?order_by_key=-score') + response = self.client.get( + self.given_rating_url + '?order_by_key=-score') self.assertEqual(response.context['order_by'], 'dsc') self.assertEqual(response.context['order_by_key'], 'score') # Invalid params - response = self.client.get(self.given_rating_url + '?order_by_key=halohalohalo&order=haihaihaihai') + response = self.client.get( + self.given_rating_url + '?order_by_key=halohalohalo&order=haihaihaihai') self.assertEqual(response.context['order_by'], 'dsc') self.assertEqual(response.context['order_by_key'], 'timestamp') def test_given_rating_page_order_ascending_should_be_correct(self): self.client.login(**self.contributor_credential) - response = self.client.get(self.given_rating_url + '?order_by_key=score&order=asc') + response = self.client.get( + self.given_rating_url + '?order_by_key=score&order=asc') # From Low to High # order key score @@ -3411,13 +3565,15 @@ class SeeRatedMateriByUser(TestCase): self.assertEqual(list(response.context['rating_list']), [self.rating_test_3, self.rating_test_2, self.rating_test_1]) # order key timestamp - response = self.client.get(self.given_rating_url + '?order_by_key=timestamp&order=asc') + response = self.client.get( + self.given_rating_url + '?order_by_key=timestamp&order=asc') self.assertEqual(response.context['order_by'], 'asc') self.assertEqual(response.context['order_by_key'], 'timestamp') self.assertEqual(list(response.context['rating_list']), [self.rating_test_1, self.rating_test_2, self.rating_test_3]) # order key materi title - response = self.client.get(self.given_rating_url + '?order_by_key=materi__title&order=asc') + response = self.client.get( + self.given_rating_url + '?order_by_key=materi__title&order=asc') self.assertEqual(response.context['order_by'], 'asc') self.assertEqual(response.context['order_by_key'], 'materi__title') self.assertEqual(list(response.context['rating_list']), @@ -3427,26 +3583,30 @@ class SeeRatedMateriByUser(TestCase): self.client.login(**self.contributor_credential) # From High to Low # order key score - response = self.client.get(self.given_rating_url + '?order_by_key=score&order=dsc') + response = self.client.get( + self.given_rating_url + '?order_by_key=score&order=dsc') self.assertEqual(response.context['order_by'], 'dsc') self.assertEqual(response.context['order_by_key'], 'score') self.assertEqual(list(response.context['rating_list']), [self.rating_test_1, self.rating_test_2, self.rating_test_3]) # order key timestamp - response = self.client.get(self.given_rating_url + '?order_by_key=timestamp&order=dsc') + response = self.client.get( + self.given_rating_url + '?order_by_key=timestamp&order=dsc') self.assertEqual(response.context['order_by'], 'dsc') self.assertEqual(response.context['order_by_key'], 'timestamp') self.assertEqual(list(response.context['rating_list']), [self.rating_test_3, self.rating_test_2, self.rating_test_1]) # order key materi title - response = self.client.get(self.given_rating_url + '?order_by_key=materi__title&order=dsc') + response = self.client.get( + self.given_rating_url + '?order_by_key=materi__title&order=dsc') self.assertEqual(response.context['order_by'], 'dsc') self.assertEqual(response.context['order_by_key'], 'materi__title') self.assertEqual(list(response.context['rating_list']), [self.rating_test_2, self.rating_test_1, self.rating_test_3]) + class PasswordValidatorPolicyTest(TestCase): def setUp(self): self.password_no_lowercase = "PASSW0RD!" @@ -3456,28 +3616,34 @@ class PasswordValidatorPolicyTest(TestCase): self.password_length_lower_than_8 = "P4ss!" self.password_enforcing_policy = "Passw0rd!" self.validator = PasswordPolicyValidator() - + def test_using_password_no_lowercase(self): - self.assertRaises(ValidationError, self.validator.validate, self.password_no_lowercase) + self.assertRaises( + ValidationError, self.validator.validate, self.password_no_lowercase) def test_using_password_no_upprcase(self): - self.assertRaises(ValidationError, self.validator.validate, self.password_no_uppercase) - + self.assertRaises( + ValidationError, self.validator.validate, self.password_no_uppercase) + def test_using_password_no_digit(self): - self.assertRaises(ValidationError, self.validator.validate, self.password_no_digit) + self.assertRaises( + ValidationError, self.validator.validate, self.password_no_digit) def test_using_password_no_special_char(self): - self.assertRaises(ValidationError, self.validator.validate, self.password_no_special_char) - + self.assertRaises(ValidationError, self.validator.validate, + self.password_no_special_char) + def test_using_password_with_length_less_than_8(self): - self.assertRaises(ValidationError, self.validator.validate, self.password_length_lower_than_8) - + self.assertRaises(ValidationError, self.validator.validate, + self.password_length_lower_than_8) + def test_using_password_using_correct_policy(self): - self.assertEquals(self.validator.validate(self.password_enforcing_policy), None) - + self.assertEquals(self.validator.validate( + self.password_enforcing_policy), None) + class LandingPageNavbarTest(TestCase): - + def setUp(self): self.client = Client() self.contributor_credential = { @@ -3492,62 +3658,95 @@ class LandingPageNavbarTest(TestCase): "email": "public@gov.id", "password": id_generator() } - self.kontributor = User.objects.create_contributor(**self.contributor_credential) + self.kontributor = User.objects.create_contributor( + **self.contributor_credential) self.admin = User.objects.create_admin(**self.admin_credential) self.public = User.objects.create_user(**self.public_credential) def test_navbar_admin(self): self.client.login(**self.admin_credential) response = self.client.get('/') - self.assertContains(response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') - self.assertContains(response, '<a class="nav-link" href="/forum">Forum</a>') - self.assertContains(response, '<a class="nav-link" href="/news/all">Berita</a>') - self.assertContains(response, '<a class="nav-link" href="/profil">Profil</a>') - self.assertContains(response, '<a class="nav-link" href="/logout">Logout</a>') - self.assertContains(response, '<a class="nav-link" href="/administration">Administrasi</a>') - self.assertNotContains(response, '<a class="nav-link" href="/dashboard">Dasbor</a>') + self.assertContains( + response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') + self.assertContains( + response, '<a class="nav-link" href="/forum">Forum</a>') + self.assertContains( + response, '<a class="nav-link" href="/news/all">Berita</a>') + self.assertContains( + response, '<a class="nav-link" href="/profil">Profil</a>') + self.assertContains( + response, '<a class="nav-link" href="/logout">Logout</a>') + self.assertContains( + response, '<a class="nav-link" href="/administration">Administrasi</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/dashboard">Dasbor</a>') def test_navbar_contributor(self): self.client.login(**self.contributor_credential) response = self.client.get('/') - self.assertContains(response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') - self.assertContains(response, '<a class="nav-link" href="/forum">Forum</a>') - self.assertContains(response, '<a class="nav-link" href="/news/all">Berita</a>') - self.assertContains(response, '<a class="nav-link" href="/profil">Profil</a>') - self.assertContains(response, '<a class="nav-link" href="/logout">Logout</a>') - self.assertContains(response, '<a class="nav-link" href="/dashboard">Dasbor</a>') - self.assertNotContains(response, '<a class="nav-link" href="/administration">Administrasi</a>') + self.assertContains( + response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') + self.assertContains( + response, '<a class="nav-link" href="/forum">Forum</a>') + self.assertContains( + response, '<a class="nav-link" href="/news/all">Berita</a>') + self.assertContains( + response, '<a class="nav-link" href="/profil">Profil</a>') + self.assertContains( + response, '<a class="nav-link" href="/logout">Logout</a>') + self.assertContains( + response, '<a class="nav-link" href="/dashboard">Dasbor</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/administration">Administrasi</a>') def test_navbar_public(self): self.client.login(**self.public_credential) response = self.client.get('/') - self.assertContains(response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') - self.assertContains(response, '<a class="nav-link" href="/forum">Forum</a>') - self.assertContains(response, '<a class="nav-link" href="/news/all">Berita</a>') - self.assertContains(response, '<a class="nav-link" href="/profil">Profil</a>') - self.assertContains(response, '<a class="nav-link" href="/logout">Logout</a>') - self.assertNotContains(response, '<a class="nav-link" href="/dashboard">Dasbor</a>') - self.assertNotContains(response, '<a class="nav-link" href="/administration">Administrasi</a>') + self.assertContains( + response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') + self.assertContains( + response, '<a class="nav-link" href="/forum">Forum</a>') + self.assertContains( + response, '<a class="nav-link" href="/news/all">Berita</a>') + self.assertContains( + response, '<a class="nav-link" href="/profil">Profil</a>') + self.assertContains( + response, '<a class="nav-link" href="/logout">Logout</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/dashboard">Dasbor</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/administration">Administrasi</a>') def test_navbar_anonymous(self): response = self.client.get('/') - self.assertContains(response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') - self.assertContains(response, '<a class="nav-link" href="/forum">Forum</a>') - self.assertContains(response, '<a class="nav-link" href="/news/all">Berita</a>') + self.assertContains( + response, '<a class="sidebar-brand-text navbar-brand" href="/">Digipus</a>') + self.assertContains( + response, '<a class="nav-link" href="/forum">Forum</a>') + self.assertContains( + response, '<a class="nav-link" href="/news/all">Berita</a>') self.assertContains( response, '<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">' ) self.assertContains(response, 'Registrasi</a>') - self.assertContains(response, '<a class="dropdown-item" href="/registrasi/umum">Umum</a>') - self.assertContains(response, '<a class="dropdown-item" href="/registrasi">Kontributor</a>') + self.assertContains( + response, '<a class="dropdown-item" href="/registrasi/umum">Umum</a>') + self.assertContains( + response, '<a class="dropdown-item" href="/registrasi">Kontributor</a>') self.assertContains(response, 'Login</a>') - self.assertContains(response, '<a class="dropdown-item" href="/login">Kontributor</a>') - self.assertContains(response, '<a class="dropdown-item" href="/login_admin">Admin</a>') - self.assertNotContains(response, '<a class="nav-link" href="/profil">Profil</a>') - self.assertNotContains(response, '<a class="nav-link" href="/logout">Logout</a>') - self.assertNotContains(response, '<a class="nav-link" href="/dashboard">Dasbor</a>') - self.assertNotContains(response, '<a class="nav-link" href="/administration">Administrasi</a>') + self.assertContains( + response, '<a class="dropdown-item" href="/login">Kontributor</a>') + self.assertContains( + response, '<a class="dropdown-item" href="/login_admin">Admin</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/profil">Profil</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/logout">Logout</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/dashboard">Dasbor</a>') + self.assertNotContains( + response, '<a class="nav-link" href="/administration">Administrasi</a>') class MateriRecommendationTest(TestCase): @@ -3607,7 +3806,8 @@ class MateriRecommendationTest(TestCase): ) response = Client().get("/?recommendation=1") - list = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", response.content.decode())] + list = [int(id) for id in re.findall( + r"Materi\s(\d+)[^\d]", response.content.decode())] self.assertEqual(list, [2, 1, 3]) def test_set_date_as_tiebreak_if_like_counts_is_same(self): @@ -3644,10 +3844,50 @@ class MateriRecommendationTest(TestCase): Like.objects.create(materi=materi1) response = Client().get("/?recommendation=1") - list = [int(id) for id in re.findall(r"Materi\s(\d+)[^\d]", response.content.decode())] + list = [int(id) for id in re.findall( + r"Materi\s(\d+)[^\d]", response.content.decode())] self.assertEqual(list, [1, 2]) +class GuestBookTest(TestCase): + def test_form_name_input_has_placeholder_and_css_classes(self): + form = GuestBookForm() + self.assertIn('placeholder="Input your name"', form.as_p()) + self.assertIn('class="form-control input-lg"', form.as_p()) + + def test_form_job_input_has_placeholder_and_css_classes(self): + form = GuestBookForm() + self.assertIn('placeholder="Input your job"', form.as_p()) + self.assertIn('class="form-control input-lg"', form.as_p()) + + def test_form_gender_input_has_choices_and_css_classes(self): + form = GuestBookForm() + self.assertIn('option value="Male"', form.as_p()) + self.assertIn('option value="Female">', form.as_p()) + self.assertIn('class="form-control input-lg"', form.as_p()) + + def test_form_validation_for_blank_items(self): + form = GuestBookForm(data={'name': '', 'job': '', 'gender': ''}) + self.assertFalse(form.is_valid()) + self.assertEqual( + form.errors['name'], + ['Name is required'] + ) + self.assertEqual( + form.errors['job'], + ['Job is required'] + ) + self.assertEqual( + form.errors['gender'], + ['Gender is required'] + ) + + def test_can_create_guest_book_instance(self): + guestBook = GuestBook(name='Selvy', job='Student', gender='Female') + guestBook.save() + self.assertEqual(GuestBook.objects.count(), 1) + + class MateriSearchVectorTest(TestCase): def setUp(self): Materi.SEARCH_INDEX = (("title", "A"), ("author", "B")) @@ -3663,7 +3903,8 @@ class MateriSearchVectorTest(TestCase): self.assertGreaterEqual(len(search_vector_string.split(",")), 1) def test_search_vector_based_on_indexed_attribute(self): - materi = Materi(title="Buku 1", author="Pembuat 1", descriptions="Deskripsi 1") + materi = Materi(title="Buku 1", author="Pembuat 1", + descriptions="Deskripsi 1") materi.save() search_vector_string = list( @@ -3673,7 +3914,8 @@ class MateriSearchVectorTest(TestCase): self.assertIn("pembuat", search_vector_string) def test_search_vector_not_based_on_unindexed_attribute(self): - materi = Materi(title="Buku 1", author="Pembuat 1", descriptions="Deskripsi 1") + materi = Materi(title="Buku 1", author="Pembuat 1", + descriptions="Deskripsi 1") materi.save() search_vector_string = list( @@ -3686,12 +3928,14 @@ class MateriSearchVectorTest(TestCase): materi = Materi(title="Sebelum reconstruct") materi.save() - search_vector = list(Materi.objects.values_list("_search_vector", flat=True))[0] + search_vector = list(Materi.objects.values_list( + "_search_vector", flat=True))[0] materi.title = "Setelah reconstruct" materi.save() - search_vector = list(Materi.objects.values_list("_search_vector", flat=True))[0] + search_vector = list(Materi.objects.values_list( + "_search_vector", flat=True))[0] self.assertIn("setelah", search_vector) @@ -3699,12 +3943,14 @@ class MateriSearchVectorTest(TestCase): materi = Materi(descriptions="sebelum reconstruct") materi.save() - search_vector = list(Materi.objects.values_list("_search_vector", flat=True))[0] + search_vector = list(Materi.objects.values_list( + "_search_vector", flat=True))[0] materi.descriptions = "sebelum reconstruct" materi.save() - search_vector = list(Materi.objects.values_list("_search_vector", flat=True))[0] + search_vector = list(Materi.objects.values_list( + "_search_vector", flat=True))[0] self.assertNotIn("setelah", search_vector) @@ -3743,7 +3989,8 @@ class MateriSearchTest(TestCase): materi_2 = Materi(descriptions="ini lumayan cocok lumayan cocok") materi_2.save() - materi_1 = Materi(descriptions="ini sangat cocok sangat cocok sangat cocok") + materi_1 = Materi( + descriptions="ini sangat cocok sangat cocok sangat cocok") materi_1.save() materi_4 = Materi(descriptions="ini tidak") @@ -3809,8 +4056,10 @@ class BacaNantiTest(TestCase): self.contributor = get_user_model().objects.create_user( **self.contributor_credential, name="Kontributor", is_contributor=True ) - self.user_one = get_user_model().objects.create_user(**self.user_one_credential, name="User One") - self.user_two = get_user_model().objects.create_user(**self.user_two_credential, name="User Two") + self.user_one = get_user_model().objects.create_user( + **self.user_one_credential, name="User One") + self.user_two = get_user_model().objects.create_user( + **self.user_two_credential, name="User Two") self.cover = SimpleUploadedFile( "cover.jpg", b"Test file" @@ -3846,7 +4095,7 @@ class BacaNantiTest(TestCase): self.assertEqual(read_later_one.user, self.user_one) self.assertEqual(read_later_two.materi, self.materi1) self.assertEqual(read_later_two.user, self.user_two) - + def test_readlater_user_must_not_unique(self): ReadLater(materi=self.materi1, user=self.user_one).save() ReadLater(materi=self.materi2, user=self.user_one).save() @@ -3870,7 +4119,7 @@ class BacaNantiTest(TestCase): def test_readlater_user_cant_null(self): with self.assertRaises(IntegrityError): ReadLater(materi=self.materi1).save() - + def test_readlater_profile_page_url_exist(self): self.client.login(**self.user_one_credential) response = self.client.get(self.url) @@ -3879,30 +4128,35 @@ class BacaNantiTest(TestCase): def test_readlater_profile_page_using_template(self): self.client.login(**self.user_one_credential) response = self.client.get(self.url) - self.assertTemplateUsed(response=response, template_name="baca-nanti.html") - + self.assertTemplateUsed( + response=response, template_name="baca-nanti.html") + def test_toggle_readlater_url_exist(self): self.client.login(**self.user_one_credential) - response = self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) + response = self.client.post( + self.toggle_url, {'materi_id': self.materi1.id}) self.assertEqual(response.status_code, 200) def test_checking_readlater_in_materi_create_object(self): self.client.login(**self.user_one_credential) self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) - read_later_exist = ReadLater.objects.filter(materi=self.materi1, user=self.user_one).exists() + read_later_exist = ReadLater.objects.filter( + materi=self.materi1, user=self.user_one).exists() self.assertEqual(read_later_exist, True) - + def test_unchecking_readlater_in_materi_delete_object(self): self.client.login(**self.user_one_credential) self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) sleep(1) self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) - read_later_exist = ReadLater.objects.filter(materi=self.materi1, user=self.user_one).exists() + read_later_exist = ReadLater.objects.filter( + materi=self.materi1, user=self.user_one).exists() self.assertEqual(read_later_exist, False) def test_checking_readlater_in_materi_with_complete_paramater_return_success(self): self.client.login(**self.user_one_credential) - response = self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) + response = self.client.post( + self.toggle_url, {'materi_id': self.materi1.id}) self.assertJSONEqual( str(response.content, encoding='utf-8'), {"success": True, "read_later_checked": True} @@ -3912,20 +4166,22 @@ class BacaNantiTest(TestCase): self.client.login(**self.user_one_credential) self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) sleep(1) - response = self.client.post(self.toggle_url, {'materi_id': self.materi1.id}) + response = self.client.post( + self.toggle_url, {'materi_id': self.materi1.id}) self.assertJSONEqual( str(response.content, encoding='utf-8'), {"success": True, "read_later_checked": False} ) - + def test_toggle_readlater_return_if_method_snot_post(self): self.client.login(**self.user_one_credential) - response = self.client.get(self.toggle_url, {'materi_id': self.materi1.id}) + response = self.client.get( + self.toggle_url, {'materi_id': self.materi1.id}) self.assertJSONEqual( str(response.content, encoding='utf-8'), {"success": False, "msg": "Unsuported method"} ) - + def test_toggle_readlater_return_if_paramater_materi_id_not_found(self): self.client.login(**self.user_one_credential) response = self.client.post(self.toggle_url) @@ -3934,19 +4190,21 @@ class BacaNantiTest(TestCase): {"success": False, "msg": "Missing parameter"} ) + class MateriStatsTest(TestCase): def setUp(self): self.credential = { - 'email':"kontributor@gov.id", - 'password':"P@ssw0rd", + 'email': "kontributor@gov.id", + 'password': "P@ssw0rd", } self.path = '/stats/' self.path_json = '/stats/?data=json' self.header = 'Summary Materi per Kategori' - self.contributor = User.objects.create_contributor(**self.credential, name="kontributor") + self.contributor = User.objects.create_contributor( + **self.credential, name="kontributor") self.client = Client() categories = [] @@ -3962,7 +4220,6 @@ class MateriStatsTest(TestCase): m.categories.add(categories[i]) m.save() - def test_stats_has_correct_template(self): self.client.login(**self.credential) response = self.client.get(self.path) @@ -3975,9 +4232,9 @@ class MateriStatsTest(TestCase): def test_stats_as_anonymous(self): response = self.client.get(self.path) - self.assertEqual(response.status_code, 302) #redirect + self.assertEqual(response.status_code, 302) # redirect response = self.client.get(self.path_json) - self.assertEqual(response.status_code, 302) #redirect + self.assertEqual(response.status_code, 302) # redirect def test_stats_api_correct_data(self): self.client.login(**self.credential) @@ -3992,9 +4249,9 @@ class UploadMateriTest(TestCase): password="kontributor", is_contributor=True) self.setUpImage() self.content = SimpleUploadedFile("ExampleFile221.pdf", b"Test file") - self.category = Category.objects.create(id="1", name="sains", description="kategori sains") - - + self.category = Category.objects.create( + id="1", name="sains", description="kategori sains") + @override_settings(MEDIA_ROOT=tempfile.gettempdir()) def setUpImage(self): self.cover = InMemoryUploadedFile( @@ -4016,10 +4273,10 @@ class UploadMateriTest(TestCase): self.client.login(email="kontributor@gov.id", password="kontributor") - data = {"title":"Dunia Binatang", "author":"Parzival", "publisher":"Buku Asyik", - "release_year":"2015", "descriptions":"Buku dunia binatang seri 1", - 'categories':"1", "cover":self.cover, "content":self.content} - + data = {"title": "Dunia Binatang", "author": "Parzival", "publisher": "Buku Asyik", + "release_year": "2015", "descriptions": "Buku dunia binatang seri 1", + 'categories': "1", "cover": self.cover, "content": self.content} + self.client.post("/unggah/", data=data) self.assertEqual(Materi.objects.count(), 1) diff --git a/app/urls.py b/app/urls.py index f89a0602819e3fcfc560e1a73d602edd0a439e04..fb1e0e927cfe413948fbf74502277c0c6d6859fe 100644 --- a/app/urls.py +++ b/app/urls.py @@ -5,8 +5,7 @@ from app import views from app.views import (DashboardKontributorView, ProfilView, StatisticsView, SuksesLoginAdminView, SuksesLoginKontributorView, DownloadHistoryView, SuntingProfilView, UploadMateriHTML, UploadMateriView, UploadMateriExcelView, PostsView, - ReqMateriView, KatalogPerKontributorView, MateriFavorite, PasswordChangeViews, password_success, - SubmitVisitorView, ReadLaterView, MostContributor) + ReqMateriView, KatalogPerKontributorView, MateriFavorite, PasswordChangeViews, password_success, SubmitVisitorView, GuestBookView, ReadLaterView, MostContributor) urlpatterns = [ @@ -18,13 +17,16 @@ urlpatterns = [ path("review/delete/<int:pk_materi>/<int:pk_review>", views.delete_review, name="delete-review"), path("comment/like/", views.toggle_like_comment, name="comment-like-toggle"), - path("comment/dislike/", views.toggle_dislike_comment, name="comment-dislike-toggle"), + path("comment/dislike/", views.toggle_dislike_comment, + name="comment-dislike-toggle"), path("materi/<int:pk>/delete", views.delete_materi, name="detele-materi"), path("materi/<int:pk>/unduh", views.download_materi, name="download-materi"), path("materi/<int:pk>/view", views.view_materi, name="view-materi"), path("dashboard/", DashboardKontributorView.as_view(), name="dashboard"), - path("download-history/", DownloadHistoryView.as_view(), name="download-history"), - path("revisi/materi/<int:pk>/", views.RevisiMateriView.as_view(), name="revisi"), + path("download-history/", DownloadHistoryView.as_view(), + name="download-history"), + path("revisi/materi/<int:pk>/", + views.RevisiMateriView.as_view(), name="revisi"), path("unggah/", UploadMateriView.as_view(), name="unggah"), path("unggah_excel/", UploadMateriExcelView.as_view(), name="unggah_excel"), path("profil/", ProfilView.as_view(), name="profil"), @@ -38,26 +40,33 @@ urlpatterns = [ path("profil/<str:email>/", KatalogPerKontributorView.as_view(), name="katalog-per-kontributor"), path("materi/rate/", views.add_rating_materi, name="rate-materi"), - path("materi/<int:pk>/save-to-gdrive/", views.save_to_gdrive, name="save-to-gdrive"), + path("materi/<int:pk>/save-to-gdrive/", + views.save_to_gdrive, name="save-to-gdrive"), path("favorite/", MateriFavorite.as_view(), name="favorite"), - path("change-password/", PasswordChangeViews.as_view(template_name='change-password.html')), + path("change-password/", + PasswordChangeViews.as_view(template_name='change-password.html')), path("password_success/", views.password_success, name="password_success"), path("given-rating/", views.see_given_rating, name="see_given_rating"), path("submit-visitor/", SubmitVisitorView.as_view(), name="submit-visitor"), path("baca-nanti/", ReadLaterView.as_view(), name="read-later"), path("baca-nanti-toggle/", views.toggle_readlater, name="toggle-read-later"), path("stats/", StatisticsView.as_view(), name="stats"), - path("reset_password/", - auth_views.PasswordResetView.as_view(template_name="password_reset.html"), - name="reset_password"), - path("reset_password_sent/", - auth_views.PasswordResetDoneView.as_view(template_name="password_reset_sent.html"), - name="password_reset_done"), - path("reset/<uidb64>/<token>/", - auth_views.PasswordResetConfirmView.as_view(template_name="password_reset_form.html"), - name="password_reset_confirm"), - path("reset_password_complete/", - auth_views.PasswordResetCompleteView.as_view(template_name="password_reset_done.html"), - name="password_reset_complete"), - path("most-contributor/", MostContributor.as_view(), name="most-contributor") + path("reset_password/", + auth_views.PasswordResetView.as_view( + template_name="password_reset.html"), + name="reset_password"), + path("reset_password_sent/", + auth_views.PasswordResetDoneView.as_view( + template_name="password_reset_sent.html"), + name="password_reset_done"), + path("reset/<uidb64>/<token>/", + auth_views.PasswordResetConfirmView.as_view( + template_name="password_reset_form.html"), + name="password_reset_confirm"), + path("reset_password_complete/", + auth_views.PasswordResetCompleteView.as_view( + template_name="password_reset_done.html"), + name="password_reset_complete"), + path("most-contributor/", MostContributor.as_view(), name="most-contributor"), + path("guest-book/", GuestBookView.as_view(), name="guest-book") ] diff --git a/app/views.py b/app/views.py index 12bbc08ca1ad98d48615e56838d8bd99cca6b92e..1d831a6019cd4e655a8105cf694370d4ef23ccd8 100644 --- a/app/views.py +++ b/app/views.py @@ -24,7 +24,7 @@ from django.urls import reverse_lazy from django.views import defaults from django.views.generic import TemplateView -from app.forms import SuntingProfilForm, UploadMateriForm, RatingContributorForm +from app.forms import SuntingProfilForm, UploadMateriForm, RatingContributorForm, GuestBookForm from app.models import ( Category, Comment, @@ -34,6 +34,7 @@ from app.models import ( ReqMaterial, Rating, RatingContributor, SubmitVisitor, + GuestBook, ReadLater, NotifikasiKontributor, AdminNotification @@ -51,6 +52,7 @@ UNGGAH_URL = "/unggah/" UNGGAH_EXCEL_URL = "/unggah_excel/" LOGIN_URL = "/login/" + def permission_denied(request, exception, template_name="error_403.html"): return defaults.permission_denied(request, exception, template_name) @@ -66,11 +68,12 @@ class DaftarKatalog(TemplateView): context = self.get_context_data(**kwargs) context["kategori_list"] = Category.objects.all() - lst_materi = Materi.objects.filter(status="APPROVE").order_by("date_modified") + lst_materi = Materi.objects.filter( + status="APPROVE").order_by("date_modified") url = "" - lst_materi, url = DafterKatalogService.apply_options(lst_materi, request, url) - + lst_materi, url = DafterKatalogService.apply_options( + lst_materi, request, url) context["materi_list"] = lst_materi paginator = Paginator(context["materi_list"], 15) @@ -105,14 +108,16 @@ class KatalogPerKontributorView(TemplateView): contributor = context["contributor"] context["form_rating"] = RatingContributorForm(initial={ "contributor": contributor, - "user":request.user + "user": request.user }) context["avg_rating"] = User.objects.filter(email=kwargs["email"]) \ .annotate(avg_rating=Avg("contributor__score"))[0] - context["count_rating"] = RatingContributor.objects.filter(contributor=contributor).count() + context["count_rating"] = RatingContributor.objects.filter( + contributor=contributor).count() if request.user.is_authenticated: - has_rated = RatingContributor.objects.filter(user=request.user, contributor=contributor).exists() + has_rated = RatingContributor.objects.filter( + user=request.user, contributor=contributor).exists() context["has_rated"] = has_rated return self.render_to_response(context=context) @@ -126,7 +131,7 @@ class KatalogPerKontributorView(TemplateView): is_update = request.POST.get('update', None) if is_delete: rating_contributor = get_object_or_404( - RatingContributor, + RatingContributor, user=request.user, contributor=context["contributor"] ) @@ -137,7 +142,7 @@ class KatalogPerKontributorView(TemplateView): user=request.user, contributor=context["contributor"] ).first() - + if rating and score: rating.score = int(score) rating.save() @@ -145,9 +150,10 @@ class KatalogPerKontributorView(TemplateView): data = RatingContributorForm(request.POST) if data.is_valid(): data.save() - + return redirect("katalog-per-kontributor", email=kwargs["email"]) + class DetailMateri(TemplateView): template_name = "app/detail_materi.html" @@ -156,17 +162,21 @@ class DetailMateri(TemplateView): if not self.request.session or not self.request.session.session_key: self.request.session.save() materi = get_object_or_404(Materi, pk=kwargs["pk"]) - DetailMateriService.init_context_data(context, materi, self.request.session) + DetailMateriService.init_context_data( + context, materi, self.request.session) published_date = DetailMateriService.set_published_date(materi) - DetailMateriService.init_citation_and_materi_rating(context, materi, published_date, self.request) + DetailMateriService.init_citation_and_materi_rating( + context, materi, published_date, self.request) DetailMateriService.init_materi_download_count(context, materi) if self.request.user.is_authenticated: - materi_rating = Rating.objects.filter(materi=materi, user=self.request.user).first() + materi_rating = Rating.objects.filter( + materi=materi, user=self.request.user).first() if materi_rating is not None: context['materi_rating_score'] = materi_rating.score - materi_read_later = ReadLater.objects.filter(materi=materi, user=self.request.user).first() + materi_read_later = ReadLater.objects.filter( + materi=materi, user=self.request.user).first() if materi_read_later is not None: context['is_in_read_later_list'] = True else: @@ -176,12 +186,14 @@ class DetailMateri(TemplateView): return context - def get(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) - query_set_for_comment = Comment.objects.filter(materi=context["materi_data"]) - query_set_for_review = Review.objects.filter(materi=context["materi_data"]) - has_disliked, has_liked = DetailMateriService.find_comment_like_dislike(query_set_for_comment, self.request.session) + query_set_for_comment = Comment.objects.filter( + materi=context["materi_data"]) + query_set_for_review = Review.objects.filter( + materi=context["materi_data"]) + has_disliked, has_liked = DetailMateriService.find_comment_like_dislike( + query_set_for_comment, self.request.session) context["comment_data"] = query_set_for_comment context["review_data"] = query_set_for_review context["has_liked_comment"] = has_liked @@ -191,45 +203,45 @@ class DetailMateri(TemplateView): opened_notif.delete() return self.render_to_response(context=context) - - def post(self, request, *args, **kwargs): comment_text = request.POST.get("comment", None) - review_text = request.POST.get("review", None) + review_text = request.POST.get("review", None) report_text = request.POST.get("report", None) - if ((comment_text == None or comment_text == "" ) and \ - (review_text == None or review_text == "") and \ - (report_text == None or report_text == "")): + if ((comment_text == None or comment_text == "") and + (review_text == None or review_text == "") and + (report_text == None or report_text == "")): context = self.get_context_data(*args, **kwargs) context["error_message"] = "Anda belum menuliskan komentar" context["materi_data"] = get_object_or_404(Materi, pk=kwargs["pk"]) - query_set_for_comment = Comment.objects.filter(materi=context["materi_data"]) + query_set_for_comment = Comment.objects.filter( + materi=context["materi_data"]) context["comment_data"] = query_set_for_comment - query_set_for_review = Review.objects.filter(materi=context["materi_data"]) + query_set_for_review = Review.objects.filter( + materi=context["materi_data"]) context["review_data"] = query_set_for_review return self.render_to_response(context=context) materi = get_object_or_404(Materi, pk=kwargs["pk"]) user_obj = request.user if request.user.is_authenticated else None if user_obj: - if (comment_text != None ): + if (comment_text != None): comment = Comment.objects.create( comment=comment_text, username=DetailMateriService.get_user_name(request), materi=materi, user=user_obj ) comment.save() materi_uploader = materi.uploader if materi_uploader.is_subscribing_to_material_comments and user_obj.email != materi_uploader.email: - email_content = f'User dengan email {user_obj.email} ' + \ + email_content = f'User dengan email {user_obj.email} ' + \ f'menambahkan komentar pada materi Anda dengan judul "{materi.title}".' + \ f'\nKomentar: "{comment.comment}".\n' + \ f'Silahkan akses halaman detail materi untuk berinteraksi lebih lanjut.' MailService.send( - subject = 'DIGIPUS: Komentar Baru pada Materi Anda', - message = email_content, - from_email = getattr(settings, 'EMAIL_HOST_USER'), - recipient_list = [materi_uploader.email,], - ) + subject='DIGIPUS: Komentar Baru pada Materi Anda', + message=email_content, + from_email=getattr(settings, 'EMAIL_HOST_USER'), + recipient_list=[materi_uploader.email, ], + ) elif (review_text != None): review = Review.objects.create( review=review_text, username=DetailMateriService.get_user_name(request), materi=materi, user=user_obj @@ -299,17 +311,16 @@ def add_rating_materi(request): materi_id = request.POST.get("materi_id", None) rating_score = request.POST.get("rating_score", None) - is_valid_params, materi_id, \ - rating_score, response, \ - status_code = MateriFieldValidationHelperService.\ - validate_materi_rating_params(materi_id,rating_score) + rating_score, response, \ + status_code = MateriFieldValidationHelperService.\ + validate_materi_rating_params(materi_id, rating_score) if not is_valid_params: return JsonResponse(response, status=status_code) is_valid_rating, materi, \ - response, status_code = MateriFieldValidationHelperService.\ + response, status_code = MateriFieldValidationHelperService.\ validate_materi_rating(materi_id, request.user) if not is_valid_rating: @@ -322,7 +333,6 @@ def add_rating_materi(request): return JsonResponse({"success": False, "msg": "Forbidden"}, status=403) - def download_materi(request, pk): materi = get_object_or_404(Materi, pk=pk) path = materi.content.path @@ -349,7 +359,8 @@ def view_materi(request, pk): try: with open(file_path, "rb") as fh: response = HttpResponse(fh.read(), content_type=mimetype[0]) - DownloadViewMateriHelperService.build_view_materi_response(file_path, materi, response) + DownloadViewMateriHelperService.build_view_materi_response( + file_path, materi, response) return response except Exception: raise Http404(FILE_NOT_FOUND_MESSAGE) @@ -365,6 +376,7 @@ def delete_materi(request, pk): materi.delete() return HttpResponseRedirect("/dashboard/") + class UploadMateriView(TemplateView): template_name = UNGGAH_HTML context = {} @@ -386,7 +398,8 @@ class UploadMateriView(TemplateView): if not UploadMateriService.validate_file_extension(konten, request, yt_url_id): return HttpResponseRedirect(UNGGAH_URL) UploadMateriService.upload_materi(form, materi) - messages.success(request, "Materi berhasil diunggah, periksa riwayat unggah anda") + messages.success( + request, "Materi berhasil diunggah, periksa riwayat unggah anda") return HttpResponseRedirect(UNGGAH_URL) else: context = self.get_context_data(**kwargs) @@ -394,8 +407,6 @@ class UploadMateriView(TemplateView): messages.error(request, "Terjadi kesalahan pada pengisian data") return self.render_to_response(context) - - def get(self, request, *args, **kwargs): if request.user.is_authenticated == False or not request.user.is_contributor: raise PermissionDenied(request) @@ -424,11 +435,14 @@ class UploadMateriExcelView(TemplateView): if "template" in self.request.GET: data_frame = pd.DataFrame( - {"Title": [], "Author": [], "Publisher": [], "Categories": [], "Description": [],} + {"Title": [], "Author": [], "Publisher": [], + "Categories": [], "Description": [], } ) + # pylint: disable=abstract-class-instantiated with BytesIO() as b: - writer = pd.ExcelWriter(b, engine="xlsxwriter") # pylint: disable=abstract-class-instantiated + writer = pd.ExcelWriter( + b, engine="xlsxwriter") data_frame.to_excel(writer, index=0) writer.save() response = HttpResponse( @@ -462,9 +476,11 @@ class UploadMateriExcelView(TemplateView): for i in range(row): # Validate Categories - message = UploadMateriService.validate_excel_categories(categories, excel, i, message) + message = UploadMateriService.validate_excel_categories( + categories, excel, i, message) - message = UploadMateriService.validate_excel_field_length(excel, field_length, i, message) + message = UploadMateriService.validate_excel_field_length( + excel, field_length, i, message) if message != None: break @@ -475,15 +491,14 @@ class UploadMateriExcelView(TemplateView): # Second pass, save data with django.db.transaction.atomic(): - UploadMateriService.upload_materi_excel(categories, excel, request, row) + UploadMateriService.upload_materi_excel( + categories, excel, request, row) messages.success(request, "Materi berhasil diunggah") return HttpResponseRedirect(UNGGAH_EXCEL_URL) - - class DashboardKontributorView(TemplateView): template_name = "dashboard.html" @@ -493,7 +508,8 @@ class DashboardKontributorView(TemplateView): return super(DashboardKontributorView, self).dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): - context = super(DashboardKontributorView, self).get_context_data(**kwargs) + context = super(DashboardKontributorView, + self).get_context_data(**kwargs) return context def get(self, request, *args, **kwargs): @@ -540,13 +556,15 @@ class SuntingProfilView(TemplateView): current_user = self.request.user - form = SuntingProfilForm(request.POST, request.FILES, instance=current_user) + form = SuntingProfilForm( + request.POST, request.FILES, instance=current_user) if form.is_valid(): current_user.default_profile_picture = True # Removing exifdata from profile picture on upload if request.FILES: - EditProfileService.update_profile_picture(current_user, request) + EditProfileService.update_profile_picture( + current_user, request) else: form.save() return HttpResponseRedirect("/profil/") @@ -590,7 +608,8 @@ class SuksesLoginKontributorView(TemplateView): return super(SuksesLoginKontributorView, self).dispatch(request, *args, **kwargs) def get_context_data(self, **kwargs): - context = super(SuksesLoginKontributorView, self).get_context_data(**kwargs) + context = super(SuksesLoginKontributorView, + self).get_context_data(**kwargs) return context def get(self, request, *args, **kwargs): @@ -643,9 +662,11 @@ class PostsView(TemplateView): user = self.request.user posts = Materi.objects.filter(uploader=user).order_by("-date_created") - posts_data = {post.id: {"data": post, "comments": []} for post in posts} + posts_data = {post.id: {"data": post, "comments": []} + for post in posts} - comments = Comment.objects.filter(materi__id__in=posts_data.keys()).order_by("-timestamp") + comments = Comment.objects.filter( + materi__id__in=posts_data.keys()).order_by("-timestamp") for comment in comments: posts_data[comment.materi.id]["comments"].append(comment) @@ -680,7 +701,8 @@ class RevisiMateriView(TemplateView): raise PermissionDenied(request) current_materi = get_object_or_404(Materi, pk=kwargs["pk"]) - form = UploadMateriForm(request.POST, request.FILES, instance=current_materi) + form = UploadMateriForm( + request.POST, request.FILES, instance=current_materi) if form.is_valid(): RevisiMateriService.revisi_materi(form, request) return HttpResponseRedirect("/dashboard/") @@ -717,7 +739,8 @@ class DownloadHistoryView(TemplateView): context = self.get_context_data(**kwargs) if request.user.is_authenticated: current_user = self.request.user - DownloadHistoryService.init_data_authenticated_user(context, current_user) + DownloadHistoryService.init_data_authenticated_user( + context, current_user) else: DownloadHistoryService.init_data_guest_user(context, request) return self.render_to_response(context) @@ -734,6 +757,7 @@ def save_to_gdrive(request, pk): return HttpResponseRedirect(reverse('detail-materi', kwargs={'pk': pk})) + class MateriFavorite(TemplateView): template_name = "user_favorite_materi.html" @@ -748,7 +772,7 @@ class MateriFavorite(TemplateView): user = self.request.user materi = Materi.objects.filter(like=True) - likes_data = { mat.id: { "data": mat, "comments": [] } for mat in materi } + likes_data = {mat.id: {"data": mat, "comments": []} for mat in materi} comments = Comment.objects \ .filter(materi__id__in=likes_data.keys()) \ @@ -762,11 +786,13 @@ class MateriFavorite(TemplateView): return self.render_to_response(context=context) + class PasswordChangeViews(PasswordChangeView): from_class = PasswordChangeForm success_url = reverse_lazy('password_success') + def password_success(request): return render(request, 'password_success.html', {}) @@ -785,15 +811,18 @@ def see_given_rating(request): try: if order_by_key[0] == '-': order_by_key = order_by_key[1:] - rating_list = Rating.objects.filter(user=request.user).order_by(query_order + order_by_key) + rating_list = Rating.objects.filter( + user=request.user).order_by(query_order + order_by_key) except FieldError: order_by_key = 'timestamp' - rating_list = Rating.objects.filter(user=request.user).order_by(query_order + order_by_key) + rating_list = Rating.objects.filter( + user=request.user).order_by(query_order + order_by_key) return render(request, 'given-rating.html', context={'rating_list': rating_list, 'order_by_key': order_by_key, 'order_by': order_by}) return permission_denied(request, exception=None) + class SubmitVisitorView(TemplateView): template_name = "submit_visitor.html" @@ -819,6 +848,21 @@ class SubmitVisitorView(TemplateView): SubmitVisitor(msg=title, user_id=user_id, email=email).save() return JsonResponse({"success": True, "msg": "Buku tamu berhasil ditambahkan"}) + +class GuestBookView(TemplateView): + def get(self, request, *args, **kwargs): + form = GuestBookForm() + return render(request, 'guest_book.html', {'form': form}) + + def post(self, request, *args, **kwargs): + name = request.POST.get('name') + job = request.POST.get('job') + gender = request.POST.get('gender') + guestBook = GuestBook(name=name, job=job, gender=gender) + guestBook.save() + return redirect("daftar_katalog") + + class ReadLaterView(TemplateView): template_name = 'baca-nanti.html' @@ -834,19 +878,22 @@ class ReadLaterView(TemplateView): def get(self, request, *args, **kwargs): context = self.get_context_data(**kwargs) user = self.request.user - context["read_later_list"] = ReadLater.objects.filter(user=user).order_by('-timestamp') + context["read_later_list"] = ReadLater.objects.filter( + user=user).order_by('-timestamp') return self.render_to_response(context) + def toggle_readlater(request): if request.method == "POST": materi_id = request.POST.get("materi_id", None) if materi_id is None: return JsonResponse({"success": False, "msg": MISSING_PARAMETER_MESSAGE}) - + return JsonResponse(ReadLaterService.toggle_read_later(materi_id, request.user)) else: return JsonResponse({"success": False, "msg": UNSUPPORTED_MESSAGE}) + class StatisticsView(TemplateView): template_name = "statistik.html" @@ -867,29 +914,29 @@ class StatisticsView(TemplateView): result.append(e) chart_data = { - 'labels': [e.name for e in result], - 'datasets': [{ - 'label': 'Jumlah Materi per Kategori', - 'data': [e.num for e in result], - 'backgroundColor': [ - 'rgba(255, 99, 132, 0.2)', - 'rgba(54, 162, 235, 0.2)', - 'rgba(255, 206, 86, 0.2)', - 'rgba(75, 192, 192, 0.2)', - 'rgba(153, 102, 255, 0.2)', - 'rgba(255, 159, 64, 0.2)' - ], - 'borderColor': [ - 'rgba(255, 99, 132, 1)', - 'rgba(54, 162, 235, 1)', - 'rgba(255, 206, 86, 1)', - 'rgba(75, 192, 192, 1)', - 'rgba(153, 102, 255, 1)', - 'rgba(255, 159, 64, 1)' - ], - 'borderWidth': 1 - }] - } + 'labels': [e.name for e in result], + 'datasets': [{ + 'label': 'Jumlah Materi per Kategori', + 'data': [e.num for e in result], + 'backgroundColor': [ + 'rgba(255, 99, 132, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(255, 206, 86, 0.2)', + 'rgba(75, 192, 192, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(255, 159, 64, 0.2)' + ], + 'borderColor': [ + 'rgba(255, 99, 132, 1)', + 'rgba(54, 162, 235, 1)', + 'rgba(255, 206, 86, 1)', + 'rgba(75, 192, 192, 1)', + 'rgba(153, 102, 255, 1)', + 'rgba(255, 159, 64, 1)' + ], + 'borderWidth': 1 + }] + } return chart_data def get(self, request, *args, **kwargs): @@ -904,6 +951,7 @@ class StatisticsView(TemplateView): return self.render_to_response(context) + class MostContributor(TemplateView): template_name = "most-contributor.html" @@ -914,6 +962,6 @@ class MostContributor(TemplateView): def count_contributor(self): count_materi = Materi.objects.all.count() - content = {'count_materi':count_materi} + content = {'count_materi': count_materi} print(content) return content diff --git a/requirements.txt b/requirements.txt index 30fd8032d8b3be87ddcb85a8443175668af3dc5f..43d0d26f750678927c647708539ffbe7f4bd9589 100644 --- a/requirements.txt +++ b/requirements.txt @@ -101,4 +101,4 @@ whitenoise==5.0.1 wrapt==1.11.2 xlrd==1.2.0 XlsxWriter==1.3.6 -zipp==3.1.0 +zipp==3.1.0 \ No newline at end of file