Fakultas Ilmu Komputer UI

Commit 46cff8ea authored by Bunga Amalia Kurniawati's avatar Bunga Amalia Kurniawati 🌺
Browse files

Merge branch '1706022104-32' into 'master'

[#32] Material: Like/Dislike on a Comment

See merge request !50
parents 796c9dba f77f1928
Pipeline #58193 passed with stages
in 14 minutes and 19 seconds
# Generated by Django 3.1 on 2020-10-09 16:19
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('app', '0020_merge_20201009_2039'),
]
operations = [
migrations.CreateModel(
name='LikeComment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('session_id', models.CharField(max_length=32)),
('comment', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='app.comment')),
],
),
migrations.CreateModel(
name='DislikeComment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timestamp', models.DateTimeField(default=django.utils.timezone.now)),
('session_id', models.CharField(max_length=32)),
('comment', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='app.comment')),
],
),
]
......@@ -108,6 +108,28 @@ class Comment(models.Model):
def __str__(self):
return self.username
@property
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 LikeComment(models.Model):
comment = models.ForeignKey(Comment, models.SET_NULL, null=True)
timestamp = models.DateTimeField(default=timezone.now)
session_id = models.CharField(max_length=32, blank=False)
class DislikeComment(models.Model):
comment = models.ForeignKey(Comment, models.SET_NULL, null=True)
timestamp = models.DateTimeField(default=timezone.now)
session_id = models.CharField(max_length=32, blank=False)
class Like(models.Model):
materi = models.ForeignKey(Materi, models.SET_NULL, null=True)
......
......@@ -288,11 +288,35 @@
{% else %}
<span style="background-color: #{{comment.profile}}" class="profile p-1 bd-highligh"></span>
{% endif %}
<p class="p-1 bd-highligh m-0"><strong>{{comment.user.name}}</strong></p>
<p class="p-1 bd-highligh m-0"></p>
<p class="timestamp p-1 bd-highligh m-0 text-muted">
{{ comment.timestamp|naturaltime }}
</p>
<div class="d-flex flex-row justify-content-end">
<p class="p-1 bd-highligh m-0"><strong>{{comment.user.name}}</strong></p>
<p class="p-1 bd-highligh m-0"></p>
<p class="timestamp p-1 bd-highligh m-0 text-muted">
{{ comment.timestamp|naturaltime }}
</p>
<div>
<button id="thumb-like-comment-{{ comment.id }}" class="btn btn-link btn-book shadow-sm p-2 mr-2 bg-white rounded" onClick="postLikeComment({{ comment.id }})">
<div class="d-flex flex-row">
{% if has_liked.comment.id %}
<i id="thumb-like-comment-icon-{{ comment.id }}" aria-hidden="true" class="fas fa-thumbs-up"></i>
{% else %}
<i id="thumb-like-comment-icon-{{ comment.id }}" aria-hidden="true" class="far fa-thumbs-up"></i>
{% endif %}
<div id="like-comment-{{ comment.id }}">{{ comment.like_count }}</div>
</div
</button>
<button id="thumb-dislike-comment-{{ comment.id }}" class="btn btn-link btn-book shadow-sm p-2 mr-2 bg-white rounded" onClick="postDislikeComment({{ comment.id }})">
<div class="d-flex flex-row">
{% if has_disliked.comment.id %}
<i id="thumb-dislike-comment-icon-{{ comment.id }}" aria-hidden="true" class="fas fa-thumbs-down"></i>
{% else %}
<i id="thumb-dislike-comment-icon-{{ comment.id }}" aria-hidden="true" class="far fa-thumbs-down"></i>
{% endif %}
<div id="dislike-comment-{{ comment.id }}">{{ comment.dislike_count }}</div>
</div>
</button>
</div>
</div>
{% if user.is_admin %}
<a class="ml-auto p-1 bd-highlight close"
href="{% url 'delete-comment' materi_data.id comment.id %}">
......@@ -426,6 +450,46 @@
});
});
function postLikeComment(comment_id) {
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$.ajax({
type: 'POST',
url: "{% url 'comment-like-toggle' %}",
data: {
'comment_id': comment_id,
'session_id': "{{ session_id }}"
},
success: likeComment,
dataType: 'html'
});
}
function postDislikeComment(comment_id) {
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$.ajax({
type: 'POST',
url: "{% url 'comment-dislike-toggle' %}",
data: {
'comment_id': comment_id,
'session_id': "{{ session_id }}"
},
success: dislikeComment,
dataType: 'html'
});
}
function postAddRating(rating_score) {
$.ajaxSetup({
beforeSend: function (xhr, settings) {
......@@ -463,6 +527,32 @@
document.getElementById("thumb").firstChild.data = " Disukai"
}
}
function likeComment(data, jqXHR) {
var data = $.parseJSON(data)
likeIcon = $('#thumb-like-comment-icon-' + data['comment_id'])
likeValue = $('#like-comment-' + data['comment_id'])
if (data['liked']) {
likeIcon.removeClass("fas fa-thumbs-up").addClass('far fa-thumbs-up')
likeValue.text(parseInt(likeValue.text())-1)
} else {
likeIcon.removeClass("far fa-thumbs-up").addClass('fas fa-thumbs-up')
likeValue.text(parseInt(likeValue.text())+1)
}
}
function dislikeComment(data, jqXHR) {
var data = $.parseJSON(data)
dislikeIcon = $('#thumb-dislike-comment-icon-' + data['comment_id'])
dislikeValue = $('#dislike-comment-' + data['comment_id'])
if (data['disliked']) {
dislikeIcon.removeClass("fas fa-thumbs-down").addClass('far fa-thumbs-down')
dislikeValue.text(parseInt(dislikeValue.text())-1)
} else {
dislikeIcon.removeClass("far fa-thumbs-down").addClass('fas fa-thumbs-down')
dislikeValue.text(parseInt(dislikeValue.text())+1)
}
}
function getCitation(text){
var $temp = $("<input>");
......
......@@ -28,9 +28,11 @@ from digipus.settings import TIME_ZONE
from .models import (
Category,
Comment,
DislikeComment,
DownloadStatistics,
Materi,
Like,
LikeComment,
Rating,
ReqMaterial,
RatingContributor,
......@@ -363,6 +365,96 @@ class DetailMateriTest(TestCase):
response = self.client.get(url)
self.assertContains(response, "Anonymous")
def test_comment_disliked_by_anonymous(self):
url_materi = self.url
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
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()
self.assertEqual(num_of_comment_dislikes, 0)
def test_comment_liked_by_anonymous(self):
url_materi = self.url
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
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()
self.assertEqual(num_of_comment_likes, 0)
def test_comment_undisliked_by_anonymous(self):
url_materi = self.url
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")
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()
self.assertEqual(num_of_comment_dislikes, 0)
def test_comment_unliked_by_anonymous(self):
url_materi = self.url
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")
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()
self.assertEqual(num_of_comment_likes, 0)
def test_comment_new_does_not_have_dislike(self):
url_materi = self.url
self.client.get("/logout/")
self.client.login(**self.anonymous_credential)
response = self.client.get(url_materi)
session_id = response.context["session_id"]
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()
self.assertEqual(comment_dislike_counter, 0)
def test_comment_new_does_not_have_like(self):
url_materi = self.url
self.client.get("/logout/")
self.client.login(**self.anonymous_credential)
response = self.client.get(url_materi)
session_id = response.context["session_id"]
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()
self.assertEqual(comment_like_counter, 0)
def test_detail_materi_contains_form_comment(self):
self.client.login(**self.contributor_credential)
response = self.client.get(self.url)
......
......@@ -13,6 +13,8 @@ urlpatterns = [
path("materi/like/", views.toggle_like, name="PostLikeToggle"),
path("delete/<int:pk_materi>/<int:pk_comment>",
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("materi/<int:pk>/delete", views.delete_materi, name="detele-materi"),
path("materi/<int:pk>/unduh", views.download_materi, name="download-materi"),
path("materi/<int:pk>/view", views.view_materi, name="view-materi"),
......
......@@ -20,8 +20,10 @@ from app.forms import SuntingProfilForm, UploadMateriForm, RatingContributorForm
from app.models import (
Category,
Comment,
DislikeComment,
Materi,
Like,
LikeComment,
ViewStatistics,
DownloadStatistics,
ReqMaterial,
......@@ -169,7 +171,14 @@ class DetailMateri(TemplateView):
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
query_set_for_comment = Comment.objects.filter(materi=context["materi_data"])
has_liked = {}
has_disliked = {}
for comment in query_set_for_comment:
has_liked[comment.id] = LikeComment.objects.filter(comment=comment, session_id=self.request.session.session_key).exists()
has_disliked[comment.id] = DislikeComment.objects.filter(comment=comment, session_id=self.request.session.session_key).exists()
context["comment_data"] = query_set_for_comment
context["has_liked"] = has_liked
context["has_disliked"] = has_disliked
return self.render_to_response(context=context)
def get_user_name(self, request):
......@@ -227,6 +236,41 @@ def delete_comment(request, pk_materi, pk_comment):
comment.delete()
return HttpResponseRedirect(url)
def toggle_like_comment(request):
if request.method == "POST":
comment_id = request.POST.get("comment_id", None)
session_id = request.POST.get("session_id", None)
if comment_id is None or session_id is None:
return JsonResponse({"success": False, "msg": "Missing parameter", "comment_id": comment_id})
comment = get_object_or_404(Comment, pk=comment_id)
has_liked = LikeComment.objects.filter(comment=comment, session_id=session_id).exists()
if has_liked:
like = get_object_or_404(LikeComment, comment=comment, session_id=session_id)
like.delete()
return JsonResponse({"success": True, "liked": True, "comment_id": comment_id})
else:
LikeComment(comment=comment, session_id=session_id).save()
return JsonResponse({"success": True, "liked": False, "comment_id": comment_id})
else:
return JsonResponse({"success": False, "msg": "Unsuported method", "comment_id": comment_id})
def toggle_dislike_comment(request):
if request.method == "POST":
comment_id = request.POST.get("comment_id", None)
session_id = request.POST.get("session_id", None)
if comment_id is None or session_id is None:
return JsonResponse({"success": False, "msg": "Missing parameter", "comment_id": comment_id})
comment = get_object_or_404(Comment, pk=comment_id)
has_disliked = DislikeComment.objects.filter(comment=comment, session_id=session_id).exists()
if has_disliked:
dislike = get_object_or_404(DislikeComment, comment=comment, session_id=session_id)
dislike.delete()
return JsonResponse({"success": True, "disliked": True, "comment_id": comment_id})
else:
DislikeComment(comment=comment, session_id=session_id).save()
return JsonResponse({"success": True, "disliked": False, "comment_id": comment_id})
else:
return JsonResponse({"success": False, "msg": "Unsuported method", "comment_id": comment_id})
def get_citation_ieee(request, materi):
current_date = datetime.datetime.now()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment