Fakultas Ilmu Komputer UI

Commit ff4ce3df authored by MUHAMMAD EZRA RIZKIATAMA PUTRA's avatar MUHAMMAD EZRA RIZKIATAMA PUTRA
Browse files

Merge branch '1606896041-72' into 'master'

[#72] Profile: Rating for Contributor (Delete Rating)

See merge request !83
parents b8f2b16e f9afd12b
Pipeline #60039 passed with stages
in 27 minutes and 11 seconds
......@@ -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()
}
# 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')},
),
]
......@@ -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):
......
{% 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
......@@ -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 =