From: Gael Le Mignot Date: Fri, 22 Jul 2022 10:28:00 +0000 (+0200) Subject: Uncommited changes by Yoan X-Git-Tag: 2.8.1-pro~84^2~4^2~1 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=d8c575f2475765653c053ccef30f9e00f1ea6f0d;p=teleforma.git Uncommited changes by Yoan --- diff --git a/teleforma/admin.py b/teleforma/admin.py index e4633bc3..c36d877c 100644 --- a/teleforma/admin.py +++ b/teleforma/admin.py @@ -210,9 +210,13 @@ class ConferenceAdmin(admin.ModelAdmin): class SeminarQuestionInline(admin.StackedInline): model = Question +class SeminarStepInline(admin.StackedInline): + model = SeminarStep + autocomplete_fields = [ 'docs_1', 'medias', 'docs_2', 'docs_correct', 'quiz'] + class SeminarAdmin(admin.ModelAdmin): exclude = ['keywords'] - inlines = [SeminarQuestionInline,] + inlines = [SeminarQuestionInline, SeminarStepInline] filter_horizontal = ['professor',] # filter_vertical = ['docs_description', 'docs_1', # 'docs_2', 'docs_correct', 'medias', @@ -288,6 +292,9 @@ class SeminarAdmin(admin.ModelAdmin): class Media: css = { 'all': ('admin/extra.css',) } + + + class MediaItemMarkerAdmin(admin.ModelAdmin): search_fields = ['title', 'description'] diff --git a/teleforma/migrations/0006_seminarstep.py b/teleforma/migrations/0006_seminarstep.py new file mode 100644 index 00000000..2855b055 --- /dev/null +++ b/teleforma/migrations/0006_seminarstep.py @@ -0,0 +1,27 @@ +# Generated by Django 3.2.3 on 2022-07-13 10:32 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('quiz', '__first__'), + ('teleforma', '0005_auto_20220117_1756'), + ] + + operations = [ + migrations.CreateModel( + name='SeminarStep', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('docs_1', models.ManyToManyField(blank=True, related_name='seminarstep_docs1', to='teleforma.Document', verbose_name='documents 1')), + ('docs_2', models.ManyToManyField(blank=True, related_name='seminarstep_docs2', to='teleforma.Document', verbose_name='documents 2')), + ('docs_correct', models.ManyToManyField(blank=True, related_name='seminarstep_docs_correct', to='teleforma.Document', verbose_name='corrected documents')), + ('medias', models.ManyToManyField(blank=True, related_name='seminarstep', to='teleforma.Media', verbose_name='media')), + ('quiz', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='seminarstep', to='quiz.quiz', verbose_name='quiz')), + ('seminar', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='steps', to='teleforma.seminar', verbose_name='seminar')), + ], + ), + ] diff --git a/teleforma/migrations/0007_alter_seminarstep_quiz.py b/teleforma/migrations/0007_alter_seminarstep_quiz.py new file mode 100644 index 00000000..482e8c91 --- /dev/null +++ b/teleforma/migrations/0007_alter_seminarstep_quiz.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.3 on 2022-07-13 10:49 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('quiz', '__first__'), + ('teleforma', '0006_seminarstep'), + ] + + operations = [ + migrations.AlterField( + model_name='seminarstep', + name='quiz', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.PROTECT, related_name='seminarstep', to='quiz.quiz', verbose_name='quiz'), + preserve_default=False, + ), + ] diff --git a/teleforma/models/pro.py b/teleforma/models/pro.py index 5bbabbe2..fab61248 100644 --- a/teleforma/models/pro.py +++ b/teleforma/models/pro.py @@ -61,6 +61,9 @@ class SeminarType(models.Model): verbose_name = _('Seminar type') + + + class Seminar(ClonableMixin, Displayable, ProductCodeMixin, SuggestionsMixin): # title, description, keywords, dates and status are given by Displayable @@ -181,6 +184,33 @@ class Seminar(ClonableMixin, Displayable, ProductCodeMixin, SuggestionsMixin): def suggestions(self): return (list(self.suggested_seminars.all())+list(self.suggested_conferences.all()))[:3] + @property + def is_multistep(self): + return self.steps.count() + + @property + def number_of_steps(self): + """ number of top steps """ + return self.steps.count() or 1 + + def get_steps(self, user): + """ get steps info """ + steps = [] + last_accessible = None + for i, step in enumerate(self.steps.order_by('id')): + validated = step.is_validated(user) + accessible = validated + if not validated and not last_accessible: + accessible = True + last_accessible = True + steps.append({ + 'index': i + 1, + 'object': step, + 'validated': validated, + 'accessible': accessible + }) + return steps + def use_webclass(self, user): """ Should we show the webclass or the media ? @@ -243,6 +273,30 @@ class Seminar(ClonableMixin, Displayable, ProductCodeMixin, SuggestionsMixin): verbose_name = _('Seminar') ordering = ['rank'] +class SeminarStep(models.Model): + seminar = models.ForeignKey(Seminar, related_name='steps', verbose_name=_('seminar'), on_delete=models.CASCADE) + docs_1 = models.ManyToManyField(Document, related_name="seminarstep_docs1", + verbose_name=_('documents 1'), + blank=True) + medias = models.ManyToManyField(Media, related_name="seminarstep", + verbose_name=_('media'), + blank=True) + docs_2 = models.ManyToManyField(Document, related_name="seminarstep_docs2", + verbose_name=_('documents 2'), + blank=True) + docs_correct = models.ManyToManyField(Document, related_name="seminarstep_docs_correct", + verbose_name=_('corrected documents'), + blank=True) + quiz = models.ForeignKey(Quiz, related_name="seminarstep", + verbose_name=_('quiz'), + on_delete=models.PROTECT) + + + def is_validated(self, user): + validations = QuizValidation.objects.filter(quiz=self.quiz, user=user, validated=True, date_validated__range=[self.seminar.date_added, self.seminar.expiry_date]) + if validations: + return True + return False class Question(ClonableMixin, models.Model): diff --git a/teleforma/templates/teleforma/inc/quiz_list.html b/teleforma/templates/teleforma/inc/quiz_list.html index 552be974..592d6fa1 100644 --- a/teleforma/templates/teleforma/inc/quiz_list.html +++ b/teleforma/templates/teleforma/inc/quiz_list.html @@ -5,17 +5,17 @@ - {% if seminar.quiz %} - {{ seminar.quiz.title }} + {% if quiz %} + {{ quiz.title }} {% endif %} - {% if seminar|quiz_validated:user %} - {% trans "validé le" %} {{ seminar|quiz_validated:user }} + {% if quiz|one_more:user|quiz_validated:seminar %} + {% trans "validé le" %} {{ quiz|one_more:user|quiz_validated:seminar }} {% endif %} - {% if seminar|quiz_validated:user %} + {% if quiz|one_more:user|quiz_validated:seminar %} {% else %} diff --git a/teleforma/templates/teleforma/seminar_detail.html b/teleforma/templates/teleforma/seminar_detail.html index e05a5caa..96aaf513 100644 --- a/teleforma/templates/teleforma/seminar_detail.html +++ b/teleforma/templates/teleforma/seminar_detail.html @@ -158,85 +158,132 @@ {% endif %} - {% with seminar.docs_1 as docs %} -
-
-

{% trans "Step" %} 1 : - {% if docs.all.count > 1 %}{% trans "read these documents" %}{% else %}{% trans "read this document" %}{% endif %} -

-
- {% include "teleforma/inc/document_simple_list.html" %} -
- {% endwith %} - - {% if show_webclass %} - {% with seminar.conference as webclass %} -
-
-

{% trans "Step" %} 2 : - {% trans "view this conference" %}

+ {% if seminar.is_multistep %} + {% for step in steps %} + {{ step.index }} + {% endfor %} + + + {% for step in steps %} +

Step {{ step.index }} - {{ step.validated }} {{ step.accessible }}

+ + {% with step.object.docs_1 as docs %} +
+
+

{% trans "Step" %} 1 : + {% if docs.all.count > 1 %}{% trans "read these documents" %}{% else %}{% trans "read this document" %}{% endif %} +

+
+ {% include "teleforma/inc/document_simple_list.html" %}
- {% include "teleforma/inc/webclass.html" %} -
- {% endwith %} + {% endwith %} + + {% with step.object.medias as medias %} +
+
+

{% trans "Step" %} 2 : + {% if medias.all.count > 1 %}{% trans "view these conferences" %}{% else %}{% trans "view this conference" %}{% endif %} +

+
+ {% include "teleforma/inc/media_package_list.html" %} +
+ {% endwith %} + + {% with step.object.quiz as quiz %} +
+
+

{% trans "Step" %} 2bis : + {% trans "Quiz" %}

+
+ {% include "teleforma/inc/quiz_list.html" %} +
+ {% endwith %} + + {% endfor %} + {% else %} - {% with seminar.medias as medias %} + {% with seminar.docs_1 as docs %}
-

{% trans "Step" %} 2 : - {% if medias.all.count > 1 %}{% trans "view these conferences" %}{% else %}{% trans "view this conference" %}{% endif %} +

{% trans "Step" %} 1 : + {% if docs.all.count > 1 %}{% trans "read these documents" %}{% else %}{% trans "read this document" %}{% endif %}

- {% include "teleforma/inc/media_package_list.html" %} + {% include "teleforma/inc/document_simple_list.html" %}
{% endwith %} - {% endif %} + {% if show_webclass %} + {% with seminar.conference as webclass %} +
+
+

{% trans "Step" %} 2 : + {% trans "view this conference" %}

+
+ {% include "teleforma/inc/webclass.html" %} +
+ {% endwith %} + {% else %} + {% with seminar.medias as medias %} +
+
+

{% trans "Step" %} 2 : + {% if medias.all.count > 1 %}{% trans "view these conferences" %}{% else %}{% trans "view this conference" %}{% endif %} +

+
+ {% include "teleforma/inc/media_package_list.html" %} +
+ {% endwith %} + {% endif %} - {% if seminar.quiz %} -
-
-

{% trans "Step" %} 2bis : - {% trans "Quiz" %}

-
- {% include "teleforma/inc/quiz_list.html" %} -
- {% endif %} - {% with seminar.docs_2 as docs %} -
-
-

{% trans "Step" %} 3 : - {% if docs.all.count > 1 %}{% trans "read these documents" %}{% else %}{% trans "read this document" %}{% endif %} -

+ {% if seminar.quiz %} + {% with seminar.quiz as quiz %} +
+
+

{% trans "Step" %} 2bis : + {% trans "Quiz" %}

+
+ {% include "teleforma/inc/quiz_list.html" %} +
+ {% endwith %} + {% endif %} + + {% with seminar.docs_2 as docs %} +
+
+

{% trans "Step" %} 3 : + {% if docs.all.count > 1 %}{% trans "read these documents" %}{% else %}{% trans "read this document" %}{% endif %} +

+
+ {% include "teleforma/inc/document_simple_list.html" %}
- {% include "teleforma/inc/document_simple_list.html" %} -
- {% endwith %} + {% endwith %} - {% with seminar.question as questions %} -
-
-

{% trans "Step" %} 4 : - {% if questions.all.count > 1 %}{% trans "answer to these questions" %}{% else %}{% trans "answer to this question" %}{% endif %} -

+ {% with seminar.question as questions %} +
+
+

{% trans "Step" %} 4 : + {% if questions.all.count > 1 %}{% trans "answer to these questions" %}{% else %}{% trans "answer to this question" %}{% endif %} +

+
+ {% include "teleforma/inc/question_list.html" %}
- {% include "teleforma/inc/question_list.html" %} -
- {% endwith %} - - {% with seminar.docs_correct as docs %} -
-
-

{% trans "Step" %} 5 : - {% if docs.all.count > 1 %}{% trans "read these corrected documents" %}{% else %}{% trans "read this corrected document" %}{% endif %} -

+ {% endwith %} + + {% with seminar.docs_correct as docs %} +
+
+

{% trans "Step" %} 5 : + {% if docs.all.count > 1 %}{% trans "read these corrected documents" %}{% else %}{% trans "read this corrected document" %}{% endif %} +

+
+ {% include "teleforma/inc/document_simple_list.html" %}
- {% include "teleforma/inc/document_simple_list.html" %} -
- {% endwith %} + {% endwith %} + {% endif %} {% if seminar_progress == 100 %} diff --git a/teleforma/templatetags/teleforma_tags.py b/teleforma/templatetags/teleforma_tags.py index 887a16d0..895746ae 100644 --- a/teleforma/templatetags/teleforma_tags.py +++ b/teleforma/templatetags/teleforma_tags.py @@ -237,11 +237,16 @@ def validated(question, user): return '' @register.filter -def quiz_validated(seminar, user): - quiz = seminar.quiz +def one_more(_1, _2): + # to pass more than one argument to filter + return _1, _2 + +@register.filter +def quiz_validated(quiz_and_user, seminar): + quiz, user = quiz_and_user startdate = seminar.date_added enddate = seminar.expiry_date - validations = QuizValidation.objects.filter(quiz=quiz, user=user, validated=True,date_validated__range=[startdate, enddate]) + validations = QuizValidation.objects.filter(quiz=quiz, user=user, validated=True, date_validated__range=[startdate, enddate]) if validations: return validations[0].date_validated else: diff --git a/teleforma/views/pro.py b/teleforma/views/pro.py index 91d4b7af..8b2515e9 100644 --- a/teleforma/views/pro.py +++ b/teleforma/views/pro.py @@ -71,7 +71,7 @@ from quiz.views import QuizTake from teleforma.context_processors import all_conferences, all_seminars, seminar_progress, seminar_validated from teleforma.models.core import Conference -from teleforma.models.pro import Answer, Question, QuizValidation, Seminar, SeminarRevision, Testimonial +from teleforma.models.pro import Answer, Question, QuizValidation, Seminar, SeminarRevision, SeminarStep, Testimonial from teleforma.forms import AnswerForm from teleforma.views.core import DocumentDownloadView, DocumentReadView, MediaView @@ -231,6 +231,9 @@ class SeminarView(SeminarAccessMixin, DetailView): user = self.request.user context['show_webclass'] = seminar.use_webclass(user) + context['steps'] = seminar.get_steps(user) + + validated = seminar_validated(user, seminar) if validated: # check if testimonial exists and create it @@ -939,31 +942,40 @@ class QuizQuestionView(SeminarAccessMixin, SeminarRevisionMixin, QuizTake): template_name = 'quiz/question.html' + def _init(self): + self.seminar = Seminar.objects.get(pk=self.kwargs['pk']) + try: + self.step = self.quiz.seminarstep.get(seminar__pk=self.kwargs['pk']) + except SeminarStep.DoesNotExist: + self.step = self.seminar + def get_user(self): user_id = self.request.user.id return User.objects.get(id=user_id) def can_access(self): user = self.get_user() - for items in [self.seminar.docs_1, self.seminar.medias]: + for items in [self.step.docs_1, self.step.medias]: for item in items.all(): if item.weight: if user not in item.readers.all(): return False return True + def get_context_data(self, **kwargs): context = super(QuizQuestionView, self).get_context_data(**kwargs) + self._init() user = self.get_user() - self.seminar = Seminar.objects.get(pk=self.kwargs['pk']) + context['can_access'] = self.can_access() context['seminar'] = self.seminar context['seminar_progress'] = seminar_progress(user, self.seminar) return context def final_result_user(self): + self._init() user = self.get_user() - self.seminar = Seminar.objects.get(pk=self.kwargs['pk']) results = { 'quiz': self.quiz, @@ -989,11 +1001,11 @@ class QuizQuestionView(SeminarAccessMixin, SeminarRevisionMixin, QuizTake): if self.sitting.get_percent_correct >= self.quiz.pass_mark: validation = QuizValidation( - user=user, quiz=self.seminar.quiz, validated=True) + user=user, quiz=self.step.quiz, validated=True) validation.save() else: # revert step 1 validation - for doc in self.seminar.docs_1.all(): + for doc in self.step.docs_1.all(): doc.readers.remove(user) doc.save()