mirror of
https://github.com/ae-utbm/sith.git
synced 2026-09-17 17:54:22 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46318be572 | ||
|
|
ee6b4d4b1e | ||
|
|
22bf38beaf |
+55
-4
@@ -1,15 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
import typing
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.backends import ModelBackend
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.db.models import Exists, OuterRef, Q, QuerySet
|
||||
|
||||
from core.models import Group
|
||||
from core.models import Group, User
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from core.models import User
|
||||
if typing.TYPE_CHECKING:
|
||||
from django.db.models.base import Model
|
||||
|
||||
|
||||
class SithModelBackend(ModelBackend):
|
||||
@@ -40,3 +41,53 @@ class SithModelBackend(ModelBackend):
|
||||
return Permission.objects.filter(
|
||||
group__group__in=groups.values_list("pk", flat=True)
|
||||
)
|
||||
|
||||
@typing.override
|
||||
def with_perm(
|
||||
self,
|
||||
perm: str | Permission,
|
||||
is_active: bool | None = True,
|
||||
include_superusers: bool = False,
|
||||
obj: Model | None = None,
|
||||
) -> QuerySet[User]:
|
||||
"""Return users that have permission "perm".
|
||||
|
||||
Contrary to the base django method, superusers aren't included in the
|
||||
result.
|
||||
This is because the OR operation to include superusers in the query result
|
||||
utterly destroy the query performances on postgres
|
||||
(it makes it like 1000x slower, and I'm not even kidding).
|
||||
To overcome that, we could use a UNION instead, but then we wouldn't
|
||||
be able to perform further filter operations on the queryset.
|
||||
Thus, the `include_superusers` argument is not used at all.
|
||||
|
||||
Because of that, it is useless to set `include_superusers`,
|
||||
as it will be silently ignored.
|
||||
The only reason it's still there is not to break the interface
|
||||
of the base class.
|
||||
"""
|
||||
if isinstance(perm, str):
|
||||
try:
|
||||
app_label, codename = perm.split(".")
|
||||
except ValueError as e:
|
||||
raise ValueError(
|
||||
"Permission name should be in the form "
|
||||
"app_label.permission_codename."
|
||||
) from e
|
||||
permission_q = Q(codename=codename, content_type__app_label=app_label)
|
||||
elif isinstance(perm, Permission):
|
||||
permission_q = Q(pk=perm.pk)
|
||||
else:
|
||||
raise TypeError(
|
||||
"The `perm` argument must be a string or a permission instance."
|
||||
)
|
||||
|
||||
user_q = Exists(
|
||||
Permission.objects.filter(
|
||||
Q(group__group__users=OuterRef("pk")) | Q(user=OuterRef("pk")),
|
||||
permission_q,
|
||||
)
|
||||
)
|
||||
if is_active is not None:
|
||||
user_q &= Q(is_active=is_active)
|
||||
return User.objects.filter(user_q)
|
||||
|
||||
@@ -747,6 +747,7 @@ class Command(BaseCommand):
|
||||
"add_subscription",
|
||||
"add_membership",
|
||||
"view_hidden_user",
|
||||
"add_refilling",
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
@@ -42,7 +42,6 @@ details.accordion>.accordion-content {
|
||||
background: #ffffff;
|
||||
color: #333333;
|
||||
padding: 1em 2.2em;
|
||||
margin-top: 0;
|
||||
border: 1px solid #dddddd;
|
||||
border-bottom-right-radius: 3px;
|
||||
border-bottom-left-radius: 3px;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import pytest
|
||||
from django.contrib.auth.models import Permission
|
||||
from model_bakery import baker
|
||||
|
||||
from core.models import Group, User
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_with_perm():
|
||||
"""Test that `SithModelBackend.with_perm` works as intended."""
|
||||
perms = baker.make(Permission, _quantity=4)
|
||||
groups = baker.make(Group, _quantity=2)
|
||||
groups[0].permissions.set(perms[0:2])
|
||||
groups[1].permissions.set(perms[2:4])
|
||||
users = [
|
||||
baker.make(User),
|
||||
baker.make(User, groups=[groups[0]]),
|
||||
baker.make(User, groups=[groups[1]]),
|
||||
baker.make(User, user_permissions=[perms[0]]),
|
||||
baker.make(User, user_permissions=[perms[2]]),
|
||||
baker.make(User, groups=[groups[1]], user_permissions=[perms[0]]),
|
||||
]
|
||||
|
||||
expected = [users[1], users[3], users[5]]
|
||||
assert list(User.objects.with_perm(perms[0])) == expected
|
||||
str_repr = f"{perms[0].content_type.app_label}.{perms[0].codename}"
|
||||
assert list(User.objects.with_perm(str_repr)) == expected
|
||||
+11
-6
@@ -669,13 +669,18 @@ class Counter(models.Model):
|
||||
"""Update the barman activity to prevent timeout."""
|
||||
self.permanencies.filter(end=None).update(activity=timezone.now())
|
||||
|
||||
@cached_property
|
||||
def can_refill(self) -> bool:
|
||||
"""Show if the counter authorize the refilling with physic money."""
|
||||
if self.type != "BAR":
|
||||
return False
|
||||
# at least one of the barmen is in the AE board
|
||||
ae = Club.objects.get(id=settings.SITH_MAIN_CLUB_ID)
|
||||
return any(ae.get_membership_for(barman) for barman in self.barmen_list)
|
||||
"""Show if the counter authorize the refilling with physic money.
|
||||
|
||||
Refills are authorized if a user having the required permission
|
||||
is currently logged in.
|
||||
"""
|
||||
return self.type == "BAR" and (
|
||||
User.objects.with_perm("counter.add_refilling")
|
||||
.filter(id__in=[u.id for u in self.barmen_list])
|
||||
.exists()
|
||||
)
|
||||
|
||||
def get_top_barmen(self) -> QuerySet:
|
||||
"""Return a QuerySet querying the office hours stats of all the barmen of all time
|
||||
|
||||
@@ -108,6 +108,13 @@ class TestFullClickBase(TestCase):
|
||||
|
||||
|
||||
class TestRefilling(TestFullClickBase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
super().setUpTestData()
|
||||
cls.board_admin.user_permissions.add(
|
||||
Permission.objects.get(codename="add_refilling")
|
||||
)
|
||||
|
||||
def login_in_bar(self, barmen: User | None = None):
|
||||
used_barman = barmen if barmen is not None else self.board_admin
|
||||
self.client.post(
|
||||
@@ -147,7 +154,7 @@ class TestRefilling(TestFullClickBase):
|
||||
assert self.updated_amount(self.customer) == 0
|
||||
|
||||
def test_refilling_no_refer_fail(self):
|
||||
"""Check that the refill fails is the HTTP_REFERER header is missing"""
|
||||
"""Check that the refill fails if the HTTP_REFERER header is missing"""
|
||||
|
||||
def refill():
|
||||
return self.client.post(
|
||||
|
||||
@@ -204,7 +204,7 @@ class CounterClick(
|
||||
res["student_card_fragment"] = StudentCardFormFragment.as_fragment()(
|
||||
self.request, customer=self.customer
|
||||
)
|
||||
if self.object.can_refill():
|
||||
if self.object.can_refill:
|
||||
res["refilling_fragment"] = RefillingCreateView.as_fragment()(
|
||||
self.request, customer=self.customer, counter=self.object
|
||||
)
|
||||
@@ -250,7 +250,7 @@ class RefillingCreateView(FragmentMixin, CreateView):
|
||||
if not (
|
||||
request.barmen
|
||||
and request.barmen.issubset(self.counter.barmen_list)
|
||||
and self.counter.can_refill()
|
||||
and self.counter.can_refill
|
||||
):
|
||||
raise PermissionDenied
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-09-14 11:48+0200\n"
|
||||
"POT-Creation-Date: 2026-09-09 07:21+0200\n"
|
||||
"PO-Revision-Date: 2016-07-18\n"
|
||||
"Last-Translator: Maréchal <thomas.girod@utbm.fr\n"
|
||||
"Language-Team: AE info <ae.info@utbm.fr>\n"
|
||||
@@ -736,9 +736,8 @@ msgstr "Méthode de paiement"
|
||||
#: counter/templates/counter/fragments/create_student_card.jinja
|
||||
#: counter/templates/counter/last_ops.jinja
|
||||
#: election/templates/election/election_detail.jinja
|
||||
#: forum/templates/forum/macros.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/guide.jinja sas/templates/sas/album.jinja
|
||||
#: forum/templates/forum/macros.jinja pedagogy/templates/pedagogy/guide.jinja
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja sas/templates/sas/album.jinja
|
||||
#: sas/templates/sas/moderation.jinja sas/templates/sas/picture.jinja
|
||||
#: trombi/templates/trombi/detail.jinja
|
||||
#: trombi/templates/trombi/edit_profile.jinja
|
||||
@@ -932,9 +931,8 @@ msgstr "Outils"
|
||||
#: counter/templates/counter/cash_summary_list.jinja
|
||||
#: counter/templates/counter/counter_list.jinja
|
||||
#: election/templates/election/election_detail.jinja
|
||||
#: forum/templates/forum/macros.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/guide.jinja sas/templates/sas/album.jinja
|
||||
#: forum/templates/forum/macros.jinja pedagogy/templates/pedagogy/guide.jinja
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja sas/templates/sas/album.jinja
|
||||
#: trombi/templates/trombi/detail.jinja
|
||||
#: trombi/templates/trombi/edit_profile.jinja
|
||||
msgid "Edit"
|
||||
@@ -1190,9 +1188,8 @@ msgstr "Actions"
|
||||
|
||||
#: com/templates/com/mailing_admin.jinja com/templates/com/poster_list.jinja
|
||||
#: core/templates/core/file_detail.jinja
|
||||
#: core/templates/core/file_moderation.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: sas/templates/sas/moderation.jinja sas/templates/sas/picture.jinja
|
||||
#: core/templates/core/file_moderation.jinja sas/templates/sas/moderation.jinja
|
||||
#: sas/templates/sas/picture.jinja
|
||||
msgid "Moderate"
|
||||
msgstr "Modérer"
|
||||
|
||||
@@ -1494,6 +1491,7 @@ msgstr "Descendre"
|
||||
|
||||
#: com/templates/com/weekmail_preview.jinja
|
||||
#: core/templates/core/user_account_detail.jinja
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
#: trombi/templates/trombi/comment_moderation.jinja
|
||||
#: trombi/templates/trombi/export.jinja
|
||||
msgid "Back"
|
||||
@@ -1844,9 +1842,7 @@ msgstr "Un utilisateur de ce nom d'utilisateur existe déjà"
|
||||
#: core/models.py core/templates/core/macros.jinja
|
||||
#: core/templates/core/user_detail.jinja core/templates/core/user_edit.jinja
|
||||
#: election/templates/election/election_detail.jinja
|
||||
#: forum/templates/forum/macros.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: trombi/templates/trombi/user_tools.jinja
|
||||
#: forum/templates/forum/macros.jinja trombi/templates/trombi/user_tools.jinja
|
||||
msgid "Profile"
|
||||
msgstr "Profil"
|
||||
|
||||
@@ -2237,7 +2233,6 @@ msgstr "Confirmation"
|
||||
#: core/templates/core/file_delete_confirm.jinja
|
||||
#: counter/templates/counter/counter_click.jinja
|
||||
#: counter/templates/counter/fragments/delete_student_card.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/comment_report.jinja
|
||||
#: sas/templates/sas/ask_picture_removal.jinja
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
@@ -3784,6 +3779,7 @@ msgstr "Coffre vidé"
|
||||
|
||||
#: counter/templates/counter/cash_summary_list.jinja counter/views/cash.py
|
||||
#: pedagogy/templates/pedagogy/moderation.jinja
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
#: trombi/templates/trombi/comment.jinja
|
||||
#: trombi/templates/trombi/user_tools.jinja
|
||||
msgid "Comment"
|
||||
@@ -5113,62 +5109,6 @@ msgstr "signaler"
|
||||
msgid "reporter"
|
||||
msgstr "signalant"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/comment_report.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
msgid "Report"
|
||||
msgstr "Signaler"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_comment_form.jinja
|
||||
msgid "Leave comment"
|
||||
msgstr "Laisser un commentaire"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: trombi/templates/trombi/export.jinja
|
||||
msgid "Comments"
|
||||
msgstr "Commentaires"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
msgid "This comment has been reported"
|
||||
msgstr "Ce commentaire a été signalé"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
msgid "It will be hidden until moderated."
|
||||
msgstr "Il sera caché tant qu'il ne sera pas modéré."
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/grade.jinja
|
||||
msgid "Global grade"
|
||||
msgstr "Note globale"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/grade.jinja
|
||||
msgid "Utility"
|
||||
msgstr "Utilité"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/grade.jinja
|
||||
msgid "Interest"
|
||||
msgstr "Intérêt"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/grade.jinja
|
||||
msgid "Teaching"
|
||||
msgstr "Enseignement"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/comments.jinja
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/grade.jinja
|
||||
msgid "Workload"
|
||||
msgstr "Charge de travail"
|
||||
|
||||
#: pedagogy/templates/pedagogy/fragments/ue_detail/ue_detail.jinja
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid ""
|
||||
"You already posted a comment on this UE. If you want to comment again, "
|
||||
"please modify or delete your previous comment."
|
||||
msgstr ""
|
||||
"Vous avez déjà commenté cette UE. Si vous voulez de nouveau commenter, "
|
||||
"veuillez modifier ou supprimer votre commentaire précédent."
|
||||
|
||||
#: pedagogy/templates/pedagogy/guide.jinja
|
||||
msgid "A guide of courses available at UTBM."
|
||||
msgstr "Un guide de tous les cours disponibles à l'UTBM."
|
||||
@@ -5177,10 +5117,6 @@ msgstr "Un guide de tous les cours disponibles à l'UTBM."
|
||||
msgid "Search UE"
|
||||
msgstr "Recherche d'UE"
|
||||
|
||||
#: pedagogy/templates/pedagogy/guide.jinja
|
||||
msgid "Hide closed UEs"
|
||||
msgstr "Cacher les UEs fermées"
|
||||
|
||||
#: pedagogy/templates/pedagogy/guide.jinja
|
||||
#, python-format
|
||||
msgid "%(display_name)s"
|
||||
@@ -5234,20 +5170,44 @@ msgid "UE Details"
|
||||
msgstr "Détails d'UE"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Category"
|
||||
msgstr "Catégorie"
|
||||
msgid "CM: "
|
||||
msgstr "CM : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Credits"
|
||||
msgstr "Crédits"
|
||||
msgid "TD: "
|
||||
msgstr "TD : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Availability"
|
||||
msgstr "Disponibilité"
|
||||
msgid "TP: "
|
||||
msgstr "TP : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Manager"
|
||||
msgstr "Responsable"
|
||||
msgid "TE: "
|
||||
msgstr "TE : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "THE: "
|
||||
msgstr "THE : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Global grade"
|
||||
msgstr "Note globale"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Utility"
|
||||
msgstr "Utilité"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Interest"
|
||||
msgstr "Intérêt"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Teaching"
|
||||
msgstr "Enseignement"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Work load"
|
||||
msgstr "Charge de travail"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Objectives"
|
||||
@@ -5265,6 +5225,35 @@ msgstr "Compétences acquises"
|
||||
msgid "Key concepts"
|
||||
msgstr "Concepts clefs"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "UE manager: "
|
||||
msgstr "Gestionnaire d'UE : "
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja pedagogy/tests/tests.py
|
||||
msgid ""
|
||||
"You already posted a comment on this UE. If you want to comment again, "
|
||||
"please modify or delete your previous comment."
|
||||
msgstr ""
|
||||
"Vous avez déjà commenté cette UE. Si vous voulez de nouveau commenter, "
|
||||
"veuillez modifier ou supprimer votre commentaire précédent."
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Leave comment"
|
||||
msgstr "Laisser un commentaire"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
#: trombi/templates/trombi/export.jinja
|
||||
msgid "Comments"
|
||||
msgstr "Commentaires"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "This comment has been reported"
|
||||
msgstr "Ce commentaire a été signalé"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_detail.jinja
|
||||
msgid "Report this comment"
|
||||
msgstr "Signaler ce commentaire"
|
||||
|
||||
#: pedagogy/templates/pedagogy/ue_edit.jinja
|
||||
msgid "Edit UE"
|
||||
msgstr "Éditer l'UE"
|
||||
|
||||
@@ -1,22 +1,52 @@
|
||||
@import "core/static/core/devices";
|
||||
@import "core/static/core/colors";
|
||||
|
||||
|
||||
$pedagogy-blue: #1bb9ea;
|
||||
$pedagogy-orange: #ea7900;
|
||||
$pedagogy-hover-blue: #0e97ce;
|
||||
$pedagogy-light-blue: #caf0ff;
|
||||
$pedagogy-white-text: #f0f0f0;
|
||||
|
||||
.pedagogy {
|
||||
.star-not-checked {
|
||||
color: lightgray;
|
||||
&.star-not-checked {
|
||||
color: #f7f7f7;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.star-checked {
|
||||
&.star-checked {
|
||||
color: $pedagogy-orange;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&.grade-without-star {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
&.star-not-checked {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
&.star-checked {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $small-devices) {
|
||||
&.grade-without-star {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.grade-with-star {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#ue-list {
|
||||
font-size: 1.1em;
|
||||
|
||||
@@ -34,10 +64,12 @@ $pedagogy-white-text: #f0f0f0;
|
||||
}
|
||||
|
||||
#search_form {
|
||||
|
||||
.radio-guide fieldset {
|
||||
input[type="checkbox"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
margin-top: 10px;
|
||||
margin-bottom: 0;
|
||||
color: white;
|
||||
@@ -53,79 +85,80 @@ $pedagogy-white-text: #f0f0f0;
|
||||
}
|
||||
}
|
||||
|
||||
&#ue_detail {
|
||||
.ue-infos {
|
||||
display: flex;
|
||||
gap: 2em;
|
||||
flex-direction: row;
|
||||
@media screen and (max-width: 700px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
.infos-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1em;
|
||||
min-width: 300px;
|
||||
}
|
||||
.info-container {
|
||||
// Darken the background color just enough to make this part
|
||||
// stand out a little, while not being too perceptible
|
||||
background: darken($white-color, 1%);
|
||||
#ue_detail {
|
||||
color: #062f38;
|
||||
|
||||
.ue-quick-info-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
border-radius: 5px;
|
||||
padding: .75rem 1rem ;
|
||||
grid-gap: .5rem;
|
||||
@include shadow;
|
||||
grid-template-columns: 20% 20% 20% 20% auto;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"hours-cm hours-td hours-tp hours-te hours-the"
|
||||
"department credit-type semester . .";
|
||||
}
|
||||
|
||||
.info-container-item {
|
||||
display: grid;
|
||||
grid-column: span 2;
|
||||
grid-template-rows: subgrid;
|
||||
grid-template-columns: subgrid;
|
||||
grid-column-gap: 1rem;
|
||||
.department {
|
||||
grid-area: department;
|
||||
}
|
||||
|
||||
div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.credit-type {
|
||||
grid-area: credit-type;
|
||||
}
|
||||
|
||||
:first-child {
|
||||
justify-content: right;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
.semester {
|
||||
grid-area: semester;
|
||||
}
|
||||
|
||||
hr {
|
||||
grid-column: span 2;
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
.hours-cm {
|
||||
grid-area: hours-cm;
|
||||
}
|
||||
|
||||
.hours-td {
|
||||
grid-area: hours-td;
|
||||
}
|
||||
|
||||
.hours-tp {
|
||||
grid-area: hours-tp;
|
||||
}
|
||||
|
||||
.hours-te {
|
||||
grid-area: hours-te;
|
||||
}
|
||||
|
||||
.hours-the {
|
||||
grid-area: hours-the;
|
||||
}
|
||||
|
||||
.leave-comment-not-allowed {
|
||||
p {
|
||||
text-align: center;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.leave-comment {
|
||||
.comment-form-content {
|
||||
display: flex;
|
||||
gap: 2em;
|
||||
.leave-comment-grid-container {
|
||||
display: grid;
|
||||
grid-template-columns: 270px auto;
|
||||
grid-template-rows: 100%;
|
||||
grid-template-areas: "stars comment";
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
gap: 1em;
|
||||
flex-direction: column;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"stars"
|
||||
"comment";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.form-stars {
|
||||
flex: 0;
|
||||
min-width: 250px;
|
||||
display: flex;
|
||||
align-content: flex-start;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem 2em;
|
||||
height: unset;
|
||||
grid-area: stars;
|
||||
}
|
||||
|
||||
.form-comment {
|
||||
flex: 2;
|
||||
grid-area: comment;
|
||||
}
|
||||
|
||||
.ui-accordion-header-icon {
|
||||
@@ -133,81 +166,284 @@ $pedagogy-white-text: #f0f0f0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
.input-stars {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
summary {
|
||||
background: $pedagogy-orange;
|
||||
color: $pedagogy-white-text;
|
||||
@media screen and (min-width: $large-devices) {
|
||||
clip-path: polygon(0 0%, 0 100%, 30% 100%, 33% 0);
|
||||
}
|
||||
.ue-details-container {
|
||||
display: grid;
|
||||
grid-template-columns: 150px 130px auto;
|
||||
grid-template-rows: 156px 1fr;
|
||||
grid-template-areas:
|
||||
"grade grade-stars ue-infos"
|
||||
". . ue-infos";
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"grade grade-stars"
|
||||
"ue-infos ue-infos";
|
||||
}
|
||||
}
|
||||
|
||||
.grade {
|
||||
grid-area: grade;
|
||||
color: $pedagogy-white-text;
|
||||
background-color: $pedagogy-blue;
|
||||
padding-right: 10px;
|
||||
|
||||
>p {
|
||||
text-align: right;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.grade-stars {
|
||||
grid-area: grade-stars;
|
||||
color: $pedagogy-white-text;
|
||||
background-color: $pedagogy-blue;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ue-infos {
|
||||
grid-area: ue-infos;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.comment {
|
||||
padding: 15px;
|
||||
margin: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
background: $primary-neutral-light-color;
|
||||
border-radius: 5px;
|
||||
border: 1px darken($secondary-neutral-light-color, 10%) solid;
|
||||
.comment-container {
|
||||
display: grid;
|
||||
grid-template-columns: 300px auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-areas:
|
||||
"grade-block comment"
|
||||
"grade-block info"
|
||||
"comment-end-bar comment-end-bar";
|
||||
margin-bottom: 30px;
|
||||
margin-top: 10px;
|
||||
|
||||
&.reported {
|
||||
border: #fc8181 1px solid;
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto auto auto;
|
||||
grid-template-areas:
|
||||
"grade-block"
|
||||
"comment"
|
||||
"info"
|
||||
"comment-end-bar";
|
||||
}
|
||||
|
||||
.comment-header {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
.grade-block {
|
||||
grid-area: grade-block;
|
||||
width: 300px;
|
||||
|
||||
img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
display: grid;
|
||||
grid-template-columns: 150px 150px;
|
||||
grid-template-rows: 156px auto;
|
||||
grid-template-areas:
|
||||
"grade-type grade-stars"
|
||||
"grade-extension grade-extension";
|
||||
grid-gap: 15px;
|
||||
|
||||
clip-path: polygon(0 0, 0 100%, 100% 100%, 100% 30px, 270px 0);
|
||||
align-items: start;
|
||||
|
||||
background-color: $pedagogy-blue;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: 50% auto;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas: "grade-type grade-stars";
|
||||
width: auto;
|
||||
clip-path: none;
|
||||
align-content: space-evenly;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.comment-metadata {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
.grade-extension {
|
||||
grid-area: grade-extension;
|
||||
background-color: $pedagogy-blue;
|
||||
}
|
||||
|
||||
.comment-options {
|
||||
flex: 2;
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
gap: 15px;
|
||||
.grade-type {
|
||||
grid-area: grade-type;
|
||||
|
||||
>p {
|
||||
color: $pedagogy-white-text;
|
||||
font-weight: bold;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.grade-stars {
|
||||
grid-area: grade-stars;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-stars {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
flex-wrap: wrap;
|
||||
gap: 1em 2em;
|
||||
padding: 1.5em;
|
||||
border-top: 0.0625rem grey dotted;
|
||||
border-bottom: 0.0625rem grey dotted;
|
||||
.comment {
|
||||
grid-area: comment;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto;
|
||||
grid-template-areas:
|
||||
"anchor"
|
||||
"markdown";
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
border-left: solid;
|
||||
border-right: solid;
|
||||
border-color: $pedagogy-blue;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
grid-area: anchor;
|
||||
text-align: right;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.markdown {
|
||||
grid-area: markdown;
|
||||
|
||||
min-height: 139px;
|
||||
margin-top: 0;
|
||||
margin-right: 0;
|
||||
padding: 10px;
|
||||
text-align: justify;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-content {
|
||||
text-align: justify;
|
||||
padding: .5em 20px 1em;
|
||||
.info {
|
||||
grid-area: info;
|
||||
padding-bottom: 10px;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
border-left: solid;
|
||||
border-right: solid;
|
||||
border-color: $pedagogy-blue;
|
||||
}
|
||||
|
||||
.status-reported {
|
||||
color: red;
|
||||
float: left;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.action {
|
||||
float: right;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-end-bar {
|
||||
grid-area: comment-end-bar;
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: 33% auto auto;
|
||||
grid-template-rows: 2.5em;
|
||||
grid-template-areas: "author date report";
|
||||
|
||||
background-color: $pedagogy-blue;
|
||||
margin-top: -1px;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
grid-template-columns: auto;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-areas:
|
||||
"report"
|
||||
"date"
|
||||
"author";
|
||||
margin-top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.author {
|
||||
grid-area: author;
|
||||
|
||||
padding-top: 6px;
|
||||
padding-left: 20px;
|
||||
|
||||
background-color: $pedagogy-orange;
|
||||
clip-path: polygon(0 10px, 0 100%, 350px 200%, 300px 10px);
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
clip-path: none;
|
||||
padding: 0;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $pedagogy-white-text;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $pedagogy-hover-blue;
|
||||
}
|
||||
}
|
||||
|
||||
.date {
|
||||
grid-area: date;
|
||||
color: $pedagogy-white-text;
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.report {
|
||||
grid-area: report;
|
||||
justify-self: right;
|
||||
padding-right: 30px;
|
||||
padding-left: 30px;
|
||||
|
||||
a {
|
||||
color: $pedagogy-white-text;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: $pedagogy-hover-blue;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
text-align: center;
|
||||
justify-self: inherit;
|
||||
padding-bottom: 7px;
|
||||
background-color: $white-color;
|
||||
|
||||
border-left: solid;
|
||||
border-right: solid;
|
||||
border-color: $pedagogy-blue;
|
||||
|
||||
a {
|
||||
color: $black-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
details.accordion summary {
|
||||
|
||||
background: $pedagogy-orange !important;
|
||||
color: $pedagogy-white-text !important;
|
||||
clip-path: polygon(0 0%, 0 100%, 30% 100%, 33% 0);
|
||||
|
||||
@media screen and (max-width: $large-devices) {
|
||||
clip-path: none;
|
||||
}
|
||||
}
|
||||
|
||||
details.accordion>.accordion-content {
|
||||
background-color: $white-color;
|
||||
border-color: $pedagogy-orange;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
@@ -5,45 +5,50 @@
|
||||
<div class="accordion-content">
|
||||
{% endif %}
|
||||
<form
|
||||
class="accordion-content"
|
||||
action="{{ url('pedagogy:ue_detail', ue_id=object.id) }}"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
hx-post="{{ action }}"
|
||||
hx-target="closest .leave-comment"
|
||||
hx-swap="outerHTML"
|
||||
hx-disabled-elt="find input[type='submit']"
|
||||
>
|
||||
{% csrf_token %}
|
||||
{{ form.non_field_errors() }}
|
||||
{{ form.author.errors }}
|
||||
{{ form.ue.errors }}
|
||||
|
||||
{{ form.author }}
|
||||
{{ form.ue }}
|
||||
<div class="comment-form-content">
|
||||
<div class="leave-comment-grid-container">
|
||||
<div class="form-stars">
|
||||
<fieldset>
|
||||
<legend>{{ form.grade_global.label }} :</legend>
|
||||
{{ form.non_field_errors() }}
|
||||
{{ form.author.errors }}
|
||||
{{ form.ue.errors }}
|
||||
|
||||
{{ form.author }}
|
||||
{{ form.ue }}
|
||||
|
||||
<div class="input-stars">
|
||||
<label for="{{ form.grade_global.id_for_label }}">{{ form.grade_global.label }} :</label>
|
||||
{{ form.grade_global.errors }}
|
||||
{{ form.grade_global }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ form.grade_utility.label }} :</legend>
|
||||
</div>
|
||||
|
||||
<div class="input-stars">
|
||||
<label for="{{ form.grade_utility.id_for_label }}">{{ form.grade_utility.label }} :</label>
|
||||
{{ form.grade_utility.errors }}
|
||||
{{ form.grade_utility }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ form.grade_interest.label }} :</legend>
|
||||
</div>
|
||||
|
||||
<div class="input-stars">
|
||||
<label for="{{ form.grade_interest.id_for_label }}">{{ form.grade_interest.label }} :</label>
|
||||
{{ form.grade_interest.errors }}
|
||||
{{ form.grade_interest }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ form.grade_teaching.label }} :</legend>
|
||||
</div>
|
||||
|
||||
<div class="input-stars">
|
||||
<label for="{{ form.grade_teaching.id_for_label }}">{{ form.grade_teaching.label }} :</label>
|
||||
{{ form.grade_teaching.errors }}
|
||||
{{ form.grade_teaching }}
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>{{ form.grade_work_load.label }} :</legend>
|
||||
</div>
|
||||
|
||||
<div class="input-stars">
|
||||
<label for="{{ form.grade_work_load.id_for_label }}">{{ form.grade_work_load.label }} :</label>
|
||||
{{ form.grade_work_load.errors }}
|
||||
{{ form.grade_work_load }}
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-comment">
|
||||
<label for="{{ form.comment.id_for_label }}">{{ form.comment.label }} :</label>
|
||||
@@ -51,7 +56,9 @@
|
||||
{{ form.comment }}
|
||||
</div>
|
||||
</div>
|
||||
<p><input type="submit" class="btn btn-blue"/></p>
|
||||
<div class="buttons">
|
||||
<input type="submit" value="{% trans %}Comment{% endtrans %}" />
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{% if form.is_creation %}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
{% from "pedagogy/macros.jinja" import display_star %}
|
||||
{% from "core/macros.jinja" import user_profile_link %}
|
||||
|
||||
{% if comments %}
|
||||
<h2>{% trans %}Comments{% endtrans %}</h2>
|
||||
<br>
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
{%- for comment in comments -%}
|
||||
<article
|
||||
id="comment-{{ comment.id }}"
|
||||
class="comment {% if comment.is_reported %}reported{% endif %}"
|
||||
>
|
||||
{% if comment.is_reported %}
|
||||
<div class="alert alert-red">
|
||||
<div class="alert-main">
|
||||
<h5 class="alert-title margin-bottom">
|
||||
{% trans %}This comment has been reported{% endtrans %}
|
||||
</h5>
|
||||
<p>{% trans %}It will be hidden until moderated.{% endtrans %}</p>
|
||||
{% if user.has_perm("pedagogy.view_uecommentreport") %}
|
||||
{% for report in comment.reports.all() %}
|
||||
<div class="markdown margin-bottom">
|
||||
<blockquote>
|
||||
<em>{{ report.reporter.get_display_name() }}</em>
|
||||
{{ report.reason|markdown }}
|
||||
</blockquote>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if user.has_perm("pedagogy.delete_uecomment") %}
|
||||
<div class="alert-aside">
|
||||
<a
|
||||
href="{{ url("pedagogy:comment_delete", comment_id=comment.id) }}"
|
||||
class="btn btn-red"
|
||||
>
|
||||
<i class="fa fa-trash"></i>{% trans %}Delete{% endtrans %}
|
||||
</a>
|
||||
<a href="{{ url("pedagogy:moderation") }}" class="btn btn-green">
|
||||
<i class="fa fa-check"></i>{% trans %}Moderate{% endtrans %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="comment-header">
|
||||
<img
|
||||
{% if comment.author.avatar_pict %}
|
||||
src="{{ comment.author.avatar_pict.get_download_url() }}"
|
||||
{% elif comment.author.profile_pict %}
|
||||
src="{{ comment.author.profile_pict.get_download_url() }}"
|
||||
{% else %}
|
||||
src="{{ static("core/img/unknown.jpg") }}"
|
||||
{% endif %}
|
||||
alt="{% trans %}Profile{% endtrans %}"
|
||||
/>
|
||||
<div class="comment-metadata">
|
||||
<a href="{{ comment.author.get_absolute_url() }}">
|
||||
<strong>{{ comment.author.get_display_name() }}</strong>
|
||||
</a>
|
||||
<time datetime="{{ comment.publish_date.isoformat(timespec="seconds") }}">
|
||||
{{ comment.publish_date|localtime|date(DATETIME_FORMAT) }}
|
||||
{{ comment.publish_date|localtime|time(DATETIME_FORMAT) }}
|
||||
</time>
|
||||
</div>
|
||||
<div class="comment-options">
|
||||
{% if user.can_edit(comment) %}
|
||||
<a
|
||||
class="clickable"
|
||||
hx-get="{{ url('pedagogy:comment_update', comment_id=comment.id) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#comment-{{ comment.id }}"
|
||||
tooltip="{% trans %}Edit{% endtrans %}"
|
||||
>
|
||||
<i class="fa fa-pencil edit-action"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if not comment.is_reported %}
|
||||
<a
|
||||
class="clickable"
|
||||
hx-get="{{ url('pedagogy:comment_report', comment_id=comment.id) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#comment-{{ comment.id }}"
|
||||
tooltip="{% trans %}Report{% endtrans %}"
|
||||
>
|
||||
<i class="fa fa-exclamation delete-action"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if user.has_perm("pedagogy.delete_uecomment") %}
|
||||
<a
|
||||
href="{{ url("pedagogy:comment_delete", comment_id=comment.id) }}"
|
||||
tooltip="{% trans %}Delete{% endtrans %}"
|
||||
>
|
||||
<i class="fa fa-trash-can delete-action"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="comment-stars">
|
||||
<div>
|
||||
<span>{% trans %}Global grade{% endtrans %}</span>
|
||||
<span>{{ display_star(comment.grade_global) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{% trans %}Utility{% endtrans %}</span>
|
||||
<span>{{ display_star(comment.grade_utility) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{% trans %}Interest{% endtrans %}</span>
|
||||
<span>{{ display_star(comment.grade_interest) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{% trans %}Teaching{% endtrans %}</span>
|
||||
<span>{{ display_star(comment.grade_teaching) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>{% trans %}Workload{% endtrans %}</span>
|
||||
<span>{{ display_star(comment.grade_work_load) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="comment-content">
|
||||
{{ comment.comment|markdown }}
|
||||
</div>
|
||||
</article>
|
||||
{%- endfor -%}
|
||||
</section>
|
||||
@@ -1,20 +0,0 @@
|
||||
<div class="info-container-item">
|
||||
<span>{% trans %}Global grade{% endtrans %}</span>
|
||||
<span>{{ display_star(object.grade_global_average) }}</span>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<span>{% trans %}Utility{% endtrans %}</span>
|
||||
<span>{{ display_star(object.grade_utility_average) }}</span>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<span>{% trans %}Interest{% endtrans %}</span>
|
||||
<span>{{ display_star(object.grade_interest_average) }}</span>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<span>{% trans %}Teaching{% endtrans %}</span>
|
||||
<span>{{ display_star(object.grade_teaching_average) }}</span>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<span>{% trans %}Workload{% endtrans %}</span>
|
||||
<span>{{ display_star(object.grade_work_load_average) }}</span>
|
||||
</div>
|
||||
@@ -1,25 +0,0 @@
|
||||
{# A few hx-partials for swapping a few parts of the main ue_detail.jinja #}
|
||||
|
||||
{% from "pedagogy/macros.jinja" import display_star %}
|
||||
|
||||
<hx-partial id="ue-grade">
|
||||
{% include "pedagogy/fragments/ue_detail/grade.jinja" %}
|
||||
</hx-partial>
|
||||
|
||||
<hx-partial id="comment-form">
|
||||
{% if object.has_user_already_commented(user) %}
|
||||
<em>
|
||||
{% trans trimmed %}
|
||||
You already posted a comment on this UE.
|
||||
If you want to comment again, please modify or delete your previous comment.
|
||||
{% endtrans %}
|
||||
</em>
|
||||
<br>
|
||||
{% elif user.has_perm("pedagogy.add_uecomment") %}
|
||||
{{ add_comment_form }}
|
||||
{% endif %}
|
||||
</hx-partial>
|
||||
|
||||
<hx-partial id="comments" hx-swap="innerMorph">
|
||||
{% include "pedagogy/fragments/ue_detail/comments.jinja" %}
|
||||
</hx-partial>
|
||||
@@ -0,0 +1,91 @@
|
||||
{% from "pedagogy/macros.jinja" import display_star %}
|
||||
{% from "core/macros.jinja" import user_profile_link %}
|
||||
|
||||
{% if comments %}
|
||||
<h2>{% trans %}Comments{% endtrans %}</h2>
|
||||
<br>
|
||||
{% endif %}
|
||||
|
||||
<section>
|
||||
{% for comment in comments %}
|
||||
|
||||
<div id="comment-{{ comment.id }}" class="comment-container">
|
||||
|
||||
<div class="grade-block">
|
||||
<div class="grade-type">
|
||||
<p>{% trans %}Global grade{% endtrans %}</p>
|
||||
<p>{% trans %}Utility{% endtrans %}</p>
|
||||
<p>{% trans %}Interest{% endtrans %}</p>
|
||||
<p>{% trans %}Teaching{% endtrans %}</p>
|
||||
<p>{% trans %}Work load{% endtrans %}</p>
|
||||
</div>
|
||||
<div class="grade-stars">
|
||||
<p>{{ display_star(comment.grade_global) }}</p>
|
||||
<p>{{ display_star(comment.grade_utility) }}</p>
|
||||
<p>{{ display_star(comment.grade_interest) }}</p>
|
||||
<p>{{ display_star(comment.grade_teaching) }}</p>
|
||||
<p>{{ display_star(comment.grade_work_load) }}</p>
|
||||
</div>
|
||||
<div class="grade-extension"></div>
|
||||
</div>
|
||||
|
||||
<div class="comment">
|
||||
<div class="anchor">
|
||||
<a href="{{ url('pedagogy:ue_detail', ue_id=ue.id) }}#comment-{{ comment.id }}"><i class="fa fa-paragraph"></i></a>
|
||||
</div>
|
||||
{{ comment.comment|markdown }}
|
||||
</div>
|
||||
|
||||
<div class="info">
|
||||
{% if comment.is_reported %}
|
||||
<p class="status-reported">
|
||||
{% trans %}This comment has been reported{% endtrans %}
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if comment.author_id == user.id or user.has_perm("pedagogy.change_comment") %}
|
||||
<button
|
||||
class="btn btn-orange action"
|
||||
hx-get="{{ url('pedagogy:comment_update', comment_id=comment.id) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#comment-{{ comment.id }}"
|
||||
>
|
||||
<i class="fa fa-pencil"></i> {% trans %}Edit{% endtrans %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if comment.author_id == user.id or user.has_perm("pedagogy.delete_comment") %}
|
||||
<form class="action"
|
||||
hx-post="{{ url('pedagogy:comment_delete', comment_id=comment.id) }}"
|
||||
hx-confirm='{% trans obj=object %}Are you sure you want to delete "{{ obj }}"?{% endtrans %}'
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#comment-{{ comment.id }}"
|
||||
>
|
||||
{% csrf_token %}
|
||||
<button class="btn btn-red action">
|
||||
<i class="fa fa-trash-can"></i> {% trans %}Delete{% endtrans %}
|
||||
</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="comment-end-bar">
|
||||
<div class="report">
|
||||
<p>
|
||||
<a
|
||||
hx-get="{{ url('pedagogy:comment_report', comment_id=comment.id) }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-target="#comment-{{ comment.id }}"
|
||||
>
|
||||
{% trans %}Report this comment{% endtrans %}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="date"><p>{{ comment.publish_date.strftime('%d/%m/%Y') }}</p></div>
|
||||
|
||||
<div class="author"><p>{{ user_profile_link(comment.author) }}</p></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endfor %}
|
||||
</section>
|
||||
@@ -0,0 +1,10 @@
|
||||
{% if object.has_user_already_commented(user) %}
|
||||
<div class="leave-comment-not-allowed">
|
||||
<p>{% trans %}You already posted a comment on this UE. If you want to comment again, please modify or delete your previous comment.{% endtrans %}</p>
|
||||
</div>
|
||||
<br>
|
||||
{% endif %}
|
||||
|
||||
{% if not object.has_user_already_commented(user) and user.has_perm("pedagogy.add_uecomment") %}
|
||||
{{ add_comment_form }}
|
||||
{% endif %}
|
||||
@@ -0,0 +1,27 @@
|
||||
<div class="ue-details-container">
|
||||
<div class="grade">
|
||||
<p>{% trans %}Global grade{% endtrans %}</p>
|
||||
<p>{% trans %}Utility{% endtrans %}</p>
|
||||
<p>{% trans %}Interest{% endtrans %}</p>
|
||||
<p>{% trans %}Teaching{% endtrans %}</p>
|
||||
<p>{% trans %}Work load{% endtrans %}</p>
|
||||
</div>
|
||||
<div class="grade-stars">
|
||||
<p>{{ display_star(object.grade_global_average) }}</p>
|
||||
<p>{{ display_star(object.grade_utility_average) }}</p>
|
||||
<p>{{ display_star(object.grade_interest_average) }}</p>
|
||||
<p>{{ display_star(object.grade_teaching_average) }}</p>
|
||||
<p>{{ display_star(object.grade_work_load_average) }}</p>
|
||||
</div>
|
||||
<div class="ue-infos">
|
||||
<p><b>{% trans %}Objectives{% endtrans %}</b></p>
|
||||
<p>{{ object.objectives|markdown }}</p>
|
||||
<p><b>{% trans %}Program{% endtrans %}</b></p>
|
||||
<p>{{ object.program|markdown }}</p>
|
||||
<p><b>{% trans %}Earned skills{% endtrans %}</b></p>
|
||||
<p>{{ object.skills|markdown }}</p>
|
||||
<p><b>{% trans %}Key concepts{% endtrans %}</b></p>
|
||||
<p>{{ object.key_concepts|markdown }}</p>
|
||||
<p><b>{% trans %}UE manager: {% endtrans %}</b>{{ object.manager }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,4 +1,5 @@
|
||||
{% macro display_star(grade) -%}
|
||||
|
||||
{% if grade >= 0 %}
|
||||
{% for i in range(5) %}
|
||||
{% if i <= grade %}
|
||||
@@ -7,7 +8,9 @@
|
||||
<span class="fa-solid fa-star pedagogy star-not-checked grade-with-star"></span>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<span class="pedagogy grade-without-star">{{ grade }}/5</span>
|
||||
{% else %}
|
||||
<span class="grade-text"> {% trans %} not rated {% endtrans %} </span>
|
||||
{% endif %}
|
||||
|
||||
{%- endmacro %}
|
||||
|
||||
@@ -1,96 +1,91 @@
|
||||
{% extends "core/base.jinja" %}
|
||||
{% from "pedagogy/macros.jinja" import display_star %}
|
||||
|
||||
{% if is_fragment %}
|
||||
|
||||
{% block additional_css %}
|
||||
<link rel="stylesheet" href="{{ static('pedagogy/css/pedagogy.scss') }}">
|
||||
{% endblock %}
|
||||
<hx-partial id="ue-grade">
|
||||
{% include "pedagogy/fragments/ue_details/grade.jinja" %}
|
||||
</hx-partial>
|
||||
|
||||
{% block title %}
|
||||
{% trans %}UE Details{% endtrans %}
|
||||
{% endblock %}
|
||||
<hx-partial id="comment-form">
|
||||
{% include "pedagogy/fragments/ue_details/form.jinja" %}
|
||||
</hx-partial>
|
||||
|
||||
{% block content %}
|
||||
<h1>{{ object.code }}</h1>
|
||||
<h2 class="margin-bottom">{{ object.title }}</h2>
|
||||
<div class="pedagogy" id="ue_detail">
|
||||
<div class="ue-infos">
|
||||
<div class="infos-column">
|
||||
<aside class="info-container">
|
||||
<div class="info-container-item">
|
||||
<div>{% trans %}Category{% endtrans %}</div>
|
||||
<div>{{ object.credit_type }}</div>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<div>{% trans %}Credits{% endtrans %}</div>
|
||||
<div>{{ object.credits }}</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="info-container-item">
|
||||
<div>Cours magistraux</div>
|
||||
<div>{{ object.hours_CM }}h</div>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<div>Travaux dirigés</div>
|
||||
<div>{{ object.hours_TD }}h</div>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<div>Travaux pratiques</div>
|
||||
<div>{{ object.hours_TP }}h</div>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<div>Travail hors encadrement</div>
|
||||
<div>{{ object.hours_THE }}h</div>
|
||||
</div>
|
||||
<div class="info-container-item">
|
||||
<div>Cours magistraux</div>
|
||||
<div>{{ object.hours_TE }}h</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="info-container-item">
|
||||
<div>{% trans %}Availability{% endtrans %}</div>
|
||||
<div>{{ object.get_semester_display() }}</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="info-container-item">
|
||||
<div>{% trans %}Manager{% endtrans %}</div>
|
||||
<div>{{ object.manager }}</div>
|
||||
</div>
|
||||
</aside>
|
||||
<aside class="info-container" id="ue-grade">
|
||||
{% include "pedagogy/fragments/ue_detail/grade.jinja" %}
|
||||
</aside>
|
||||
</div>
|
||||
<section class="ue-main-infos">
|
||||
<h3>{% trans %}Objectives{% endtrans %}</h3>
|
||||
<p>{{ object.objectives|markdown }}</p>
|
||||
<h3>{% trans %}Program{% endtrans %}</h3>
|
||||
<p>{{ object.program|markdown }}</p>
|
||||
<h3>{% trans %}Earned skills{% endtrans %}</h3>
|
||||
<p>{{ object.skills|markdown }}</p>
|
||||
<h3>{% trans %}Key concepts{% endtrans %}</h3>
|
||||
<p>{{ object.key_concepts|markdown }}</p>
|
||||
</section>
|
||||
</div>
|
||||
<hx-partial id="comments" hx-swap="innerMorph">
|
||||
{% include "pedagogy/fragments/ue_details/comments.jinja" %}
|
||||
</hx-partial>
|
||||
|
||||
<br>
|
||||
{% else %}
|
||||
{% extends "core/base.jinja" %}
|
||||
|
||||
<div id="comment-form">
|
||||
{% if object.has_user_already_commented(user) %}
|
||||
<em>
|
||||
{% trans trimmed %}
|
||||
You already posted a comment on this UE.
|
||||
If you want to comment again, please modify or delete your previous comment.
|
||||
{% endtrans %}
|
||||
</em>
|
||||
{% block additional_css %}
|
||||
<link rel="stylesheet" href="{{ static('pedagogy/css/pedagogy.scss') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
{% trans %}UE Details{% endtrans %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="pedagogy">
|
||||
<div id="ue_detail">
|
||||
<button onclick='(function(){
|
||||
// If comes from the guide page, go back with history
|
||||
if (document.referrer.replace(/\?(.+)/gm,"").endsWith(`{{ url("pedagogy:guide") }}`)){
|
||||
window.history.back();
|
||||
return;
|
||||
}
|
||||
// Simply goes to the guide page
|
||||
window.location.href = `{{ url("pedagogy:guide") }}`;
|
||||
})()' hidden>{% trans %}Back{% endtrans %}</button>
|
||||
|
||||
<h1>{{ object.code }} - {{ object.title }}</h1>
|
||||
<br>
|
||||
{% elif user.has_perm("pedagogy.add_uecomment") %}
|
||||
{{ add_comment_form }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="ue-quick-info-container">
|
||||
<div class="hours-cm">
|
||||
<b>{% trans %}CM: {% endtrans %}</b>{{ object.hours_CM }}
|
||||
</div>
|
||||
<div class="hours-td">
|
||||
<b>{% trans %}TD: {% endtrans %}</b>{{ object.hours_TD }}
|
||||
</div>
|
||||
<div class="hours-tp">
|
||||
<b>{% trans %}TP: {% endtrans %}</b>{{ object.hours_TP }}
|
||||
</div>
|
||||
<div class="hours-te">
|
||||
<b>{% trans %}TE: {% endtrans %}</b>{{ object.hours_TE }}
|
||||
</div>
|
||||
<div class="hours-the">
|
||||
<b>{% trans %}THE: {% endtrans %}</b>{{ object.hours_THE }}
|
||||
</div>
|
||||
|
||||
<div id="comments">
|
||||
{% include "pedagogy/fragments/ue_detail/comments.jinja" %}
|
||||
<div class="department">
|
||||
{{ object.department }}
|
||||
</div>
|
||||
<div class="credit-type">
|
||||
{{ object.credit_type }}
|
||||
</div>
|
||||
<div class="semester">
|
||||
{{ object.get_semester_display() }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div id="ue-grade">
|
||||
{% include "pedagogy/fragments/ue_details/grade.jinja" %}
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<div id="comment-form">
|
||||
{% include "pedagogy/fragments/ue_details/form.jinja" %}
|
||||
</div>
|
||||
|
||||
<div id="comments">
|
||||
{% include "pedagogy/fragments/ue_details/comments.jinja" %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
|
||||
+7
-10
@@ -88,19 +88,16 @@ class UEDetailView(
|
||||
|
||||
model = UE
|
||||
pk_url_kwarg = "ue_id"
|
||||
template_name = "pedagogy/ue_detail.jinja"
|
||||
permission_required = "pedagogy.view_ue"
|
||||
fragments = {"add_comment_form": UECommentCreateView}
|
||||
|
||||
def get_template_names(self) -> list[str]:
|
||||
is_fragment = self.request.headers.get("HX-Request", False)
|
||||
return (
|
||||
["pedagogy/fragments/ue_detail/ue_detail.jinja"]
|
||||
if is_fragment
|
||||
else ["pedagogy/ue_detail.jinja"]
|
||||
)
|
||||
fragments = {
|
||||
"add_comment_form": UECommentCreateView,
|
||||
}
|
||||
|
||||
def get_fragment_data(self):
|
||||
return {"add_comment_form": {"ue_id": self.object.id}}
|
||||
return {
|
||||
"add_comment_form": {"ue_id": self.object.id},
|
||||
}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
return super().get_context_data(**kwargs) | {
|
||||
|
||||
Reference in New Issue
Block a user