diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 5050adda..a34f65c0 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-06-10 20:18+0200\n" +"POT-Creation-Date: 2026-08-21 14:10+0200\n" "PO-Revision-Date: 2016-07-18\n" "Last-Translator: Maréchal \n" @@ -4969,6 +4969,10 @@ msgstr "Ne pas voter" msgid "This user has already commented on this UE" msgstr "Cet utilisateur a déjà commenté cette UE" +#: pedagogy/forms.py +msgid "UE comment can't be empty." +msgstr "Un commentaire d'UE ne peut pas être vide." + #: pedagogy/forms.py msgid "Accepted reports" msgstr "Signalements acceptés" diff --git a/pedagogy/forms.py b/pedagogy/forms.py index e2ca430b..d0623731 100644 --- a/pedagogy/forms.py +++ b/pedagogy/forms.py @@ -22,6 +22,8 @@ # from django import forms +from django.contrib.staticfiles.storage import staticfiles_storage +from django.forms.fields import ValidationError from django.utils.translation import gettext_lazy as _ from core.models import User @@ -30,7 +32,7 @@ from pedagogy.models import UE, UEComment, UECommentReport class UEForm(forms.ModelForm): - """Form handeling creation and edit of an UE.""" + """Form handling creation and edit of an UE.""" class Meta: model = UE @@ -68,22 +70,28 @@ class UEForm(forms.ModelForm): self.fields["author"].initial = author_id -class StarList(forms.NumberInput): +class StarList(forms.RadioSelect): template_name = "pedagogy/starlist.jinja" - def __init__(self, nubmer_of_stars=0): - super().__init__(None) - self.number_of_stars = nubmer_of_stars + def __init__(self, number_of_stars=0, attrs=None): + super().__init__( + attrs=attrs, + choices=( + (choice, _("Do not vote") if choice == -1 else choice) + for choice in range(-1, number_of_stars) + ), + ) def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) - context["number_of_stars"] = range(0, self.number_of_stars) - context["translations"] = {"do_not_vote": _("Do not vote")} + context["statics"] = { + "css": staticfiles_storage.url("pedagogy/css/starlist.scss"), + } return context class UECommentForm(forms.ModelForm): - """Form handeling creation and edit of an UEComment.""" + """Form handling creation and edit of an UEComment.""" class Meta: model = UEComment @@ -129,11 +137,25 @@ class UECommentForm(forms.ModelForm): ), ) + # Ensure that at least one value is exists + if ( + all( + grade == -1 + for grade in [ + self.cleaned_data[key] + for key in self.cleaned_data + if key.startswith("grade_") + ] + ) + and not self.cleaned_data["comment"] + ): + raise ValidationError(message=_("UE comment can't be empty.")) + return self.cleaned_data class UECommentReportForm(forms.ModelForm): - """Form handeling creation and edit of an UEReport.""" + """Form handling creation and edit of an UEReport.""" class Meta: model = UECommentReport @@ -153,7 +175,7 @@ class UECommentReportForm(forms.ModelForm): class UECommentModerationForm(forms.Form): - """Form handeling bulk comment deletion.""" + """Form handling bulk comment deletion.""" accepted_reports = forms.ModelMultipleChoiceField( UECommentReport.objects.all(), diff --git a/pedagogy/static/pedagogy/css/pedagogy.scss b/pedagogy/static/pedagogy/css/pedagogy.scss index eeacedfe..f0b9863d 100644 --- a/pedagogy/static/pedagogy/css/pedagogy.scss +++ b/pedagogy/static/pedagogy/css/pedagogy.scss @@ -520,40 +520,4 @@ details.accordion>.accordion-content { background-color: $white-color; border-color: $pedagogy-orange; border-right: none; -} - -fieldset.star { - label { - display: inline; - cursor: pointer; - } - - .checked { - color: orange; - } - - .unchecked { - color: gray; - } - - .hovered { - color: #FFD700; - } - - .checked.hovered { - color: orange; - } - - .removed { - color: red; - } - - input[type="radio"] { - display: none; - } - - label:first-child { - margin-right: 10px; - } - } \ No newline at end of file diff --git a/pedagogy/static/pedagogy/css/starlist.scss b/pedagogy/static/pedagogy/css/starlist.scss new file mode 100644 index 00000000..43d1b05d --- /dev/null +++ b/pedagogy/static/pedagogy/css/starlist.scss @@ -0,0 +1,42 @@ +fieldset.star { + border: none; + + label { + display: inline; + cursor: pointer; + } + + .checked { + color: orange; + } + + .unchecked { + color: gray; + } + + .hovered { + color: #FFD700; + } + + .checked.hovered { + color: orange; + } + + .removed { + color: red; + } + + input[type="radio"] { + display: none; + } + + label:first-child { + margin-right: 10px; + } + + &:has(input:required:invalid) { + border: 1px solid; + border-color: #c00000; + } + +} \ No newline at end of file diff --git a/pedagogy/templates/pedagogy/starlist.jinja b/pedagogy/templates/pedagogy/starlist.jinja index a122d6b8..275f012e 100644 --- a/pedagogy/templates/pedagogy/starlist.jinja +++ b/pedagogy/templates/pedagogy/starlist.jinja @@ -1,44 +1,52 @@ -
- {# Do not vote button #} -
\ No newline at end of file diff --git a/pedagogy/templates/pedagogy/ue_detail.jinja b/pedagogy/templates/pedagogy/ue_detail.jinja index f5118c42..93423afd 100644 --- a/pedagogy/templates/pedagogy/ue_detail.jinja +++ b/pedagogy/templates/pedagogy/ue_detail.jinja @@ -89,13 +89,14 @@

{% trans %}You already posted a comment on this UE. If you want to comment again, please modify or delete your previous comment.{% endtrans %}

{% elif user.has_perm("pedagogy.add_uecomment") %} -
+
{% trans %}Leave comment{% endtrans %}
{% csrf_token %}
+ {{ form.non_field_errors() }} {{ form.author.errors }} {{ form.ue.errors }} diff --git a/pedagogy/tests/tests.py b/pedagogy/tests/tests.py index 671a698c..b638516e 100644 --- a/pedagogy/tests/tests.py +++ b/pedagogy/tests/tests.py @@ -339,6 +339,24 @@ class TestUVCommentCreationAndDisplay(TestCase): response = self.client.get(self.ue_url) self.assertContains(response, text="Superbe UE") + def test_create_ue_empty_comment_fail(self): + self.client.force_login(self.tutu) + response = self.client.post( + self.ue_url, + { + "author": self.tutu.id, + "ue": UE.objects.get(code="PA00").id, + "grade_global": -1, + "grade_utility": -1, + "grade_interest": -1, + "grade_teaching": -1, + "grade_work_load": -1, + "comment": "", + }, + ) + assert response.status_code == 200 + self.assertInHTML("Un commentaire d'UE ne peut pas être vide.", response.text) + def test_create_ue_comment_unauthorized_fail(self): nb_comments = self.ue.comments.count() # Test with anonymous user