diff --git a/app/forms.py b/app/forms.py index d6f9d1c94dcefee16837c8a7fa9a98ac2b641c22..5b8b3438c71bbe7efcb9dbee7746662563efb42b 100644 --- a/app/forms.py +++ b/app/forms.py @@ -59,7 +59,7 @@ class SuntingProfilForm(forms.ModelForm): class RatingContributorForm(forms.ModelForm): class Meta: model = RatingContributor - fields = ['score', 'user'] + fields = ['score', 'user', 'contributor'] SCORE_CHOICE = ( ('', 'Select score'), ('1', '1'), # First one is the value of select option and second is the displayed value in option @@ -69,6 +69,7 @@ class RatingContributorForm(forms.ModelForm): ('5', '5'), ) widgets = { - 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control'},), - 'user': forms.HiddenInput() + 'score': forms.Select(choices=SCORE_CHOICE, attrs={'class': 'form-control', 'id':'form-rating'},), + 'user': forms.HiddenInput(), + 'contributor': forms.HiddenInput() } diff --git a/app/migrations/0027_auto_20201030_1648.py b/app/migrations/0027_auto_20201030_1648.py new file mode 100644 index 0000000000000000000000000000000000000000..2c3a8b0a4d27b16db4d83a5dbd283d5556565f13 --- /dev/null +++ b/app/migrations/0027_auto_20201030_1648.py @@ -0,0 +1,31 @@ +# Generated by Django 3.1 on 2020-10-30 09:48 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('app', '0026_submitvisitor'), + ] + + operations = [ + migrations.AddField( + model_name='ratingcontributor', + name='contributor', + field=models.ForeignKey(default='', on_delete=django.db.models.deletion.CASCADE, related_name='contributor', to='authentication.user'), + preserve_default=False, + ), + migrations.AlterField( + model_name='ratingcontributor', + name='user', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL), + ), + migrations.AlterUniqueTogether( + name='ratingcontributor', + unique_together={('contributor', 'user')}, + ), + ] diff --git a/app/models.py b/app/models.py index f50c904311702c26984f43b30fde58c3ee278f57..e531ad121c188ab50d73c93dfbedd3eafb464389 100644 --- a/app/models.py +++ b/app/models.py @@ -253,13 +253,17 @@ class Rating(models.Model): class RatingContributor(models.Model): timestamp = models.DateTimeField(auto_now=True) score = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)]) - user = models.ForeignKey(User, on_delete=models.CASCADE) + contributor = models.ForeignKey(User, on_delete=models.CASCADE, related_name='contributor') + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user') def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if 1 <= self.score <= 5: super().save(force_insert, force_update, using, update_fields) else: raise ValidationError("Rating score must be integer between 1-5") + + class Meta: + unique_together = ["contributor", "user"] class LaporanMateri(models.Model): diff --git a/app/templates/app/katalog_kontri.html b/app/templates/app/katalog_kontri.html index 3dc7915a72348cc02da5cf53aff3dc4143963b70..38d7e95fe9db70860a996bdacc5c1cec0ece7e44 100644 --- a/app/templates/app/katalog_kontri.html +++ b/app/templates/app/katalog_kontri.html @@ -1,41 +1,33 @@ {% extends "base.html" %} {% load static %} {% load humanize %} -{% block title %}Digipus - {% endblock %} +{% block title %}Digipus - {{ contributor.name }}'s' Profile{% endblock %} {% block header %} +<meta charset="UTF-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> -<!DOCTYPE html> -<html lang="en"> +<link href="../../static/app/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> +<link href="../../static/app/css/heroic-features.css" rel="stylesheet"> -<head> - <title>Digipus Home</title> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> +<link rel="stylesheet" type="text/css" href="{% static 'app/css/katalog_materi.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'app/css/katalog_kontri.css' %}"> - <link href="../../static/app/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> - <link href="../../static/app/css/heroic-features.css" rel="stylesheet"> +<link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'css/util.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'app/css/katalog_materi.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'app/css/katalog_kontri.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'fonts/font-awesome-4.7.0/css/font-awesome.min.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'vendor/animsition/css/animsition.min.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'vendor/daterangepicker/daterangepicker.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'vendor/css-hamburgers/hamburgers.min.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'vendor/select2/select2.min.css' %}"> +<link rel="stylesheet" type="text/css" href="{% static 'vendor/animate/animate.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'css/util.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'css/styles.css' %}"> +<link rel="icon" type="image/png" href="{% static 'images/icons/logo.ico' %}" /> - <link rel="stylesheet" type="text/css" href="{% static 'fonts/font-awesome-4.7.0/css/font-awesome.min.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'vendor/animsition/css/animsition.min.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'vendor/daterangepicker/daterangepicker.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'vendor/css-hamburgers/hamburgers.min.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'vendor/select2/select2.min.css' %}"> - <link rel="stylesheet" type="text/css" href="{% static 'vendor/animate/animate.css' %}"> +{% endblock header %} - <link rel="icon" type="image/png" href="{% static 'images/icons/logo.ico' %}" /> - - - {% endblock header %} - {% block content %} - -</head> +{% block content %} <body style="background-color: #f8f8f8;"> <div class="container main"> @@ -87,10 +79,28 @@ </table> </div> </div> - <h4 id="rating">Rating: {% if avg_rating.avg_rating %}{{ avg_rating.avg_rating|floatformat:"2"|intcomma }}{% else %}0{% endif %}</h4> - <h6>oleh: {{ count_rating }} orang</h6> - <div class="row"><form method="post">{{ form_rating }} {% csrf_token %} - <button type="submit" class="form-control" style="margin-top: 1rem">Submit</button></form> </div> + <div class="row mx-5 mt-3"> + <h4 id="rating">Rating: {% if avg_rating.avg_rating %}{{ avg_rating.avg_rating|floatformat:"2"|intcomma }}{% else %}0{% endif %} + </h4> + </div> + <div class="row mx-5 mt-2"> + <h6>oleh: {{ count_rating }} orang</h6> + </div> + <div class="row mx-5 mt-3"> + {% if not user.is_authenticated %} + <h4><a href="{% url 'login' %}">Kamu harus login untuk memberi rating</a></h4> + {% else %} + <form method="post" class="form-inline">{{ form_rating }} {% csrf_token %} + {% if has_rated %} + <button class="form-control mx-3" id="updateButton">Update</button> + <button class="btn btn-danger" id="deleteButton">Delete Rating</button> + {% else %} + <button type="submit" class="form-control mx-3">Submit</button> + {% endif %} + </form> + {% endif %} + + </div> </div> </header> @@ -134,7 +144,73 @@ </div> </div> </body> - -</html> - +{% endblock %} +{% block extra_scripts %} +<script type="text/javascript"> + // using jQuery + function getCookie(name) { + var cookieValue = null; + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]); + if (cookie.substring(0, name.length + 1) == (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; + } + var csrftoken = getCookie('csrftoken'); + + function csrfSafeMethod(method) { + // these HTTP methods do not require CSRF protection + return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); + } + + function reload () { + window.location = '' + }; + + $('#deleteButton').click(function () { + console.log("anjing") + $.ajaxSetup({ + beforeSend: function (xhr, settings) { + if (!csrfSafeMethod(settings.type) && !this.crossDomain) { + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + } + }); + $.ajax({ + type: 'POST', + url: "{% url 'katalog-per-kontributor' contributor.email%}", + data: { + 'delete': true + }, + success: reload, + dataType: 'html' + }); + }); + + $('#updateButton').click(function () { + $.ajaxSetup({ + beforeSend: function (xhr, settings) { + if (!csrfSafeMethod(settings.type) && !this.crossDomain) { + xhr.setRequestHeader("X-CSRFToken", csrftoken); + } + } + }); + $.ajax({ + type: 'POST', + url: "{% url 'katalog-per-kontributor' contributor.email%}", + data: { + 'update': true, + 'score': $('#form-rating').val() + }, + success: reload, + dataType: 'html' + }); + }); +</script> {% endblock %} \ No newline at end of file diff --git a/app/tests.py b/app/tests.py index c205163662ad9273b8c20495541f3646fbcbb7a6..9f10c73f27f528bd814fb834b1084391f60514d9 100644 --- a/app/tests.py +++ b/app/tests.py @@ -428,7 +428,7 @@ class DetailMateriTest(TestCase): session_id = response.context["session_id"] payload = {"comment": comment, "session_id": session_id} - ajax_response = self.client.post("/comment/dislike/", payload) + self.client.post("/comment/dislike/", payload) num_of_comment_dislikes = DislikeComment.objects.filter(comment=comment).count() self.assertEqual(num_of_comment_dislikes, 0) @@ -443,7 +443,7 @@ class DetailMateriTest(TestCase): session_id = response.context["session_id"] payload = {"comment": comment, "session_id": session_id} - ajax_response = self.client.post("/comment/like/", payload) + self.client.post("/comment/like/", payload) num_of_comment_likes = LikeComment.objects.filter(comment=comment).count() self.assertEqual(num_of_comment_likes, 0) @@ -458,9 +458,9 @@ class DetailMateriTest(TestCase): session_id = response.context["session_id"] payload = {"comment": comment, "session_id": session_id} - ajax_response = self.client.post("/comment/dislike/", payload) + self.client.post("/comment/dislike/", payload) - ajax_response = self.client.post("/comment/dislike/", payload) + self.client.post("/comment/dislike/", payload) num_of_comment_dislikes = DislikeComment.objects.filter(comment=comment, session_id=session_id).count() self.assertEqual(num_of_comment_dislikes, 0) @@ -475,9 +475,9 @@ class DetailMateriTest(TestCase): session_id = response.context["session_id"] payload = {"comment": comment, "session_id": session_id} - ajax_response = self.client.post("/comment/like/", payload) + self.client.post("/comment/like/", payload) - ajax_response = self.client.post("/comment/like/", payload) + self.client.post("/comment/like/", payload) num_of_comment_likes = LikeComment.objects.filter(comment=comment, session_id=session_id).count() self.assertEqual(num_of_comment_likes, 0) @@ -619,7 +619,7 @@ class DetailMateriTest(TestCase): url = self.url self.client.login(**self.admin_credential) self.client.post(url, {"comment": "This is new comment by Anonymous"}) - deleteURL = "/delete/" + str(self.materi1.id) + "/" + str( + delete_url = "/delete/" + str(self.materi1.id) + "/" + str( Comment.objects.get(comment="This is new comment by Anonymous").id) if is_admin: self.client.login(**self.admin_credential) @@ -627,7 +627,7 @@ class DetailMateriTest(TestCase): self.client.login(**self.contributor_credential) if not is_admin and not is_contributor: self.client.login(**self.anonymous_credential) - response = self.client.get(deleteURL) + response = self.client.get(delete_url) return response def test_delete_comments_by_admin(self): @@ -1352,7 +1352,7 @@ class UploadExcelPageTest(TestCase): 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}) + self.client.post("/unggah_excel/", {'excel': fp}) title = data_frame['Title'][0] materi = Materi.objects.get(title=title) @@ -1618,18 +1618,7 @@ class SuksesLoginKontributorTest(TestCase): # Logout self.client.logout() - def test_sukses_login_kontributor_url(self): - # Login - self.client.login(email="kontributor@gov.id", - password="kontributor") - # Test - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - # Logout - self.client.logout() - - def test_sukses_login_kontributor_access(self): - # Kontributor + def test_sukses_login_kontributor_url_access(self): # Login self.client.login(email="kontributor@gov.id", password="kontributor") @@ -1665,18 +1654,7 @@ class SuksesLoginAdminTest(TestCase): # Logout self.client.logout() - def test_sukses_login_admin_url(self): - # Login - self.client.login(email="admin@gov.id", - password="admin") - # Test - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - # Logout - self.client.logout() - - def test_sukses_login_admin_access(self): - # Kontributor + def test_sukses_login_admin_url_access(self): # Login self.client.login(email="admin@gov.id", password="admin") @@ -1731,7 +1709,7 @@ class LikeMateriTest(TestCase): 'materi_id': materi_id, 'session_id': session_id } - ajax_response = Client().post(self.url_like, payload) + Client().post(self.url_like, payload) num_of_likes = Like.objects.filter(materi=self.materi1).count() self.assertEqual(num_of_likes, 1) @@ -1748,7 +1726,7 @@ class LikeMateriTest(TestCase): 'materi_id': materi_id, 'session_id': session_id } - ajax_response = Client().post(self.url_like, payload) + Client().post(self.url_like, payload) num_of_likes = Like.objects.filter(materi=self.materi1).count() self.assertEqual(num_of_likes, 1) @@ -1760,7 +1738,7 @@ class LikeMateriTest(TestCase): 'materi_id': materi_id, 'session_id': session_id } - ajax_response = Client().post(self.url_like, payload) + Client().post(self.url_like, payload) num_of_likes = Like.objects.filter(materi=self.materi1).count() self.assertEqual(num_of_likes, 0) @@ -1777,7 +1755,7 @@ class LikeMateriTest(TestCase): 'materi_id': materi_id, 'session_id': session_id } - ajax_response = Client().post(self.url_like, payload) + Client().post(self.url_like, payload) num_of_likes = Like.objects.filter(materi=self.materi1).count() self.assertEqual(num_of_likes, 1) @@ -1789,7 +1767,7 @@ class LikeMateriTest(TestCase): 'materi_id': materi_id, 'session_id': session_id } - ajax_response = Client().post(self.url_like, payload) + Client().post(self.url_like, payload) num_of_likes = Like.objects.filter(materi=self.materi1).count() self.assertEqual(num_of_likes, 2) @@ -1850,17 +1828,17 @@ class ViewMateriStatissticsTest(TestCase): # Test single view def test_count_one_materi_view(self): - response = self.client.get(self.url) + self.client.get(self.url) num_of_views = self.materi1.baca.all().count() self.assertEqual(num_of_views, 1) # Test more than one view def test_count_more_than_one_materi_view(self): - response = self.client.get(self.url) + self.client.get(self.url) num_of_views = self.materi1.baca.all().count() self.assertEqual(num_of_views, 1) - response = Client().get(self.url) + Client().get(self.url) num_of_views = self.materi1.baca.all().count() self.assertEqual(num_of_views, 2) @@ -1892,17 +1870,17 @@ class DownloadMateriStatissticsTest(TestCase): # Test single download def test_count_one_materi_download(self): - response = self.client.get(self.url) + self.client.get(self.url) num_of_downloads = self.materi1.unduh.all().count() self.assertEqual(num_of_downloads, 1) # Test more than one download def test_count_more_than_one_materi_download(self): - response = self.client.get(self.url) + self.client.get(self.url) num_of_downloads = self.materi1.unduh.all().count() self.assertEqual(num_of_downloads, 1) - response = Client().get(self.url) + Client().get(self.url) num_of_downloads = self.materi1.unduh.all().count() self.assertEqual(num_of_downloads, 2) @@ -1948,7 +1926,7 @@ class RevisiMateriTest(TestCase): # Logout self.client.logout() - def test_revisi_materi_url(self): + def test_revisi_materi_url_access(self): # Login self.client.login(**self.contributor_credential) # Test @@ -1957,15 +1935,6 @@ class RevisiMateriTest(TestCase): # Logout self.client.logout() - def test_revisi_materi_access(self): - # Kontributor - # Login - self.client.login(**self.contributor_credential) - # Test - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - # Logout - self.client.logout() class GenerateDummyCommandTest(TestCase): @@ -2204,7 +2173,7 @@ class RatingMateriTest(TestCase): response = self.client.get(self.url_materi) self.assertEqual(1, response.context.get('materi_rating_score')) -class fileManagementUtilTest(TestCase): +class FileManagementUtilTest(TestCase): def setUp(self): self.filename = "image_with_exif_data.gif" self.file_content = open(settings.BASE_DIR + "/app/test_files/" + @@ -2273,8 +2242,8 @@ class RequestMateriTest(TestCase): self.assertEqual(response['location'], '/login/') def test_saving_and_retrieving_material_requests(self): - first_material_request = ReqMaterial(title="Material 1").save() - second_material_request = ReqMaterial(title="Material 2").save() + ReqMaterial(title="Material 1").save() + ReqMaterial(title="Material 2").save() saved_material_request = ReqMaterial.objects.all() self.assertEqual(saved_material_request.count(), 2) @@ -2313,104 +2282,244 @@ class RequestMateriTest(TestCase): class RatingContributorTest(TransactionTestCase): def setUp(self): + self.admin_credential = { + "email": "admin@gov.id", + "password": "passwordtest" + } self.contributor_credential = { "email": "kontributor@gov.id", "password": id_generator() } + self.anonymous_credential = { + "email": "anonymous@gov.id", + "password": "passwordtest" + } + self.admin = get_user_model().objects.create_user( + **self.admin_credential, name="Admin", is_admin=True) self.contributor = get_user_model().objects.create_user( **self.contributor_credential, name="Kontributor", is_contributor=True ) + self.anonymous = get_user_model().objects.create_user( + **self.anonymous_credential, name="Anonymous" + ) + + self.url = f"/profil/{self.contributor.email}/" def test_add_rating_contributor(self): - RatingContributor.objects.create(score=3, user=self.contributor) + RatingContributor.objects.create(score=3, contributor=self.contributor, user=self.anonymous) self.assertEqual(1, RatingContributor.objects.count()) def test_add_rating_contributor_should_failed_when_negative(self): with self.assertRaises(ValidationError): - RatingContributor.objects.create(score=-1, user=self.contributor) + RatingContributor.objects.create(score=-1, contributor=self.contributor, user=self.anonymous) self.assertEqual(0, RatingContributor.objects.count()) def test_add_rating_contributor_should_failed_when_bigger_than_five(self): with self.assertRaises(ValidationError): - RatingContributor.objects.create(score=6, user=self.contributor) + RatingContributor.objects.create(score=6, contributor=self.contributor, user=self.anonymous) self.assertEqual(0, RatingContributor.objects.count()) def test_submit_form_correct_rating_contributor_should_added(self): - url = f"/profil/{self.contributor.email}/" - self.client.post(url, data={"user": self.contributor.id, "score": 5}) - self.assertEqual(1, RatingContributor.objects.filter(user=self.contributor.id).count()) - self.client.post(url, data={"user": self.contributor.id, "score": 1}) - self.assertEqual(2, RatingContributor.objects.filter(user=self.contributor.id).count()) + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 5}) + self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor.id).count()) + self.client.logout() + + self.client.login(**self.admin_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": 1}) + self.assertEqual(2, RatingContributor.objects.filter(contributor=self.contributor.id).count()) def test_submit_form_not_correct_rating_contributor_should__not_added(self): - url = f"/profil/{self.contributor.email}/" - self.client.post(url, data={"user": self.contributor.id, "score": 6}) - self.assertEqual(0, RatingContributor.objects.filter(user=self.contributor.id).count()) - self.client.post(url, data={"user": self.contributor.id, "score": 0}) - self.assertEqual(0, RatingContributor.objects.filter(user=self.contributor.id).count()) + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 6}) + self.assertEqual(0, RatingContributor.objects.filter(contributor=self.contributor.id).count()) + self.client.logout() + + self.client.login(**self.admin_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": 0}) + self.assertEqual(0, RatingContributor.objects.filter(contributor=self.contributor.id).count()) def test_average_rating_score_empty(self): - url = f"/profil/{self.contributor.email}/" - response = self.client.get(url) + response = self.client.get(self.url) self.assertTemplateUsed(response=response, template_name="app/katalog_kontri.html") self.assertContains(response=response, text="Rating: 0", count=1) self.assertContains(response=response, text="oleh: 0 orang", count=1) def test_average_rating_correct(self): - url = f"/profil/{self.contributor.email}/" - self.client.post(url, data={"user": self.contributor.id, "score": 5}) - response = self.client.get(url) + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 5}) + response = self.client.get(self.url) self.assertContains(response=response, text="Rating: 5", count=1) self.assertContains(response=response, text="oleh: 1 orang", count=1) def test_average_rating_form_incorrect_correct(self): - url = f"/profil/{self.contributor.email}/" - self.client.post(url, data={"user": self.contributor.id, "score": 6}) - response = self.client.get(url) + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": 6}) + response = self.client.get(self.url) self.assertContains(response=response, text="Rating: 0", count=1) self.assertContains(response=response, text="oleh: 0 orang", count=1) - self.client.post(url, data={"user": self.contributor.id, "score": -1}) - response = self.client.get(url) + self.client.logout() + + self.client.login(**self.admin_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": -1}) + response = self.client.get(self.url) self.assertContains(response=response, text="Rating: 0", count=1) self.assertContains(response=response, text="oleh: 0 orang", count=1) def test_average_with_multiple_score_correct(self): score = 5 avg = [score] - url = f"/profil/{self.contributor.email}/" - self.client.post(url, data={"user": self.contributor.id, "score": score}) - response = self.client.get(url) + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous.id, "score": score}) + response = self.client.get(self.url) self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.client.logout() + self.anonymous2 = get_user_model().objects.create_user( + email="anonymous2@gov.id", password="test", name="Anonymous 2" + ) score = 4 avg.append(score) - self.client.post(url, data={"user": self.contributor.id, "score": score}) - response = self.client.get(url) + self.client.login(email=self.anonymous2.email, password="test") + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous2.id, "score": score}) + response = self.client.get(self.url) self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.client.logout() + self.anonymous3 = get_user_model().objects.create_user( + email="anonymous3@gov.id", password="test", name="Anonymous 3" + ) score = 3 avg.append(score) - self.client.post(url, data={"user": self.contributor.id, "score": score}) - response = self.client.get(url) + self.client.login(email=self.anonymous3.email, password="test") + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous3.id, "score": score}) + response = self.client.get(self.url) self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.client.logout() + self.anonymous4 = get_user_model().objects.create_user( + email="anonymous4@gov.id", password="test", name="Anonymous 4" + ) score = 2 avg.append(score) - self.client.post(url, data={"user": self.contributor.id, "score": score}) - response = self.client.get(url) + self.client.login(email=self.anonymous4.email, password="test") + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.anonymous4.id, "score": score}) + response = self.client.get(self.url) self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + self.client.logout() score = 1 avg.append(score) - self.client.post(url, data={"user": self.contributor.id, "score": score}) - response = self.client.get(url) + self.client.login(**self.admin_credential) + self.client.post(self.url, data={"contributor": self.contributor.id, "user": self.admin.id, "score": score}) + response = self.client.get(self.url) self.assertContains(response=response, text=f"Rating: {mean(avg)}", count=1) self.assertContains(response=response, text=f"oleh: {len(avg)} orang", count=1) + + def test_not_authenticated_user_should_not_able_to_add_rating(self): + response_post = self.client.post(self.url, data={ + "contributor":self.contributor.id, + "user":self.anonymous.id, + "score":3 + }) + response_get = self.client.get(self.url) + self.assertEqual(response_post.status_code, 403) + self.assertContains(response_get, "Kamu harus login untuk memberi rating") + + def test_not_authenticated_user_should_not_able_to_delete_rating(self): + response_post = self.client.post(self.url, data={"delete":True}) + self.assertEqual(response_post.status_code, 403) + + def test_authenticated_user_should_not_delete_rating_if_has_not_been_rated(self): + self.client.login(**self.admin_credential) + self.client.post(self.url, data={ + "contributor":self.contributor.id, + "user":self.admin.id, + "score":3 + }) + + self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor).count()) + self.client.logout() + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={"delete":True}) + + self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor).count()) + + def test_authenticated_user_should_delete_rating_if_has_been_rated(self): + self.client.login(**self.admin_credential) + self.client.post(self.url, data={ + "contributor":self.contributor.id, + "user":self.admin.id, + "score":3 + }) + response = self.client.get(self.url) + self.assertContains(response, 'Rating: 3') + self.assertContains(response, 'oleh: 1 orang') + self.assertEqual(1, RatingContributor.objects.filter(contributor=self.contributor).count()) + + self.client.post(self.url, data={"delete":True}) + response = self.client.get(self.url) + self.assertContains(response, 'Rating: 0') + self.assertContains(response, 'oleh: 0 orang') + self.assertEqual(0, RatingContributor.objects.filter(contributor=self.contributor).count()) + + def test_average_still_be_correct_when_rating_was_deleted(self): + scores = [2,4] + self.client.login(**self.admin_credential) + self.client.post(self.url, data={ + "contributor":self.contributor.id, + "user":self.admin.id, + "score":scores[0] + }) + self.client.logout() + + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={ + "contributor":self.contributor.id, + "user":self.anonymous.id, + "score":scores[1] + }) + response = self.client.get(self.url) + self.assertContains(response, f'Rating: {mean(scores)}') + self.assertContains(response, 'oleh: 2 orang') + + self.client.post(self.url, data={"delete":True}) + response = self.client.get(self.url) + self.assertContains(response, f'Rating: {scores[0]}') + self.assertContains(response, 'oleh: 1 orang') + + def test_authenticated_user_should_update_rating_if_has_been_rated(self): + self.client.login(**self.anonymous_credential) + self.client.post(self.url, data={ + "contributor":self.contributor.id, + "user":self.anonymous.id, + "score":5 + }) + response = self.client.get(self.url) + self.assertContains(response, 'Rating: 5') + self.assertContains(response, 'oleh: 1 orang') + + self.client.post(self.url, data={"update":True, "score":3}) + response = self.client.get(self.url) + self.assertContains(response, 'Rating: 3') + self.assertContains(response, 'oleh: 1 orang') + + def test_authenticated_user_should_not_update_rating_if_has_not_been_rated(self): + self.client.login(**self.anonymous_credential) + response = self.client.get(self.url) + self.assertContains(response, 'Rating: 0') + self.assertContains(response, 'oleh: 0 orang') + + self.client.post(self.url, data={"update":True, "score":3}) + response = self.client.get(self.url) + self.assertContains(response, 'Rating: 0') + self.assertContains(response, 'oleh: 0 orang') + class UserDownloadHistoryTest(TestCase): def setUp(self): @@ -2899,8 +3008,8 @@ class YTUrlVideoTest(TestCase): ) def test_yt_video_id_exists_in_Materi(self): - materiTemp = Materi.objects.create() - self.assertEqual(hasattr(materiTemp, 'yt_video_id'), True) + materi_temp = Materi.objects.create() + self.assertEqual(hasattr(materi_temp, 'yt_video_id'), True) def test_yt_video_id_exists_in_UploadMateri_page(self): self.client.login(**self.contributor_credential) @@ -2910,7 +3019,7 @@ class YTUrlVideoTest(TestCase): def test_upload_materi_with_valid_yt_video_id(self): self.client.login(**self.contributor_credential) - response = self.client.post( + 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, @@ -2920,7 +3029,7 @@ class YTUrlVideoTest(TestCase): def test_upload_materi_with_invalid_yt_video_id(self): self.client.login(**self.contributor_credential) - response = self.client.post( + 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, @@ -2937,7 +3046,7 @@ 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( + 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,} @@ -2969,17 +3078,7 @@ class ChangePasswordTest(TestCase): # Logout self.client.logout() - def test_change_password_url(self): - # Login - self.client.login(email="kontributor@gov.id", password="kontributor") - # Test - response = self.client.get(self.url) - self.assertEqual(response.status_code, 200) - # Logout - self.client.logout() - - def test_change_password_access(self): - # Kontributor + def test_change_password_url_access(self): # Login self.client.login(email="kontributor@gov.id", password="kontributor") # Test @@ -3290,7 +3389,7 @@ class MateriRecommendationTest(TestCase): Like.objects.create(materi=materi2) Like.objects.create(materi=materi2) - materi3 = Materi.objects.create( + Materi.objects.create( title="Materi 3", author="Nandhika Prayoga", uploader=self.contributor, diff --git a/app/views.py b/app/views.py index 763dd85c0e5e4ccb23377bc7336bb54adda1b1c5..a0062ed070c2065cc77c3e37757c749b70f470d1 100644 --- a/app/views.py +++ b/app/views.py @@ -90,19 +90,51 @@ class KatalogPerKontributorView(TemplateView): page_number = request.GET.get("page") 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}) + contributor = context["contributor"] + context["form_rating"] = RatingContributorForm(initial={ + "contributor": contributor, + "user":request.user + }) 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() + .annotate(avg_rating=Avg("contributor__score"))[0] + context["count_rating"] = RatingContributor.objects.filter(contributor=contributor).count() + + if request.user.is_authenticated: + has_rated = RatingContributor.objects.filter(user=request.user, contributor=contributor).exists() + context["has_rated"] = has_rated + return self.render_to_response(context=context) def post(self, request, *args, **kwargs): - data = RatingContributorForm(request.POST) - if data.is_valid(): - data.save() - return redirect("katalog-per-kontributor", email=kwargs["email"]) + context = self.get_context_data(**kwargs) + if not request.user.is_authenticated: + raise PermissionDenied(request) + is_delete = request.POST.get('delete', None) + is_update = request.POST.get('update', None) + if is_delete: + rating_contributor = get_object_or_404( + RatingContributor, + user=request.user, + contributor=context["contributor"] + ) + rating_contributor.delete() + elif is_update: + score = request.POST.get('score', None) + rating = RatingContributor.objects.filter( + user=request.user, + contributor=context["contributor"] + ).first() + + if rating and score: + rating.score = int(score) + rating.save() + else: + data = RatingContributorForm(request.POST) + if data.is_valid(): + data.save() + + return redirect("katalog-per-kontributor", email=kwargs["email"]) class DetailMateri(TemplateView): template_name = "app/detail_materi.html"