From 9ca7d0d685630c6a415d8e39f0e2f49e69efb74f Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Fri, 30 Oct 2020 22:08:18 +0700 Subject: [PATCH 01/13] [RED] test for name input has placeholder and css in guest book form --- app/tests.py | 964 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 578 insertions(+), 386 deletions(-) diff --git a/app/tests.py b/app/tests.py index 0a16cc1..6e35ffd 100644 --- a/app/tests.py +++ b/app/tests.py @@ -1,4 +1,16 @@ -import json, tempfile, os, mock, base64 +from statistics import mean +import requests +from selenium.common.exceptions import NoSuchElementException +from webdriver_manager.chrome import ChromeDriverManager +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.chrome.options import Options +from selenium import webdriver +from django.test import LiveServerTestCase +import json +import tempfile +import os +import mock +import base64 import pandas as pd from io import StringIO import re @@ -71,16 +83,6 @@ from app.utils.PasswordValidator import PasswordPolicyValidator ERROR_403_MESSAGE = "Kamu harus login untuk mengakses halaman ini" -from django.test import LiveServerTestCase -from selenium import webdriver -from selenium.webdriver.chrome.options import Options -from selenium.webdriver.common.keys import Keys -from webdriver_manager.chrome import ChromeDriverManager -from selenium.common.exceptions import NoSuchElementException -import requests -from statistics import mean - - class DaftarKatalogTest(TestCase): def test_daftar_katalog_url_exist(self): @@ -109,10 +111,12 @@ class DaftarKatalogTest(TestCase): def test_materi_model_generate_search_vector_after_save(self): Materi(title="Eating book").save() - search_vector_new_materi = list(Materi.objects.values_list("_search_vector", flat=True)) + search_vector_new_materi = list( + Materi.objects.values_list("_search_vector", flat=True)) expected_search_vector = ["'book':2A 'eat':1A"] - self.assertSequenceEqual(search_vector_new_materi, expected_search_vector) + self.assertSequenceEqual( + search_vector_new_materi, expected_search_vector) def test_search_text_on_empty_database(self): search_query = "test" @@ -153,19 +157,20 @@ class DaftarKatalogTest(TestCase): self.assertSequenceEqual(search_result, expected_search_result) + class DaftarKatalogSortingByJumlahUnduhTest(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) @@ -193,6 +198,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 = { @@ -226,20 +232,21 @@ class DaftarKatalogSortingByJumlahTampilanTest(TestCase): self.client.get(self.url) response = self.client.get("/?sort=jumlah_tampilan") 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) @@ -272,7 +279,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) @@ -286,16 +294,17 @@ class DetailMateriTest(TestCase): def _get_materi_info_html(self, info_name, info_value): info_html = '
' info_html += f'
{info_name}
' + '
' - info_html += f'

{info_value}

' + '
' + info_html += f'

{info_value}

' + \ + '' 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() @@ -322,14 +331,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) + "/" @@ -337,14 +346,15 @@ class DetailMateriTest(TestCase): self.dcount_info_name = "Jumlah Download" 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=datetime.now(), date_created=datetime.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=datetime.now(), date_created=datetime.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) @@ -420,14 +430,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} ajax_response = 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): @@ -435,14 +448,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} ajax_response = 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): @@ -450,16 +466,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} ajax_response = self.client.post("/comment/dislike/", payload) - + ajax_response = 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): @@ -467,16 +486,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} ajax_response = self.client.post("/comment/like/", payload) - + ajax_response = 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): @@ -486,10 +508,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): @@ -499,10 +524,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): @@ -514,12 +542,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) @@ -541,12 +570,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) @@ -571,12 +601,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) @@ -611,7 +642,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 @@ -630,7 +662,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): @@ -639,7 +672,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): @@ -648,10 +682,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") @@ -698,7 +732,7 @@ class DetailMateriTest(TestCase): self.client.post(url, {"review": "This is new review by Anonymous"}) response = self.client.get(url) self.assertContains(response, "Anonymous") - + def test_detail_materi_contains_review_count(self): url = self.url self.client.login(**self.contributor_credential) @@ -707,7 +741,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) @@ -721,7 +755,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) @@ -729,25 +764,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") @@ -759,19 +796,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"]) @@ -781,7 +818,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. " + \ @@ -851,10 +889,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") @@ -895,10 +934,15 @@ 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) + class PostsViewTest(TestCase): @@ -927,13 +971,13 @@ 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=datetime.now(), - materi=post, + timestamp=datetime.now(), + materi=post, session_id=("dummysession-" + str(i) + '-' + str(j)) ) - + for i, post_id in enumerate(post_comment_group_dict): post = post_comment_group_dict[post_id]["data"] @@ -953,7 +997,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): @@ -1003,12 +1048,12 @@ class PostsViewTest(TestCase): self.assertRegex( str(response.content), - rf'.*(
)' + \ - rf'.*(
)' + \ - rf'.*(
)' + \ - rf'.*(
)' + \ - rf'.*(
)' + \ - rf'.*(
)' + \ + rf'.*(
)' + + rf'.*(
)' + + rf'.*(
)' + + rf'.*(
)' + + rf'.*(
)' + + rf'.*(
)' + rf'.*(
)' ) @@ -1020,9 +1065,11 @@ class PostsViewTest(TestCase): self.assertContains( response, - '' + str(post.like_count) + '', + '' + str(post.like_count) + '', ) + class TemplateLoaderTest(TestCase): def test_template_loader_url_exist(self): url = "/test-page.html" @@ -1075,13 +1122,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/") @@ -1201,7 +1248,8 @@ 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 + writer = pd.ExcelWriter( + file_path, engine='xlsxwriter') # pylint: disable=abstract-class-instantiated data_frame.to_excel(writer, index=0) writer.save() @@ -1212,14 +1260,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 @@ -1230,33 +1279,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 @@ -1267,15 +1317,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 @@ -1290,37 +1341,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: response = 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): @@ -1390,6 +1442,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() @@ -1415,7 +1468,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() @@ -1426,14 +1480,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) @@ -1441,6 +1495,7 @@ class DeleteMateriTest(TestCase): self.materi1.refresh_from_db() self.assertNotEqual(self.materi1.deleted_at, None) + class ProfilViewTest(TestCase): @classmethod def setUpTestData(cls): @@ -1449,10 +1504,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): @@ -1460,7 +1518,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) @@ -1491,10 +1549,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): @@ -1502,7 +1563,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) @@ -1537,8 +1598,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): @@ -1914,7 +1977,8 @@ class RevisiMateriTest(TestCase): self.assertEqual(response.status_code, 200) # Logout self.client.logout() - + + class GenerateDummyCommandTest(TestCase): def setUp(self): @@ -1950,7 +2014,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) @@ -1975,8 +2040,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" @@ -2002,17 +2069,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() @@ -2064,7 +2134,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") @@ -2089,52 +2160,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): @@ -2152,11 +2236,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) @@ -2179,6 +2264,7 @@ class fileManagementUtilTest(TestCase): self.assertTrue(len(sanitized_img) < len(self.file_content)) self.assertTrue(b'")[0] + "" + + table_html = ("")[0] + "" 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) @@ -2669,9 +2786,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", @@ -2691,12 +2808,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=datetime.now(), materi=self.materi, session_id="dummysessionid1") + Like.objects.create(timestamp=datetime.now(), + materi=self.materi, session_id="dummysessionid1") self.assertEqual(1, self.materi.like_count) - Like.objects.create(timestamp=datetime.now(), materi=self.materi, session_id="dummysessionid2") + Like.objects.create(timestamp=datetime.now(), + materi=self.materi, session_id="dummysessionid2") self.assertEqual(2, self.materi.like_count) + class MateriFavoriteTest(TestCase): @classmethod def setUpTestData(cls): @@ -2705,7 +2825,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) @@ -2713,7 +2834,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): @@ -2758,7 +2881,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 @@ -2772,6 +2896,7 @@ class YearChoicesTest(TestCase): self.assertEqual((2000, 2000), choices[0]) + TEST_IMAGE = ''' iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBI WXMAAABIAAAASABGyWs+AAAACXZwQWcAAAAQAAAAEABcxq3DAAABfElEQVQ4y52TvUuCURTGf5Zg @@ -2813,18 +2938,22 @@ c3NKmqa6uLios7MXtFgsahRFGhUKHUS7KBQ0iiIdGhrS8+dndH5+XpMk0X8AMTVx/inpU4cAAAAl dEVYdGNyZWF0ZS1kYXRlADIwMTAtMTItMjZUMTQ6NDk6MjErMDk6MDAHHBB1AAAAJXRFWHRtb2Rp 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): from django.core.files.uploadedfile import InMemoryUploadedFile @@ -2851,23 +2980,23 @@ class YTUrlVideoTest(TestCase): def test_upload_materi_with_valid_yt_video_id(self): self.client.login(**self.contributor_credential) response = 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) response = 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 @@ -2878,20 +3007,23 @@ class YTUrlVideoTest(TestCase): def test_detail_materi_has_no_video_if_yt_video_id_empty(self): self.client.login(**self.contributor_credential) response = 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" @@ -2928,7 +3060,7 @@ class ChangePasswordTest(TestCase): # Logout self.client.logout() - + class SeeRatedMateriByUser(TestCase): def setUp(self): self.client = Client() @@ -2940,7 +3072,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/" @@ -2965,13 +3098,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() @@ -3011,12 +3148,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): @@ -3032,24 +3171,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 @@ -3058,13 +3201,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']), @@ -3074,26 +3219,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!" @@ -3103,28 +3252,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 = { @@ -3139,52 +3294,81 @@ 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, 'Home(current)') - self.assertContains(response, 'Forum') - self.assertContains(response, 'Berita') - self.assertContains(response, 'Administrasi') - self.assertContains(response, 'Profil') - self.assertContains(response, 'Logout') - self.assertNotContains(response, 'LogoutX') + self.assertContains( + response, 'Home(current)') + self.assertContains( + response, 'Forum') + self.assertContains( + response, 'Berita') + self.assertContains( + response, 'Administrasi') + self.assertContains( + response, 'Profil') + self.assertContains( + response, 'Logout') + self.assertNotContains( + response, 'LogoutX') def test_navbar_contributor(self): self.client.login(**self.contributor_credential) response = self.client.get('/') - self.assertContains(response, 'Home(current)') - self.assertContains(response, 'Forum') - self.assertContains(response, 'Berita') - self.assertContains(response, 'Dasbor') - self.assertContains(response, 'Profil') - self.assertContains(response, 'Logout') - self.assertNotContains(response, 'LogoutX') + self.assertContains( + response, 'Home(current)') + self.assertContains( + response, 'Forum') + self.assertContains( + response, 'Berita') + self.assertContains( + response, 'Dasbor') + self.assertContains( + response, 'Profil') + self.assertContains( + response, 'Logout') + self.assertNotContains( + response, 'LogoutX') def test_navbar_public(self): self.client.login(**self.public_credential) response = self.client.get('/') - self.assertContains(response, 'Home(current)') - self.assertContains(response, 'Forum') - self.assertContains(response, 'Berita') - self.assertContains(response, 'Profil') - self.assertContains(response, 'Logout') - self.assertNotContains(response, 'LogoutX') + self.assertContains( + response, 'Home(current)') + self.assertContains( + response, 'Forum') + self.assertContains( + response, 'Berita') + self.assertContains( + response, 'Profil') + self.assertContains( + response, 'Logout') + self.assertNotContains( + response, 'LogoutX') def test_navbar_anonymous(self): response = self.client.get('/') - self.assertContains(response, 'Home(current)') - self.assertContains(response, 'Forum') - self.assertContains(response, 'Berita') - self.assertContains(response, 'Registrasi Umum') - self.assertContains(response, 'Registrasi Kontributor') - self.assertContains(response, 'Login') - self.assertContains(response, 'Login Admin') - self.assertNotContains(response, 'LogoutX') + self.assertContains( + response, 'Home(current)') + self.assertContains( + response, 'Forum') + self.assertContains( + response, 'Berita') + self.assertContains( + response, 'Registrasi Umum') + self.assertContains( + response, 'Registrasi Kontributor') + self.assertContains( + response, 'Login') + self.assertContains( + response, 'Login Admin') + self.assertNotContains( + response, 'LogoutX') class MateriRecommendationTest(TestCase): @@ -3244,7 +3428,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): @@ -3281,6 +3466,13 @@ 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="Masukkan nama lengkap"', form.as_p()) + self.assertIn('class="form-control input-lg"', form.as_p()) -- GitLab From bcea1702308e9c84750ada07dfdbdbc1267976a6 Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Fri, 30 Oct 2020 22:21:47 +0700 Subject: [PATCH 02/13] [GREEN] add name input using placeholder and css in Guest Book Form --- app/forms.py | 9 +++++++++ app/tests.py | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/forms.py b/app/forms.py index aafd9ba..3172f6f 100644 --- a/app/forms.py +++ b/app/forms.py @@ -70,3 +70,12 @@ class RatingContributorForm(forms.ModelForm): 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control'},), 'user': forms.HiddenInput() } + + +class GuestBookForm(forms.Form): + name = forms.CharField( + widget=forms.fields.TextInput(attrs={ + 'placeholder': 'Masukkan nama lengkap', + 'class': 'form-control input-lg' + }) + ) diff --git a/app/tests.py b/app/tests.py index 6e35ffd..df58864 100644 --- a/app/tests.py +++ b/app/tests.py @@ -77,7 +77,7 @@ from .views import ( password_success, MateriFavorite, ) -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 -- GitLab From f69dbaf84d848d618cfaa9d28fb81931ff7f28ca Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Fri, 30 Oct 2020 22:34:02 +0700 Subject: [PATCH 03/13] [RED] test job input using placeholder and css in guest book form --- app/tests.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/tests.py b/app/tests.py index df58864..ef7a63a 100644 --- a/app/tests.py +++ b/app/tests.py @@ -3476,3 +3476,8 @@ class GuestBookTest(TestCase): form = GuestBookForm() self.assertIn('placeholder="Masukkan nama lengkap"', 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="Masukkan pekerjaan"', form.as_p()) + self.assertIn('class="form-control input-lg"', form.as_p()) -- GitLab From c40d573ff8f76bb59ea303249a5ce3dbe67e76ee Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Fri, 30 Oct 2020 22:36:26 +0700 Subject: [PATCH 04/13] [GREEN] add job input in guest book form --- app/forms.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/forms.py b/app/forms.py index 3172f6f..ffa1eed 100644 --- a/app/forms.py +++ b/app/forms.py @@ -79,3 +79,11 @@ class GuestBookForm(forms.Form): 'class': 'form-control input-lg' }) ) + + job = forms.CharField( + widget=forms.fields.TextInput(attrs={ + 'placeholder': 'Masukkan pekerjaan', + 'class': 'form-control input-lg' + }) + ) + -- GitLab From 46dbc0d9b84f6ae4a929da37b2e71fb2603e282d Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 13:17:40 +0700 Subject: [PATCH 05/13] add test for blank items form --- app/tests.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/tests.py b/app/tests.py index ef7a63a..85e1c92 100644 --- a/app/tests.py +++ b/app/tests.py @@ -2936,7 +2936,7 @@ cpnR0WOUSiVEhLVKhbXXa7xcXqHyaoV6o0Hqd1MxUjqu7XYLMFkaNXtXYC09+R5UwbkYEcVaizFm P/LWGsLJydMs3VvCWkP3gzxK7OKu7Bl81/tEhKmpKVhYWNCJiQkNglDDMKdhLpf1/0AQhDo+Pq5z c3NKmqa6uLios7MXtFgsahRFGhUKHUS7KBQ0iiIdGhrS8+dndH5+XpMk0X8AMTVx/inpU4cAAAAl dEVYdGNyZWF0ZS1kYXRlADIwMTAtMTItMjZUMTQ6NDk6MjErMDk6MDAHHBB1AAAAJXRFWHRtb2Rp -ZnktZGF0ZQAyMDEwLTEyLTI2VDE0OjQ5OjIxKzA5OjAwWK1mQQAAAABJRU5ErkJggg== +ZnktZGF0ZQAyMDEwLTEyLTI2VDE0OjQ5OjIxKzA5OjAwWK1mQQAAAABJRU5ErkJggg == '''.strip() @@ -3481,3 +3481,15 @@ class GuestBookTest(TestCase): form = GuestBookForm() self.assertIn('placeholder="Masukkan pekerjaan"', form.as_p()) self.assertIn('class="form-control input-lg"', form.as_p()) + + def test_form_validation_for_blank_items(self): + form = GuestBookForm(data={'nama': '', 'pekerjaan': ''}) + self.assertFalse(form.is_valid()) + self.assertEqual( + form.errors['nama'], + ['Nama wajib diisi'] + ) + self.assertEqual( + form.errors['pekerjaan'], + ['Pekerjaan wajib diisi'] + ) -- GitLab From 65e88e770144b4601f1c3961e609a2fe71ee1e28 Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 13:21:13 +0700 Subject: [PATCH 06/13] [GREEN] modify models and forms to set requrired fields --- app/forms.py | 60 ++++++++++++++++++-------------- app/migrations/0027_guestbook.py | 21 +++++++++++ app/models.py | 54 +++++++++++++++++++--------- 3 files changed, 92 insertions(+), 43 deletions(-) create mode 100644 app/migrations/0027_guestbook.py diff --git a/app/forms.py b/app/forms.py index ffa1eed..650fcef 100644 --- a/app/forms.py +++ b/app/forms.py @@ -1,19 +1,23 @@ 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) + + categories = forms.ModelMultipleChoiceField(queryset=Category.objects.all( + ), widget=forms.CheckboxSelectMultiple(attrs={'style': 'column-count:2'}), required=True) #categories.widget.attrs["style"] = "column-count:2" - 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.
\ + 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.
\ Please insert only Youtube link videos! Take a note for the video id!
\ Example : https://www.youtube.com/watch?v=DkJ-50GLi2I
has video id DkJ-50GLi2I", required=False) @@ -28,14 +32,13 @@ class UploadMateriForm(forms.ModelForm): if (field_name == "categories"): continue field.widget.attrs["class"] = "form-control" - 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"] @@ -49,7 +52,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 @@ -60,7 +62,8 @@ class RatingContributorForm(forms.ModelForm): fields = ['score', 'user'] 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'), @@ -72,18 +75,21 @@ class RatingContributorForm(forms.ModelForm): } -class GuestBookForm(forms.Form): - name = forms.CharField( - widget=forms.fields.TextInput(attrs={ - 'placeholder': 'Masukkan nama lengkap', - 'class': 'form-control input-lg' - }) - ) - - job = forms.CharField( - widget=forms.fields.TextInput(attrs={ - 'placeholder': 'Masukkan pekerjaan', - 'class': 'form-control input-lg' - }) - ) - +class GuestBookForm(forms.models.ModelForm): + class Meta: + model = GuestBook + fields = ['nama', 'pekerjaan'] + widgets = { + 'nama': forms.fields.TextInput(attrs={ + 'placeholder': 'Masukkan nama lengkap', + 'class': 'form-control input-lg' + }), + 'pekerjaan': forms.fields.TextInput(attrs={ + 'placeholder': 'Masukkan pekerjaan', + 'class': 'form-control input-lg' + }), + } + error_messages = { + 'nama': {'required': 'Nama wajib diisi'}, + 'pekerjaan': {'required': 'Pekerjaan wajib diisi'} + } diff --git a/app/migrations/0027_guestbook.py b/app/migrations/0027_guestbook.py new file mode 100644 index 0000000..06e6424 --- /dev/null +++ b/app/migrations/0027_guestbook.py @@ -0,0 +1,21 @@ +# Generated by Django 3.1 on 2020-10-31 01:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0026_submitvisitor'), + ] + + operations = [ + migrations.CreateModel( + name='GuestBook', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nama', models.TextField(default='')), + ('pekerjaan', models.TextField(default='')), + ], + ), + ] diff --git a/app/models.py b/app/models.py index f50c904..edb5e61 100644 --- a/app/models.py +++ b/app/models.py @@ -25,9 +25,11 @@ def getRandomColor(): 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="") @@ -47,7 +49,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 = search.SearchVector("title", weight="A") search_query = search.SearchQuery(search_text) @@ -55,27 +57,31 @@ class MateriManager(models.Manager): search_rank = search.SearchRank(search_vector, search_query) search_result = ( - self.get_queryset().filter(_search_vector=search_query).annotate(rank=search_rank).order_by("-rank") + self.get_queryset().filter(_search_vector=search_query).annotate( + rank=search_rank).order_by("-rank") ) return search_result + 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() @@ -85,8 +91,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) @@ -124,7 +131,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() @@ -147,7 +154,8 @@ class Comment(models.Model): profile = models.CharField(max_length=100, default=getRandomColor) 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): @@ -157,18 +165,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=getRandomColor) 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): @@ -197,6 +207,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) @@ -205,13 +216,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) @@ -252,7 +266,8 @@ class Rating(models.Model): class RatingContributor(models.Model): timestamp = models.DateTimeField(auto_now=True) - score = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) + score = models.PositiveIntegerField( + validators=[MinValueValidator(1), MaxValueValidator(5)]) user = models.ForeignKey(User, on_delete=models.CASCADE) def save(self, force_insert=False, force_update=False, using=None, update_fields=None): @@ -263,8 +278,15 @@ class RatingContributor(models.Model): 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): + nama = models.TextField(default='') + pekerjaan = models.TextField(default='') -- GitLab From 30cbaf4b3c13fb3836162ff035269bfd755dc304 Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 21:09:38 +0700 Subject: [PATCH 07/13] [RED] refactor some test and add new test for create new guest book data --- app/tests.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/app/tests.py b/app/tests.py index 85e1c92..d4fbfda 100644 --- a/app/tests.py +++ b/app/tests.py @@ -53,6 +53,7 @@ from .models import ( ReqMaterial, RatingContributor, ViewStatistics, + GuestBook ) from .services import ( @@ -3474,22 +3475,37 @@ class MateriRecommendationTest(TestCase): class GuestBookTest(TestCase): def test_form_name_input_has_placeholder_and_css_classes(self): form = GuestBookForm() - self.assertIn('placeholder="Masukkan nama lengkap"', form.as_p()) + 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="Masukkan pekerjaan"', form.as_p()) + 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={'nama': '', 'pekerjaan': ''}) + form = GuestBookForm(data={'name': '', 'job': '', 'gender': ''}) self.assertFalse(form.is_valid()) self.assertEqual( - form.errors['nama'], - ['Nama wajib diisi'] + form.errors['name'], + ['Name is required'] ) self.assertEqual( - form.errors['pekerjaan'], - ['Pekerjaan wajib diisi'] + 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) -- GitLab From 6a0ef28f565bcd52ba61e8363c8f1dc4241111cf Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 21:13:03 +0700 Subject: [PATCH 08/13] [GREEN] add new html and css for guest book form, also modify model, urls, and views for guest book --- app/forms.py | 22 ++- app/migrations/0028_auto_20201031_2000.py | 28 ++++ app/models.py | 5 +- app/static/app/css/guest_book.css | 63 ++++++++ .../app/includes/navbar_katalog_materi.html | 104 ++++++------ app/templates/guest_book.html | 31 ++++ app/urls.py | 18 ++- app/views.py | 152 +++++++++++------- 8 files changed, 302 insertions(+), 121 deletions(-) create mode 100644 app/migrations/0028_auto_20201031_2000.py create mode 100644 app/static/app/css/guest_book.css create mode 100644 app/templates/guest_book.html diff --git a/app/forms.py b/app/forms.py index 650fcef..90092a2 100644 --- a/app/forms.py +++ b/app/forms.py @@ -78,18 +78,26 @@ class RatingContributorForm(forms.ModelForm): class GuestBookForm(forms.models.ModelForm): class Meta: model = GuestBook - fields = ['nama', 'pekerjaan'] + fields = ['name', 'job', 'gender'] + gender_choices = ( + ('Male', 'Male'), + ('Female', 'Female') + ) widgets = { - 'nama': forms.fields.TextInput(attrs={ - 'placeholder': 'Masukkan nama lengkap', + 'name': forms.fields.TextInput(attrs={ + 'placeholder': 'Input your name', 'class': 'form-control input-lg' }), - 'pekerjaan': forms.fields.TextInput(attrs={ - 'placeholder': 'Masukkan pekerjaan', + '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 = { - 'nama': {'required': 'Nama wajib diisi'}, - 'pekerjaan': {'required': 'Pekerjaan wajib diisi'} + 'name': {'required': 'Name is required'}, + 'job': {'required': 'Job is required'}, + 'gender': {'required': 'Gender is required'} } diff --git a/app/migrations/0028_auto_20201031_2000.py b/app/migrations/0028_auto_20201031_2000.py new file mode 100644 index 0000000..e0bde05 --- /dev/null +++ b/app/migrations/0028_auto_20201031_2000.py @@ -0,0 +1,28 @@ +# Generated by Django 3.1 on 2020-10-31 13:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0027_guestbook'), + ] + + operations = [ + migrations.RenameField( + model_name='guestbook', + old_name='nama', + new_name='job', + ), + migrations.RenameField( + model_name='guestbook', + old_name='pekerjaan', + new_name='name', + ), + migrations.AddField( + model_name='guestbook', + name='gender', + field=models.CharField(default='Male', max_length=6), + ), + ] diff --git a/app/models.py b/app/models.py index edb5e61..d6cc1c5 100644 --- a/app/models.py +++ b/app/models.py @@ -288,5 +288,6 @@ class LaporanMateri(models.Model): class GuestBook(models.Model): - nama = models.TextField(default='') - pekerjaan = models.TextField(default='') + name = models.TextField(default='') + job = models.TextField(default='') + gender = models.CharField(max_length=6, default="Male") diff --git a/app/static/app/css/guest_book.css b/app/static/app/css/guest_book.css new file mode 100644 index 0000000..681d4f1 --- /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/app/includes/navbar_katalog_materi.html b/app/templates/app/includes/navbar_katalog_materi.html index 2ab5d5d..04b3299 100644 --- a/app/templates/app/includes/navbar_katalog_materi.html +++ b/app/templates/app/includes/navbar_katalog_materi.html @@ -1,51 +1,55 @@ - - \ 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 0000000..b2d32fc --- /dev/null +++ b/app/templates/guest_book.html @@ -0,0 +1,31 @@ +{% extends 'base.html' %} +{% load static %} +{% block title %}Digipus Home{% endblock %} +{% block header %} + + + + + + Digipus Home + + + + + {% endblock header %} + + + + +{% block content %} +
+
+

Buku Tamu Non Anggota

+ {% csrf_token %} + {{form}} + +
+
+{% endblock %} + + \ No newline at end of file diff --git a/app/urls.py b/app/urls.py index a8c7281..687f68f 100644 --- a/app/urls.py +++ b/app/urls.py @@ -5,7 +5,7 @@ from app import views from app.views import (DashboardKontributorView, ProfilView, SuksesLoginAdminView, SuksesLoginKontributorView, DownloadHistoryView, SuntingProfilView, UploadMateriHTML, UploadMateriView, UploadMateriExcelView, PostsView, - ReqMateriView, KatalogPerKontributorView, MateriFavorite, PasswordChangeViews, password_success, SubmitVisitorView) + ReqMateriView, KatalogPerKontributorView, MateriFavorite, PasswordChangeViews, password_success, SubmitVisitorView, GuestBookView) urlpatterns = [ @@ -15,13 +15,16 @@ urlpatterns = [ path("delete//", views.delete_comment, name="delete-comment"), 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//delete", views.delete_materi, name="detele-materi"), path("materi//unduh", views.download_materi, name="download-materi"), path("materi//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//", views.RevisiMateriView.as_view(), name="revisi"), + path("download-history/", DownloadHistoryView.as_view(), + name="download-history"), + path("revisi/materi//", + 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"), @@ -35,10 +38,13 @@ urlpatterns = [ path("profil//", KatalogPerKontributorView.as_view(), name="katalog-per-kontributor"), path("materi/rate/", views.add_rating_materi, name="rate-materi"), - path("materi//save-to-gdrive/", views.save_to_gdrive, name="save-to-gdrive"), + path("materi//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("guest-book/", GuestBookView.as_view(), name="guest-book") ] diff --git a/app/views.py b/app/views.py index a6c7ca1..019fe9a 100644 --- a/app/views.py +++ b/app/views.py @@ -23,7 +23,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, @@ -31,7 +31,8 @@ from app.models import ( Materi, ReqMaterial, Rating, RatingContributor, - SubmitVisitor + SubmitVisitor, + GuestBook ) from authentication.models import User from .services import DafterKatalogService, DetailMateriService, LikeDislikeService, MateriFieldValidationHelperService, \ @@ -54,11 +55,12 @@ class DaftarKatalog(TemplateView): context = self.get_context_data(**kwargs) context["kategori_list"] = Category.objects.all() - lstMateri = Materi.objects.filter(status="APPROVE").order_by("date_modified") + lstMateri = Materi.objects.filter( + status="APPROVE").order_by("date_modified") url = "" - lstMateri, url = DafterKatalogService.apply_options(lstMateri, request, url) - + lstMateri, url = DafterKatalogService.apply_options( + lstMateri, request, url) context["materi_list"] = lstMateri paginator = Paginator(context["materi_list"], 15) @@ -91,10 +93,12 @@ class KatalogPerKontributorView(TemplateView): materi_list_by_page = paginator.get_page(page_number) context["materi_list"] = materi_list_by_page contributor = get_object_or_404(User, email=kwargs["email"]) - context["form_rating"] = RatingContributorForm(initial={"user": contributor}) + context["form_rating"] = RatingContributorForm( + initial={"user": contributor}) context["avg_rating"] = User.objects.filter(email=kwargs["email"]) \ .annotate(avg_rating=Avg("ratingcontributor__score"))[0] - context["count_rating"] = RatingContributor.objects.filter(user=contributor).count() + context["count_rating"] = RatingContributor.objects.filter( + user=contributor).count() return self.render_to_response(context=context) def post(self, request, *args, **kwargs): @@ -112,13 +116,16 @@ 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 @@ -126,54 +133,56 @@ 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"] = has_liked context["has_disliked"] = has_disliked 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) - if ((comment_text == None or comment_text == "" )and (review_text == None or review_text == "")): + review_text = request.POST.get("review", None) + if ((comment_text == None or comment_text == "")and (review_text == None or review_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.' send_mail( - subject = 'DIGIPUS: Komentar Baru pada Materi Anda', - message = email_content, - from_email = getattr(settings, 'EMAIL_HOST_USER'), - recipient_list = [materi_uploader.email,], - fail_silently = False, - ) + subject='DIGIPUS: Komentar Baru pada Materi Anda', + message=email_content, + from_email=getattr(settings, 'EMAIL_HOST_USER'), + recipient_list=[materi_uploader.email, ], + fail_silently=False, + ) elif (review_text != None): review = Review.objects.create( review=review_text, username=DetailMateriService.get_user_name(request), materi=materi, user=user_obj @@ -201,6 +210,7 @@ def delete_comment(request, pk_materi, pk_comment): comment.delete() return HttpResponseRedirect(url) + def toggle_like_comment(request): comment_id = 0 if request.method == "POST": @@ -231,17 +241,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: @@ -254,7 +263,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 @@ -281,7 +289,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 as e: raise Http404("File tidak dapat ditemukan.") @@ -297,6 +306,7 @@ def delete_materi(request, pk): materi.delete() return HttpResponseRedirect("/dashboard/") + class UploadMateriView(TemplateView): template_name = "unggah.html" context = {} @@ -317,7 +327,8 @@ class UploadMateriView(TemplateView): if not UploadMateriService.validate_file_extension(konten, request, yt_url_id): return HttpResponseRedirect("/unggah/") 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/") else: context = self.get_context_data(**kwargs) @@ -325,8 +336,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) @@ -360,11 +369,13 @@ class UploadMateriExcelView(TemplateView): if "template" in self.request.GET: data_frame = pd.DataFrame( - {"Title": [], "Author": [], "Publisher": [], "Categories": [], "Description": [],} + {"Title": [], "Author": [], "Publisher": [], + "Categories": [], "Description": [], } ) with BytesIO() as b: - writer = pd.ExcelWriter(b, engine="xlsxwriter") # pylint: disable=abstract-class-instantiated + writer = pd.ExcelWriter( + b, engine="xlsxwriter") # pylint: disable=abstract-class-instantiated data_frame.to_excel(writer, index=0) writer.save() response = HttpResponse( @@ -398,9 +409,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 @@ -411,15 +424,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/") - - class DashboardKontributorView(TemplateView): template_name = "dashboard.html" @@ -429,7 +441,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): @@ -476,13 +489,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/") @@ -525,7 +540,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): @@ -572,9 +588,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) @@ -609,7 +627,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/") @@ -646,7 +665,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) @@ -663,6 +683,7 @@ def save_to_gdrive(request, pk): return HttpResponseRedirect(reverse('detail-materi', kwargs={'pk': pk})) + class MateriFavorite(TemplateView): template_name = "user_favorite_materi.html" @@ -677,7 +698,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()) \ @@ -691,11 +712,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', {}) @@ -714,15 +737,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" @@ -747,3 +773,17 @@ class SubmitVisitorView(TemplateView): return JsonResponse({"success": False, "msg": "Missing parameter"}) 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") -- GitLab From e1e1e5909883198b1e535a8725b9736c0732e89b Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 22:04:57 +0700 Subject: [PATCH 09/13] delete pylint-exit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 30fd803..43d0d26 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 -- GitLab From 71173206ed37cf6b0a05a7d7e52c0172af1d643b Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 22:06:35 +0700 Subject: [PATCH 10/13] change position pylint comment at create dummy excel test --- app/tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/tests.py b/app/tests.py index d4fbfda..9ee755f 100644 --- a/app/tests.py +++ b/app/tests.py @@ -1249,8 +1249,9 @@ class UploadExcelPageTest(TestCase): file_path = os.path.join(settings.MEDIA_ROOT, 'dummy.xlsx') + # pylint: disable=abstract-class-instantiated writer = pd.ExcelWriter( - file_path, engine='xlsxwriter') # pylint: disable=abstract-class-instantiated + file_path, engine='xlsxwriter') data_frame.to_excel(writer, index=0) writer.save() -- GitLab From 3f28754df83ca0eb125f7f7538208b97a9d0eda5 Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sat, 31 Oct 2020 22:12:12 +0700 Subject: [PATCH 11/13] change position of pylint disabled comment --- app/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views.py b/app/views.py index 019fe9a..f787781 100644 --- a/app/views.py +++ b/app/views.py @@ -373,9 +373,10 @@ class UploadMateriExcelView(TemplateView): "Categories": [], "Description": [], } ) + # pylint: disable=abstract-class-instantiated with BytesIO() as b: writer = pd.ExcelWriter( - b, engine="xlsxwriter") # pylint: disable=abstract-class-instantiated + b, engine="xlsxwriter") data_frame.to_excel(writer, index=0) writer.save() response = HttpResponse( -- GitLab From 35f08787038310e531362d0f48f073d12a3faa8e Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sun, 1 Nov 2020 01:20:28 +0700 Subject: [PATCH 12/13] renew guest book migrations and delete redundant migrations --- app/migrations/0028_auto_20201031_2000.py | 28 ------------------- .../{0027_guestbook.py => 0029_guestbook.py} | 9 +++--- app/migrations/0029_merge_20201101_0040.py | 14 ---------- app/migrations/0030_merge_20201101_0106.py | 14 ---------- 4 files changed, 5 insertions(+), 60 deletions(-) delete mode 100644 app/migrations/0028_auto_20201031_2000.py rename app/migrations/{0027_guestbook.py => 0029_guestbook.py} (56%) delete mode 100644 app/migrations/0029_merge_20201101_0040.py delete mode 100644 app/migrations/0030_merge_20201101_0106.py diff --git a/app/migrations/0028_auto_20201031_2000.py b/app/migrations/0028_auto_20201031_2000.py deleted file mode 100644 index e0bde05..0000000 --- a/app/migrations/0028_auto_20201031_2000.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 3.1 on 2020-10-31 13:00 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('app', '0027_guestbook'), - ] - - operations = [ - migrations.RenameField( - model_name='guestbook', - old_name='nama', - new_name='job', - ), - migrations.RenameField( - model_name='guestbook', - old_name='pekerjaan', - new_name='name', - ), - migrations.AddField( - model_name='guestbook', - name='gender', - field=models.CharField(default='Male', max_length=6), - ), - ] diff --git a/app/migrations/0027_guestbook.py b/app/migrations/0029_guestbook.py similarity index 56% rename from app/migrations/0027_guestbook.py rename to app/migrations/0029_guestbook.py index 06e6424..57fc440 100644 --- a/app/migrations/0027_guestbook.py +++ b/app/migrations/0029_guestbook.py @@ -1,4 +1,4 @@ -# Generated by Django 3.1 on 2020-10-31 01:23 +# Generated by Django 3.1 on 2020-10-31 18:19 from django.db import migrations, models @@ -6,7 +6,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('app', '0026_submitvisitor'), + ('app', '0028_adminnotification'), ] operations = [ @@ -14,8 +14,9 @@ class Migration(migrations.Migration): name='GuestBook', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('nama', models.TextField(default='')), - ('pekerjaan', models.TextField(default='')), + ('name', models.TextField(default='')), + ('job', models.TextField(default='')), + ('gender', models.CharField(default='Male', max_length=6)), ], ), ] diff --git a/app/migrations/0029_merge_20201101_0040.py b/app/migrations/0029_merge_20201101_0040.py deleted file mode 100644 index a149302..0000000 --- a/app/migrations/0029_merge_20201101_0040.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 3.1 on 2020-10-31 17:40 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('app', '0028_auto_20201031_2000'), - ('app', '0027_readlater'), - ] - - operations = [ - ] diff --git a/app/migrations/0030_merge_20201101_0106.py b/app/migrations/0030_merge_20201101_0106.py deleted file mode 100644 index 82f4984..0000000 --- a/app/migrations/0030_merge_20201101_0106.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 3.1 on 2020-10-31 18:06 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('app', '0029_merge_20201101_0040'), - ('app', '0028_adminnotification'), - ] - - operations = [ - ] -- GitLab From 7fa8848f2230b708c550b42c6ef36f58c82ce70b Mon Sep 17 00:00:00 2001 From: selvyfitriani31 Date: Sun, 1 Nov 2020 05:25:34 +0700 Subject: [PATCH 13/13] fix file contents in navbar because it also saved by VS code --- .../app/includes/navbar_katalog_materi.html | 122 +++++++++--------- 1 file changed, 58 insertions(+), 64 deletions(-) diff --git a/app/templates/app/includes/navbar_katalog_materi.html b/app/templates/app/includes/navbar_katalog_materi.html index 0228f04..222b70c 100644 --- a/app/templates/app/includes/navbar_katalog_materi.html +++ b/app/templates/app/includes/navbar_katalog_materi.html @@ -1,65 +1,59 @@ - \ No newline at end of file + \ No newline at end of file -- GitLab