Add a modal to create a question

This commit is contained in:
Yohann D'ANELLO 2020-10-31 18:11:37 +01:00
parent 2a282e366e
commit 0d9c293443
6 changed files with 163 additions and 52 deletions

View File

@ -6,7 +6,7 @@ from django.core.exceptions import ValidationError
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from .models import Participation, Phase, Team, Video from .models import Participation, Phase, Question, Team, Video
class TeamForm(forms.ModelForm): class TeamForm(forms.ModelForm):
@ -138,12 +138,24 @@ class SendParticipationForm(forms.ModelForm):
self.instance = participation self.instance = participation
return cleaned_data return cleaned_data
class Meta: class Meta:
model = Participation model = Participation
fields = ('sent_participation',) fields = ('sent_participation',)
class QuestionForm(forms.ModelForm):
"""
Create or update a question.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["question"].widget.attrs.update({"placeholder": _("How did you get the idea to ...?")})
class Meta:
model = Question
fields = ('question',)
class PhaseForm(forms.ModelForm): class PhaseForm(forms.ModelForm):
""" """
Form to update the calendar of a phase. Form to update the calendar of a phase.

View File

@ -114,7 +114,9 @@
</div> </div>
{% if user.registration.participates %} {% if user.registration.participates %}
<button class="btn btn-success"><i class="fas fa-plus-circle"></i> {% trans "Add a question" %}</button> <button class="btn btn-success" data-toggle="modal" data-target="#addQuestionModal">
<i class="fas fa-plus-circle"></i> {% trans "Add a question" %}
</button>
{% endif %} {% endif %}
{% elif current_phase.phase_number == 3 %} {% elif current_phase.phase_number == 3 %}
<div class="alert alert-info"> <div class="alert alert-info">
@ -164,6 +166,13 @@
{% include "base_modal.html" with modal_id="displaySolution" modal_action="" modal_button="" modal_additional_class="modal-lg" modal_content=participation.received_participation.solution.as_iframe|default:unsupported_platform %} {% include "base_modal.html" with modal_id="displaySolution" modal_action="" modal_button="" modal_additional_class="modal-lg" modal_content=participation.received_participation.solution.as_iframe|default:unsupported_platform %}
{% endif %} {% endif %}
{% endif %} {% endif %}
{% if user.registration.participates and current_phase.phase_number == 2 %}
{% trans "Add question" as modal_title %}
{% trans "Add" as modal_button %}
{% url "participation:add_question" pk=participation.pk as modal_action %}
{% include "base_modal.html" with modal_id="addQuestion" modal_button_type="success" %}
{% endif %}
{% endblock %} {% endblock %}
{% block extrajavascript %} {% block extrajavascript %}
@ -175,12 +184,22 @@
if (!modalBody.html().trim()) if (!modalBody.html().trim())
modalBody.load("{% url "participation:participation_receive_participation" pk=participation.pk %} #form-content"); modalBody.load("{% url "participation:participation_receive_participation" pk=participation.pk %} #form-content");
}); });
$('button[data-target="#defineSentParticipationModal"]').click(function() { $('button[data-target="#defineSentParticipationModal"]').click(function() {
let modalBody = $("#defineSentParticipationModal div.modal-body"); let modalBody = $("#defineSentParticipationModal div.modal-body");
if (!modalBody.html().trim()) if (!modalBody.html().trim())
modalBody.load("{% url "participation:participation_send_participation" pk=participation.pk %} #form-content"); modalBody.load("{% url "participation:participation_send_participation" pk=participation.pk %} #form-content");
}); });
{% endif %} {% endif %}
{% if user.registration.participates and current_phase.phase_number == 2 %}
$('button[data-target="#addQuestionModal"]').click(function() {
let modalBody = $("#addQuestionModal div.modal-body");
if (!modalBody.html().trim())
modalBody.load("{% url "participation:add_question" pk=participation.pk %} #form-content");
});
{% endif %}
$('button[data-target="#uploadSolutionModal"]').click(function() { $('button[data-target="#uploadSolutionModal"]').click(function() {
let modalBody = $("#uploadSolutionModal div.modal-body"); let modalBody = $("#uploadSolutionModal div.modal-body");
if (!modalBody.html().trim()) if (!modalBody.html().trim())

View File

@ -0,0 +1,14 @@
{% extends "base.html" %}
{% load crispy_forms_filters i18n %}
{% block content %}
<form method="post">
<div id="form-content">
{% csrf_token %}
{{ form|crispy }}
</div>
<button class="btn btn-primary" type="submit">{% trans "Send" %}</button>
</form>
{% endblock content %}

View File

@ -1,10 +1,10 @@
from django.urls import path from django.urls import path
from django.views.generic import TemplateView from django.views.generic import TemplateView
from .views import CalendarView, CreateTeamView, JoinTeamView, MyParticipationDetailView, MyTeamDetailView, \ from .views import CalendarView, CreateQuestionView, CreateTeamView, JoinTeamView, MyParticipationDetailView, \
ParticipationDetailView, PhaseUpdateView, SetParticipationReceiveParticipationView, \ MyTeamDetailView, ParticipationDetailView, PhaseUpdateView, SetParticipationReceiveParticipationView, \
SetParticipationSendParticipationView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamUpdateView, \ SetParticipationSendParticipationView, TeamAuthorizationsView, TeamDetailView, TeamLeaveView, TeamUpdateView, \
UploadVideoView UpdateQuestionView, UploadVideoView
app_name = "participation" app_name = "participation"
@ -24,6 +24,8 @@ urlpatterns = [
name="participation_receive_participation"), name="participation_receive_participation"),
path("detail/<int:pk>/send-participation/", SetParticipationSendParticipationView.as_view(), path("detail/<int:pk>/send-participation/", SetParticipationSendParticipationView.as_view(),
name="participation_send_participation"), name="participation_send_participation"),
path("detail/<int:pk>/add-question/", CreateQuestionView.as_view(), name="add_question"),
path("update-question/<int:pk>/", CreateQuestionView.as_view(), name="update_question"),
path("calendar/", CalendarView.as_view(), name="calendar"), path("calendar/", CalendarView.as_view(), name="calendar"),
path("calendar/<int:pk>/", PhaseUpdateView.as_view(), name="update_phase"), path("calendar/<int:pk>/", PhaseUpdateView.as_view(), name="update_phase"),
path("chat/", TemplateView.as_view(template_name="participation/chat.html"), name="chat") path("chat/", TemplateView.as_view(template_name="participation/chat.html"), name="chat")

View File

@ -20,9 +20,10 @@ from django_tables2 import SingleTableView
from magic import Magic from magic import Magic
from registration.models import AdminRegistration from registration.models import AdminRegistration
from .forms import JoinTeamForm, ParticipationForm, PhaseForm, ReceiveParticipationForm, RequestValidationForm, \ from .forms import JoinTeamForm, ParticipationForm, PhaseForm, QuestionForm, \
SendParticipationForm, TeamForm, UploadVideoForm, ValidateParticipationForm ReceiveParticipationForm, RequestValidationForm, SendParticipationForm, TeamForm, \
from .models import Participation, Phase, Team, Video UploadVideoForm, ValidateParticipationForm
from .models import Participation, Phase, Question, Team, Video
from .tables import CalendarTable from .tables import CalendarTable
@ -382,6 +383,53 @@ class SetParticipationSendParticipationView(AdminMixin, UpdateView):
return reverse_lazy("participation:participation_detail", args=(self.object.pk,)) return reverse_lazy("participation:participation_detail", args=(self.object.pk,))
class CreateQuestionView(LoginRequiredMixin, CreateView):
"""
Ask a question to another team.
"""
participation: Participation
model = Question
form_class = QuestionForm
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return self.handle_no_permission()
self.participation = Participation.objects.get(pk=kwargs["pk"])
if request.user.registration.is_admin or \
request.user.registration.participates and \
request.user.registration.team.pk == self.participation.team_id:
return super().dispatch(request, *args, **kwargs)
raise PermissionDenied
def form_valid(self, form):
form.instance.participation = self.participation
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy("participation:participation_detail", args=(self.participation.pk,))
class UpdateQuestionView(LoginRequiredMixin, UpdateView):
"""
Edit a question.
"""
model = Question
form_class = QuestionForm
def dispatch(self, request, *args, **kwargs):
self.object = self.get_object(**kwargs)
if not request.user.is_authenticated:
return self.handle_no_permission()
if request.user.registration.is_admin or \
request.user.registration.participates and \
request.user.registration.team.pk == self.object.participation.team_id:
return super().dispatch(request, *args, **kwargs)
raise PermissionDenied
def get_success_url(self):
return reverse_lazy("participation:participation_detail", args=(self.object.participation.pk,))
class UploadVideoView(LoginRequiredMixin, UpdateView): class UploadVideoView(LoginRequiredMixin, UpdateView):
""" """
Upload a solution video for a team. Upload a solution video for a team.

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: Corres2math\n" "Project-Id-Version: Corres2math\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-31 14:34+0100\n" "POT-Creation-Date: 2020-10-31 18:04+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n" "Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -123,15 +123,19 @@ msgstr "Vous ne pouvez pas envoyer de vidéo après la date limite."
msgid "Send to team" msgid "Send to team"
msgstr "Envoyer à l'équipe" msgstr "Envoyer à l'équipe"
#: apps/participation/forms.py:163 #: apps/participation/forms.py:152
msgid "How did you get the idea to ...?"
msgstr "Comment avez-vous eu l'idée de ... ?"
#: apps/participation/forms.py:175
msgid "Start date must be before the end date." msgid "Start date must be before the end date."
msgstr "La date de début doit être avant la date de fin." msgstr "La date de début doit être avant la date de fin."
#: apps/participation/forms.py:165 #: apps/participation/forms.py:177
msgid "This phase must start after the previous phases." msgid "This phase must start after the previous phases."
msgstr "Cette phase doit commencer après les phases précédentes." msgstr "Cette phase doit commencer après les phases précédentes."
#: apps/participation/forms.py:167 #: apps/participation/forms.py:179
msgid "This phase must end after the next phases." msgid "This phase must end after the next phases."
msgstr "Cette phase doit finir avant les phases suivantes." msgstr "Cette phase doit finir avant les phases suivantes."
@ -321,7 +325,7 @@ msgid "Proposed solution:"
msgstr "Solution proposée :" msgstr "Solution proposée :"
#: apps/participation/templates/participation/participation_detail.html:27 #: apps/participation/templates/participation/participation_detail.html:27
#: apps/participation/templates/participation/participation_detail.html:152 #: apps/participation/templates/participation/participation_detail.html:154
#: apps/participation/templates/participation/upload_video.html:11 #: apps/participation/templates/participation/upload_video.html:11
#: apps/registration/templates/registration/upload_photo_authorization.html:18 #: apps/registration/templates/registration/upload_photo_authorization.html:18
#: apps/registration/templates/registration/user_detail.html:78 #: apps/registration/templates/registration/user_detail.html:78
@ -395,11 +399,11 @@ msgstr ""
"vidéo, puis à poser 3 à 6 questions à propos de la vidéo. Après cela, vous " "vidéo, puis à poser 3 à 6 questions à propos de la vidéo. Après cela, vous "
"serez invités à échanger avec l'autre équipe à propos de la solution." "serez invités à échanger avec l'autre équipe à propos de la solution."
#: apps/participation/templates/participation/participation_detail.html:117 #: apps/participation/templates/participation/participation_detail.html:118
msgid "Add a question" msgid "Add a question"
msgstr "Ajouter une question" msgstr "Ajouter une question"
#: apps/participation/templates/participation/participation_detail.html:121 #: apps/participation/templates/participation/participation_detail.html:123
#, python-format #, python-format
msgid "" msgid ""
"You sent your questions to the other team about their solution. When they " "You sent your questions to the other team about their solution. When they "
@ -418,12 +422,12 @@ msgstr ""
"client Element dédié : <a href=\"https://element.correspondances-maths.fr" "client Element dédié : <a href=\"https://element.correspondances-maths.fr"
"\">element.correpondances-maths.fr</a>" "\">element.correpondances-maths.fr</a>"
#: apps/participation/templates/participation/participation_detail.html:140 #: apps/participation/templates/participation/participation_detail.html:142
msgid "Define received video" msgid "Define received video"
msgstr "Définir la vidéo reçue" msgstr "Définir la vidéo reçue"
#: apps/participation/templates/participation/participation_detail.html:141 #: apps/participation/templates/participation/participation_detail.html:143
#: apps/participation/templates/participation/participation_detail.html:146 #: apps/participation/templates/participation/participation_detail.html:148
#: apps/participation/templates/participation/phase_form.html:11 #: apps/participation/templates/participation/phase_form.html:11
#: apps/participation/templates/participation/phase_list.html:18 #: apps/participation/templates/participation/phase_list.html:18
#: apps/participation/templates/participation/receive_participation_form.html:11 #: apps/participation/templates/participation/receive_participation_form.html:11
@ -437,24 +441,32 @@ msgstr "Définir la vidéo reçue"
msgid "Update" msgid "Update"
msgstr "Modifier" msgstr "Modifier"
#: apps/participation/templates/participation/participation_detail.html:145 #: apps/participation/templates/participation/participation_detail.html:147
msgid "Define team that receives your video" msgid "Define team that receives your video"
msgstr "Définir l'équipe qui recevra votre vidéo" msgstr "Définir l'équipe qui recevra votre vidéo"
#: apps/participation/templates/participation/participation_detail.html:151 #: apps/participation/templates/participation/participation_detail.html:153
msgid "Upload video" msgid "Upload video"
msgstr "Envoyer la vidéo" msgstr "Envoyer la vidéo"
#: apps/participation/templates/participation/participation_detail.html:155 #: apps/participation/templates/participation/participation_detail.html:157
#: apps/participation/templates/participation/participation_detail.html:162 #: apps/participation/templates/participation/participation_detail.html:164
msgid "Display solution" msgid "Display solution"
msgstr "Afficher la solution" msgstr "Afficher la solution"
#: apps/participation/templates/participation/participation_detail.html:156 #: apps/participation/templates/participation/participation_detail.html:158
#: apps/participation/templates/participation/participation_detail.html:163 #: apps/participation/templates/participation/participation_detail.html:165
msgid "This video platform is not supported yet." msgid "This video platform is not supported yet."
msgstr "La plateforme de cette vidéo n'est pas encore supportée." msgstr "La plateforme de cette vidéo n'est pas encore supportée."
#: apps/participation/templates/participation/participation_detail.html:171
msgid "Add question"
msgstr "Ajouter une question"
#: apps/participation/templates/participation/participation_detail.html:172
msgid "Add"
msgstr "Ajouter"
#: apps/participation/templates/participation/phase_list.html:10 #: apps/participation/templates/participation/phase_list.html:10
#: templates/base.html:68 templates/base.html:70 templates/base.html:217 #: templates/base.html:68 templates/base.html:70 templates/base.html:217
msgid "Calendar" msgid "Calendar"
@ -464,6 +476,10 @@ msgstr "Calendrier"
msgid "Update phase" msgid "Update phase"
msgstr "Modifier la phase" msgstr "Modifier la phase"
#: apps/participation/templates/participation/question_form.html:11
msgid "Send"
msgstr "Envoyer"
#: apps/participation/templates/participation/team_detail.html:14 #: apps/participation/templates/participation/team_detail.html:14
msgid "Name:" msgid "Name:"
msgstr "Nom :" msgstr "Nom :"
@ -567,74 +583,74 @@ msgstr "Quitter l'équipe"
msgid "Are you sure that you want to leave this team?" msgid "Are you sure that you want to leave this team?"
msgstr "Êtes-vous sûr·e de vouloir quitter cette équipe ?" msgstr "Êtes-vous sûr·e de vouloir quitter cette équipe ?"
#: apps/participation/views.py:36 templates/base.html:77 #: apps/participation/views.py:37 templates/base.html:77
#: templates/base.html:230 #: templates/base.html:230
msgid "Create team" msgid "Create team"
msgstr "Créer une équipe" msgstr "Créer une équipe"
#: apps/participation/views.py:43 apps/participation/views.py:89 #: apps/participation/views.py:44 apps/participation/views.py:90
msgid "You don't participate, so you can't create a team." msgid "You don't participate, so you can't create a team."
msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe." msgstr "Vous ne participez pas, vous ne pouvez pas créer d'équipe."
#: apps/participation/views.py:45 apps/participation/views.py:91 #: apps/participation/views.py:46 apps/participation/views.py:92
msgid "You are already in a team." msgid "You are already in a team."
msgstr "Vous êtes déjà dans une équipe." msgstr "Vous êtes déjà dans une équipe."
#: apps/participation/views.py:82 templates/base.html:82 #: apps/participation/views.py:83 templates/base.html:82
#: templates/base.html:226 #: templates/base.html:226
msgid "Join team" msgid "Join team"
msgstr "Rejoindre une équipe" msgstr "Rejoindre une équipe"
#: apps/participation/views.py:133 apps/participation/views.py:300 #: apps/participation/views.py:134 apps/participation/views.py:301
#: apps/participation/views.py:333 #: apps/participation/views.py:334
msgid "You are not in a team." msgid "You are not in a team."
msgstr "Vous n'êtes pas dans une équipe." msgstr "Vous n'êtes pas dans une équipe."
#: apps/participation/views.py:134 apps/participation/views.py:334 #: apps/participation/views.py:135 apps/participation/views.py:335
msgid "You don't participate, so you don't have any team." msgid "You don't participate, so you don't have any team."
msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe." msgstr "Vous ne participez pas, vous n'avez donc pas d'équipe."
#: apps/participation/views.py:179 #: apps/participation/views.py:180
msgid "You don't participate, so you can't request the validation of the team." msgid "You don't participate, so you can't request the validation of the team."
msgstr "" msgstr ""
"Vous ne participez pas, vous ne pouvez pas demander la validation de " "Vous ne participez pas, vous ne pouvez pas demander la validation de "
"l'équipe." "l'équipe."
#: apps/participation/views.py:182 #: apps/participation/views.py:183
msgid "The validation of the team is already done or pending." msgid "The validation of the team is already done or pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: apps/participation/views.py:195 #: apps/participation/views.py:196
msgid "You are not an administrator." msgid "You are not an administrator."
msgstr "Vous n'êtes pas administrateur." msgstr "Vous n'êtes pas administrateur."
#: apps/participation/views.py:198 #: apps/participation/views.py:199
msgid "This team has no pending validation." msgid "This team has no pending validation."
msgstr "L'équipe n'a pas de validation en attente." msgstr "L'équipe n'a pas de validation en attente."
#: apps/participation/views.py:217 #: apps/participation/views.py:218
msgid "You must specify if you validate the registration or not." msgid "You must specify if you validate the registration or not."
msgstr "Vous devez spécifier si vous validez l'inscription ou non." msgstr "Vous devez spécifier si vous validez l'inscription ou non."
#: apps/participation/views.py:280 apps/registration/views.py:235 #: apps/participation/views.py:281 apps/registration/views.py:235
#, python-brace-format #, python-brace-format
msgid "Photo authorization of {student}.{ext}" msgid "Photo authorization of {student}.{ext}"
msgstr "Autorisation de droit à l'image de {student}.{ext}" msgstr "Autorisation de droit à l'image de {student}.{ext}"
#: apps/participation/views.py:284 #: apps/participation/views.py:285
#, python-brace-format #, python-brace-format
msgid "Photo authorizations of team {trigram}.zip" msgid "Photo authorizations of team {trigram}.zip"
msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip" msgstr "Autorisations de droit à l'image de l'équipe {trigram}.zip"
#: apps/participation/views.py:302 #: apps/participation/views.py:303
msgid "The team is already validated or the validation is pending." msgid "The team is already validated or the validation is pending."
msgstr "La validation de l'équipe est déjà faite ou en cours." msgstr "La validation de l'équipe est déjà faite ou en cours."
#: apps/participation/views.py:346 #: apps/participation/views.py:347
msgid "The team is not validated yet." msgid "The team is not validated yet."
msgstr "L'équipe n'est pas encore validée." msgstr "L'équipe n'est pas encore validée."
#: apps/participation/views.py:355 #: apps/participation/views.py:356
#, python-brace-format #, python-brace-format
msgid "Participation of team {trigram}" msgid "Participation of team {trigram}"
msgstr "Participation de l'équipe {trigram}" msgstr "Participation de l'équipe {trigram}"