mirror of
https://github.com/ae-utbm/sith.git
synced 2024-10-31 19:38:04 +00:00
Merge branch 'pedagogy_v2_moderation' into 'pedagogy_v2'
Pedagogy comments moderation See merge request ae/Sith!215
This commit is contained in:
commit
4f7a8661ba
40
core/migrations/0030_auto_20190704_1500.py
Normal file
40
core/migrations/0030_auto_20190704_1500.py
Normal file
@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-07-04 13:00
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [("core", "0029_auto_20180426_2013")]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="notification",
|
||||
name="type",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("POSTER_MODERATION", "A new poster needs to be moderated"),
|
||||
("MAILING_MODERATION", "A new mailing list needs to be moderated"),
|
||||
(
|
||||
"PEDAGOGY_MODERATION",
|
||||
"A new pedagogy comment has been signaled for moderation",
|
||||
),
|
||||
("NEWS_MODERATION", "There are %s fresh news to be moderated"),
|
||||
("FILE_MODERATION", "New files to be moderated"),
|
||||
(
|
||||
"SAS_MODERATION",
|
||||
"There are %s pictures to be moderated in the SAS",
|
||||
),
|
||||
("NEW_PICTURES", "You've been identified on some pictures"),
|
||||
("REFILLING", "You just refilled of %s €"),
|
||||
("SELLING", "You just bought %s"),
|
||||
("GENERIC", "You have a notification"),
|
||||
],
|
||||
default="GENERIC",
|
||||
max_length=32,
|
||||
verbose_name="type",
|
||||
),
|
||||
)
|
||||
]
|
@ -23,11 +23,12 @@
|
||||
#
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from core.views.forms import MarkdownInput
|
||||
from core.models import User
|
||||
|
||||
from pedagogy.models import UV, UVComment
|
||||
from pedagogy.models import UV, UVComment, UVCommentReport
|
||||
|
||||
|
||||
class UVForm(forms.ModelForm):
|
||||
@ -100,3 +101,45 @@ class UVCommentForm(forms.ModelForm):
|
||||
self.fields["author"].initial = author_id
|
||||
self.fields["uv"].queryset = UV.objects.filter(id=uv_id).all()
|
||||
self.fields["uv"].initial = uv_id
|
||||
|
||||
|
||||
class UVCommentReportForm(forms.ModelForm):
|
||||
"""
|
||||
Form handeling creation and edit of an UVReport
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
model = UVCommentReport
|
||||
fields = ("comment", "reporter", "reason")
|
||||
widgets = {
|
||||
"comment": forms.HiddenInput,
|
||||
"reporter": forms.HiddenInput,
|
||||
"reason": MarkdownInput,
|
||||
}
|
||||
|
||||
def __init__(self, reporter_id, comment_id, *args, **kwargs):
|
||||
super(UVCommentReportForm, self).__init__(*args, **kwargs)
|
||||
self.fields["reporter"].queryset = User.objects.filter(id=reporter_id).all()
|
||||
self.fields["reporter"].initial = reporter_id
|
||||
self.fields["comment"].queryset = UVComment.objects.filter(id=comment_id).all()
|
||||
self.fields["comment"].initial = comment_id
|
||||
|
||||
|
||||
class UVCommentModerationForm(forms.Form):
|
||||
"""
|
||||
Form handeling bulk comment deletion
|
||||
"""
|
||||
|
||||
accepted_reports = forms.ModelMultipleChoiceField(
|
||||
UVCommentReport.objects.all(),
|
||||
label=_("Accepted reports"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
required=False,
|
||||
)
|
||||
|
||||
denied_reports = forms.ModelMultipleChoiceField(
|
||||
UVCommentReport.objects.all(),
|
||||
label=_("Denied reports"),
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
required=False,
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.20 on 2019-06-18 20:07
|
||||
# Generated by Django 1.11.20 on 2019-06-19 23:05
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
@ -190,7 +190,7 @@ class Migration(migrations.Migration):
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
("comment", models.TextField(verbose_name="comment")),
|
||||
("comment", models.TextField(blank=True, verbose_name="comment")),
|
||||
(
|
||||
"grade_global",
|
||||
models.IntegerField(
|
||||
@ -281,7 +281,26 @@ class Migration(migrations.Migration):
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
)
|
||||
),
|
||||
("reason", models.TextField(verbose_name="reason")),
|
||||
(
|
||||
"comment",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="reports",
|
||||
to="pedagogy.UVComment",
|
||||
verbose_name="report",
|
||||
),
|
||||
),
|
||||
(
|
||||
"reporter",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="reported_uv_comment",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="reporter",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
|
@ -27,6 +27,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils import timezone
|
||||
from django.core import validators
|
||||
from django.conf import settings
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
from core.models import User
|
||||
|
||||
@ -165,6 +166,13 @@ class UVComment(models.Model):
|
||||
"""
|
||||
return self.author == user or user.is_owner(self.uv)
|
||||
|
||||
@cached_property
|
||||
def is_reported(self):
|
||||
"""
|
||||
Return True if someone reported this UV
|
||||
"""
|
||||
return self.reports.exists()
|
||||
|
||||
def __str__(self):
|
||||
return "%s - %s" % (self.uv, self.author)
|
||||
|
||||
@ -176,7 +184,7 @@ class UVComment(models.Model):
|
||||
blank=False,
|
||||
)
|
||||
uv = models.ForeignKey(UV, related_name="comments", verbose_name=_("uv"))
|
||||
comment = models.TextField(_("comment"))
|
||||
comment = models.TextField(_("comment"), blank=True)
|
||||
grade_global = models.IntegerField(
|
||||
_("global grade"),
|
||||
validators=[validators.MinValueValidator(-1), validators.MaxValueValidator(4)],
|
||||
@ -251,4 +259,19 @@ class UVCommentReport(models.Model):
|
||||
Report an inapropriate comment
|
||||
"""
|
||||
|
||||
pass
|
||||
def is_owned_by(self, user):
|
||||
"""
|
||||
Can be created by a pedagogy admin, a superuser or a subscriber
|
||||
"""
|
||||
return user.is_subscribed or user.is_owner(self.comment.uv)
|
||||
|
||||
comment = models.ForeignKey(
|
||||
UVComment,
|
||||
related_name="reports",
|
||||
verbose_name=_("report"),
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
reporter = models.ForeignKey(
|
||||
User, related_name="reported_uv_comment", verbose_name=_("reporter")
|
||||
)
|
||||
reason = models.TextField(_("reason"))
|
||||
|
63
pedagogy/templates/pedagogy/moderation.jinja
Normal file
63
pedagogy/templates/pedagogy/moderation.jinja
Normal file
@ -0,0 +1,63 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
{% from 'core/macros.jinja' import select_all_checkbox %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}UV comment moderation{% endtrans %}
|
||||
{% endblock title %}
|
||||
|
||||
{% block content %}
|
||||
<form action="{{ url('pedagogy:moderation') }}", id="moderation_delete_form" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p style="margin-bottom: 1em;">{{ select_all_checkbox("moderation_delete_form") }}</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}UV{% endtrans %}</td>
|
||||
<td>{% trans %}Comment{% endtrans %}</td>
|
||||
<td>{% trans %}Reason{% endtrans %}</td>
|
||||
<td>{% trans %}Delete{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% set queryset = form.accepted_reports.field.queryset %}
|
||||
{% for widget in form.accepted_reports.subwidgets %}
|
||||
{% set report = queryset.get(id=widget.data.value) %}
|
||||
<tr>
|
||||
<td><a href="{{ url('pedagogy:uv_detail', uv_id=report.comment.uv.id) }}">{{ report.comment.uv }}</a></td>
|
||||
<td>{{ report.comment.comment|markdown }}</td>
|
||||
<td>{{ report.reason|markdown }}</td>
|
||||
<td>{{ widget.tag() }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p><input type="submit" value="{% trans %}Delete comments{% endtrans %}"></p>
|
||||
</form>
|
||||
<form action="{{ url('pedagogy:moderation') }}", id="moderation_keep_form" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<p style="margin-bottom: 1em;">{{ select_all_checkbox("moderation_keep_form") }}</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{% trans %}UV{% endtrans %}</td>
|
||||
<td>{% trans %}Comment{% endtrans %}</td>
|
||||
<td>{% trans %}Reason{% endtrans %}</td>
|
||||
<td>{% trans %}Delete{% endtrans %}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% set queryset = form.denied_reports.field.queryset %}
|
||||
{% for widget in form.denied_reports.subwidgets %}
|
||||
{% set report = queryset.get(id=widget.data.value) %}
|
||||
<tr>
|
||||
<td><a href="{{ url('pedagogy:uv_detail', uv_id=report.comment.uv.id) }}">{{ report.comment.uv }}</a></td>
|
||||
<td>{{ report.comment.comment|markdown }}</td>
|
||||
<td>{{ report.reason|markdown }}</td>
|
||||
<td>{{ widget.tag() }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p><input type="submit" value="{% trans %}Delete report{% endtrans %}"></p>
|
||||
</form>
|
||||
{% endblock content %}
|
@ -29,6 +29,10 @@
|
||||
<p><a href="{{ url('pedagogy:comment_update', comment_id=comment.id) }}">{% trans %}Edit{% endtrans %}</a></p>
|
||||
<p><a href="{{ url('pedagogy:comment_delete', comment_id=comment.id) }}">{% trans %}Delete{% endtrans %}</a></p>
|
||||
{% endif %}
|
||||
<p><a href="{{ url('pedagogy:comment_report', comment_id=comment.id) }}">{% trans %}Report{% endtrans %}</a></p>
|
||||
{% if comment.is_reported %}
|
||||
<p>{% trans %}This comment has been reported{% endtrans %}</p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -22,13 +22,14 @@
|
||||
#
|
||||
#
|
||||
|
||||
from django.conf import settings
|
||||
from django.test import TestCase
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.core.management import call_command
|
||||
|
||||
from core.models import User
|
||||
from core.models import User, Notification
|
||||
|
||||
from pedagogy.models import UV, UVComment
|
||||
from pedagogy.models import UV, UVComment, UVCommentReport
|
||||
|
||||
|
||||
def create_uv_template(user_id, code="IFC1", exclude_list=[]):
|
||||
@ -727,3 +728,323 @@ class UVSearchTest(TestCase):
|
||||
# Search with credit type
|
||||
response = self.client.get(reverse("pedagogy:guide"), {"credit_type": "TM"})
|
||||
self.assertNotContains(response, text="PA00")
|
||||
|
||||
|
||||
class UVModerationFormTest(TestCase):
|
||||
"""
|
||||
Test moderation view
|
||||
Assert access rights and if the form works well
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
|
||||
self.krophil = User.objects.get(username="krophil")
|
||||
|
||||
# Prepare a comment
|
||||
comment_kwargs = create_uv_comment_template(self.krophil.id)
|
||||
comment_kwargs["author"] = self.krophil
|
||||
comment_kwargs["uv"] = UV.objects.get(id=comment_kwargs["uv"])
|
||||
self.comment_1 = UVComment(**comment_kwargs)
|
||||
self.comment_1.save()
|
||||
|
||||
# Prepare another comment
|
||||
comment_kwargs = create_uv_comment_template(self.krophil.id)
|
||||
comment_kwargs["author"] = self.krophil
|
||||
comment_kwargs["uv"] = UV.objects.get(id=comment_kwargs["uv"])
|
||||
self.comment_2 = UVComment(**comment_kwargs)
|
||||
self.comment_2.save()
|
||||
|
||||
# Prepare a comment report for comment 1
|
||||
self.report_1 = UVCommentReport(
|
||||
comment=self.comment_1, reporter=self.krophil, reason="C'est moche"
|
||||
)
|
||||
self.report_1.save()
|
||||
self.report_1_bis = UVCommentReport(
|
||||
comment=self.comment_1, reporter=self.krophil, reason="C'est moche 2"
|
||||
)
|
||||
self.report_1_bis.save()
|
||||
|
||||
# Prepare a comment report for comment 2
|
||||
self.report_2 = UVCommentReport(
|
||||
comment=self.comment_2, reporter=self.krophil, reason="C'est moche"
|
||||
)
|
||||
self.report_2.save()
|
||||
|
||||
def test_access_authorized_success(self):
|
||||
# Test with root
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
# Test with pedagogy admin
|
||||
self.client.login(username="tutu", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
self.assertEquals(response.status_code, 200)
|
||||
|
||||
def test_access_unauthorized_fail(self):
|
||||
# Test with anonymous user
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Test with unsubscribed user
|
||||
self.client.login(username="guy", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
# Test with subscribed user
|
||||
self.client.login(username="sli", password="plop")
|
||||
response = self.client.get(reverse("pedagogy:moderation"))
|
||||
self.assertEquals(response.status_code, 403)
|
||||
|
||||
def test_do_nothing(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(reverse("pedagogy:moderation"))
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that nothing has changed
|
||||
self.assertTrue(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
self.assertTrue(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
self.assertTrue(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
|
||||
def test_delete_comment(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"), {"accepted_reports": [self.report_1.id]}
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that the comment and it's associated report has been deleted
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
# Test that the bis report has been deleted
|
||||
self.assertFalse(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
|
||||
# Test that the other comment and report still exists
|
||||
self.assertTrue(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
|
||||
def test_delete_comment_bulk(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"),
|
||||
{"accepted_reports": [self.report_1.id, self.report_2.id]},
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that comments and their associated reports has been deleted
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
# Test that the bis report has been deleted
|
||||
self.assertFalse(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
|
||||
def test_delete_comment_with_bis(self):
|
||||
# Test case if two reports targets the same comment and are both deleted
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"),
|
||||
{"accepted_reports": [self.report_1.id, self.report_1_bis.id]},
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that the comment and it's associated report has been deleted
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
# Test that the bis report has been deleted
|
||||
self.assertFalse(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
|
||||
def test_delete_report(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"), {"denied_reports": [self.report_1.id]}
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that the report has been deleted and that the comment still exists
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
# Test that the bis report is still there
|
||||
self.assertTrue(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
|
||||
# Test that the other comment and report still exists
|
||||
self.assertTrue(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
|
||||
def test_delete_report_bulk(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"),
|
||||
{
|
||||
"denied_reports": [
|
||||
self.report_1.id,
|
||||
self.report_1_bis.id,
|
||||
self.report_2.id,
|
||||
]
|
||||
},
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that every reports has been deleted
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertFalse(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
|
||||
# Test that comments still exists
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
|
||||
def test_delete_mixed(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"),
|
||||
{
|
||||
"accepted_reports": [self.report_2.id],
|
||||
"denied_reports": [self.report_1.id],
|
||||
},
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that report 2 and his comment has been deleted
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
|
||||
# Test that report 1 has been deleted and it's comment still exists
|
||||
self.assertFalse(UVCommentReport.objects.filter(id=self.report_1.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
|
||||
# Test that report 1 bis is still there
|
||||
self.assertTrue(
|
||||
UVCommentReport.objects.filter(id=self.report_1_bis.id).exists()
|
||||
)
|
||||
|
||||
def test_delete_mixed_with_bis(self):
|
||||
self.client.login(username="root", password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:moderation"),
|
||||
{
|
||||
"accepted_reports": [self.report_1.id],
|
||||
"denied_reports": [self.report_1_bis.id],
|
||||
},
|
||||
)
|
||||
self.assertEquals(response.status_code, 302)
|
||||
|
||||
# Test that report 1 and 1 bis has been deleted
|
||||
self.assertFalse(
|
||||
UVCommentReport.objects.filter(
|
||||
id__in=[self.report_1.id, self.report_1_bis.id]
|
||||
).exists()
|
||||
)
|
||||
|
||||
# Test that comment 1 has been deleted
|
||||
self.assertFalse(UVComment.objects.filter(id=self.comment_1.id).exists())
|
||||
|
||||
# Test that report and comment 2 still exists
|
||||
self.assertTrue(UVCommentReport.objects.filter(id=self.report_2.id).exists())
|
||||
self.assertTrue(UVComment.objects.filter(id=self.comment_2.id).exists())
|
||||
|
||||
|
||||
class UVCommentReportCreateTest(TestCase):
|
||||
"""
|
||||
Test report creation view view
|
||||
Assert access rights and if you can create with it
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
call_command("populate")
|
||||
|
||||
self.krophil = User.objects.get(username="krophil")
|
||||
self.tutu = User.objects.get(username="tutu")
|
||||
|
||||
# Prepare a comment
|
||||
comment_kwargs = create_uv_comment_template(self.krophil.id)
|
||||
comment_kwargs["author"] = self.krophil
|
||||
comment_kwargs["uv"] = UV.objects.get(id=comment_kwargs["uv"])
|
||||
self.comment = UVComment(**comment_kwargs)
|
||||
self.comment.save()
|
||||
|
||||
def create_report_test(self, username, success):
|
||||
self.client.login(username=username, password="plop")
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_report", kwargs={"comment_id": self.comment.id}),
|
||||
{
|
||||
"comment": self.comment.id,
|
||||
"reporter": User.objects.get(username=username).id,
|
||||
"reason": "C'est moche",
|
||||
},
|
||||
)
|
||||
if success:
|
||||
self.assertEquals(response.status_code, 302)
|
||||
else:
|
||||
self.assertEquals(response.status_code, 403)
|
||||
self.assertEquals(UVCommentReport.objects.all().exists(), success)
|
||||
|
||||
def test_create_report_root_success(self):
|
||||
self.create_report_test("root", True)
|
||||
|
||||
def test_create_report_pedagogy_admin_success(self):
|
||||
self.create_report_test("tutu", True)
|
||||
|
||||
def test_create_report_subscriber_success(self):
|
||||
self.create_report_test("sli", True)
|
||||
|
||||
def test_create_report_unsubscribed_fail(self):
|
||||
self.create_report_test("guy", False)
|
||||
|
||||
def test_create_report_anonymous_fail(self):
|
||||
response = self.client.post(
|
||||
reverse("pedagogy:comment_report", kwargs={"comment_id": self.comment.id}),
|
||||
{"comment": self.comment.id, "reporter": 0, "reason": "C'est moche"},
|
||||
)
|
||||
self.assertEquals(response.status_code, 403)
|
||||
self.assertFalse(UVCommentReport.objects.all().exists())
|
||||
|
||||
def test_notifications(self):
|
||||
self.assertFalse(
|
||||
self.tutu.notifications.filter(type="PEDAGOGY_MODERATION").exists()
|
||||
)
|
||||
# Create a comment report
|
||||
self.create_report_test("tutu", True)
|
||||
|
||||
# Check that a notification has been created for pedagogy admins
|
||||
self.assertTrue(
|
||||
self.tutu.notifications.filter(type="PEDAGOGY_MODERATION").exists()
|
||||
)
|
||||
|
||||
# Check that only pedagogy admins recieves this notification
|
||||
for notif in Notification.objects.filter(type="PEDAGOGY_MODERATION").all():
|
||||
self.assertTrue(
|
||||
notif.user.is_in_group(settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
)
|
||||
|
||||
# Check that notifications are not duplicated if not viewed
|
||||
self.create_report_test("tutu", True)
|
||||
self.assertEquals(
|
||||
self.tutu.notifications.filter(type="PEDAGOGY_MODERATION").count(), 1
|
||||
)
|
||||
|
||||
# Check that a new notification is created when the old one has been viewed
|
||||
notif = self.tutu.notifications.filter(type="PEDAGOGY_MODERATION").first()
|
||||
notif.viewed = True
|
||||
notif.save()
|
||||
|
||||
self.create_report_test("tutu", True)
|
||||
|
||||
self.assertEquals(
|
||||
self.tutu.notifications.filter(type="PEDAGOGY_MODERATION").count(), 2
|
||||
)
|
||||
|
@ -46,7 +46,6 @@ urlpatterns = [
|
||||
name="comment_report",
|
||||
),
|
||||
# Moderation
|
||||
url(r"^reported$", UVCommentReportListView.as_view(), name="comment_report_list"),
|
||||
url(r"^moderation$", UVModerationFormView.as_view(), name="moderation"),
|
||||
# Administration : Create Update Delete Edit
|
||||
url(r"^uv/create$", UVCreateView.as_view(), name="uv_create"),
|
||||
|
@ -34,7 +34,10 @@ from django.views.generic import (
|
||||
from django.core import serializers
|
||||
from django.utils import html
|
||||
from django.http import HttpResponse
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.core.exceptions import PermissionDenied, ObjectDoesNotExist
|
||||
from django.core.urlresolvers import reverse_lazy, reverse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.conf import settings
|
||||
|
||||
from core.views import (
|
||||
DetailFormView,
|
||||
@ -43,11 +46,17 @@ from core.views import (
|
||||
CanViewMixin,
|
||||
CanEditPropMixin,
|
||||
)
|
||||
from core.models import RealGroup, Notification
|
||||
|
||||
from haystack.query import SearchQuerySet
|
||||
|
||||
from pedagogy.forms import UVForm, UVCommentForm
|
||||
from pedagogy.models import UV, UVComment
|
||||
from pedagogy.forms import (
|
||||
UVForm,
|
||||
UVCommentForm,
|
||||
UVCommentReportForm,
|
||||
UVCommentModerationForm,
|
||||
)
|
||||
from pedagogy.models import UV, UVComment, UVCommentReport
|
||||
|
||||
# Some mixins
|
||||
|
||||
@ -200,28 +209,82 @@ class UVListView(CanViewMixin, CanCreateUVFunctionMixin, ListView):
|
||||
return queryset.filter(id__in=([o.object.id for o in qs]))
|
||||
|
||||
|
||||
class UVCommentReportCreateView(CreateView):
|
||||
class UVCommentReportCreateView(CanCreateMixin, CreateView):
|
||||
"""
|
||||
Create a new report for an inapropriate comment
|
||||
"""
|
||||
|
||||
pass
|
||||
model = UVCommentReport
|
||||
form_class = UVCommentReportForm
|
||||
template_name = "core/edit.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.uv_comment = get_object_or_404(UVComment, pk=kwargs["comment_id"])
|
||||
return super(UVCommentReportCreateView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
class UVCommentReportListView(ListView):
|
||||
"""
|
||||
List all UV reports for moderation (Privileged)
|
||||
"""
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(UVCommentReportCreateView, self).get_form_kwargs()
|
||||
kwargs["reporter_id"] = self.request.user.id
|
||||
kwargs["comment_id"] = self.uv_comment.id
|
||||
return kwargs
|
||||
|
||||
pass
|
||||
def form_valid(self, form):
|
||||
resp = super(UVCommentReportCreateView, self).form_valid(form)
|
||||
|
||||
# Send a message to moderation admins
|
||||
for user in (
|
||||
RealGroup.objects.filter(id=settings.SITH_GROUP_PEDAGOGY_ADMIN_ID)
|
||||
.first()
|
||||
.users.all()
|
||||
):
|
||||
if not user.notifications.filter(
|
||||
type="PEDAGOGY_MODERATION", viewed=False
|
||||
).exists():
|
||||
Notification(
|
||||
user=user,
|
||||
url=reverse("pedagogy:moderation"),
|
||||
type="PEDAGOGY_MODERATION",
|
||||
).save()
|
||||
|
||||
return resp
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy(
|
||||
"pedagogy:uv_detail", kwargs={"uv_id": self.uv_comment.uv.id}
|
||||
)
|
||||
|
||||
|
||||
class UVModerationFormView(FormView):
|
||||
"""
|
||||
List all UVs to moderate and allow to moderate them (Privileged)
|
||||
Moderation interface (Privileged)
|
||||
"""
|
||||
|
||||
form_class = UVCommentModerationForm
|
||||
template_name = "pedagogy/moderation.jinja"
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
if not request.user.is_owner(UV()):
|
||||
raise PermissionDenied
|
||||
return super(UVModerationFormView, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
form_clean = form.clean()
|
||||
for report in form_clean.get("accepted_reports", []):
|
||||
try:
|
||||
report.comment.delete() # Delete the related comment
|
||||
except ObjectDoesNotExist:
|
||||
# To avoid errors when two reports points the same comment
|
||||
pass
|
||||
for report in form_clean.get("denied_reports", []):
|
||||
try:
|
||||
report.delete() # Delete the report itself
|
||||
except ObjectDoesNotExist:
|
||||
# To avoid errors when two reports points the same comment
|
||||
pass
|
||||
return super(UVModerationFormView, self).form_valid(form)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy("pedagogy:moderation")
|
||||
|
||||
|
||||
class UVCreateView(CanCreateMixin, CreateView):
|
||||
|
@ -560,6 +560,10 @@ SITH_LAUNDERETTE_PRICES = {"WASHING": 1.0, "DRYING": 0.75}
|
||||
SITH_NOTIFICATIONS = [
|
||||
("POSTER_MODERATION", _("A new poster needs to be moderated")),
|
||||
("MAILING_MODERATION", _("A new mailing list needs to be moderated")),
|
||||
(
|
||||
"PEDAGOGY_MODERATION",
|
||||
_("A new pedagogy comment has been signaled for moderation"),
|
||||
),
|
||||
("NEWS_MODERATION", _("There are %s fresh news to be moderated")),
|
||||
("FILE_MODERATION", _("New files to be moderated")),
|
||||
("SAS_MODERATION", _("There are %s pictures to be moderated in the SAS")),
|
||||
|
Loading…
Reference in New Issue
Block a user