From 32c5632aa53fe4a10f93505fa49ea784887d100e Mon Sep 17 00:00:00 2001 From: jem-odoo <jem@openerp.com> Date: Wed, 13 Mar 2019 15:43:23 +0000 Subject: [PATCH] [FIX] website_slides: auto set done successfull quizz For now, in no fullscreen mode, if the quiz is succeed, the user progress is not updated because the quiz is not set to done. This commit implements this call to mark slide as done and green the check bullet. We decided to unify the submit RPC call with the done one, so a quiz (or a slide with questions) can only be done when submitting answers. As consequence, we need to prevent some slide type to use the /set_completed route (quiz and certif). Task-1941250 --- addons/website_slides/controllers/main.py | 9 +++-- .../src/js/slides_course_fullscreen_player.js | 28 +++++++++++---- .../static/src/js/slides_course_quiz.js | 35 ++++++++----------- .../controllers/slides.py | 11 +++++- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py index 85ea0ba96813..718d01be6402 100644 --- a/addons/website_slides/controllers/main.py +++ b/addons/website_slides/controllers/main.py @@ -61,6 +61,9 @@ class WebsiteSlides(WebsiteProfile): return True def _set_completed_slide(self, slide, quiz_attempts_inc=False): + # quiz use their specific mechanism to be marked as done + if slide.slide_type == 'quiz' or slide.question_ids: + raise werkzeug.exceptions.Forbidden(_("Slide with questions must be marked as done when submitting all good answers ")) if slide.website_published and slide.channel_id.is_member: slide.action_set_completed(quiz_attempts_inc=quiz_attempts_inc) return True @@ -662,6 +665,7 @@ class WebsiteSlides(WebsiteProfile): rank_progress = {} if not user_bad_answers: slide._action_set_quiz_done() + slide.action_set_completed(quiz_attempts_inc=True) lower_bound = request.env.user.rank_id.karma_min upper_bound = request.env.user.next_rank_id.karma_min rank_progress = { @@ -674,11 +678,12 @@ class WebsiteSlides(WebsiteProfile): return { 'goodAnswers': user_good_answers.ids, 'badAnswers': user_bad_answers.ids, - 'completed': not user_bad_answers, + 'completed': slide.user_membership_id.sudo().completed, + 'channel_completion': slide.channel_id.completion, 'quizKarmaWon': quiz_info['quiz_karma_won'], 'quizKarmaGain': quiz_info['quiz_karma_gain'], 'quizAttemptsCount': quiz_info['quiz_attempts_count'], - 'rankProgress': rank_progress + 'rankProgress': rank_progress, } # -------------------------------------------------- diff --git a/addons/website_slides/static/src/js/slides_course_fullscreen_player.js b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js index a83df8a01cd5..30d23f20f2fa 100644 --- a/addons/website_slides/static/src/js/slides_course_fullscreen_player.js +++ b/addons/website_slides/static/src/js/slides_course_fullscreen_player.js @@ -102,7 +102,7 @@ odoo.define('website_slides.fullscreen', function (require) { if (totalTime && currentTime > totalTime - 30){ clearInterval(self.tid); if (!self.slide.hasQuestion && !self.slide.completed){ - self.trigger_up('slide_completed', self.slide); + self.trigger_up('slide_to_complete', self.slide); } } } @@ -289,8 +289,8 @@ odoo.define('website_slides.fullscreen', function (require) { }, custom_events: { 'change_slide': '_onChangeSlideRequest', + 'slide_to_complete': '_onSlideToComplete', 'slide_completed': '_onSlideCompleted', - 'quiz_completed': '_onSlideCompleted', 'slide_go_next': '_onSlideGoToNext', }, /** @@ -367,11 +367,17 @@ odoo.define('website_slides.fullscreen', function (require) { */ _fetchSlideContent: function (){ var slide = this.get('slide'); - if (slide.type === 'webpage') { + if (slide.type === 'webpage' && !slide.isQuiz) { return this._fetchHtmlContent(); } return $.when(); }, + _markAsCompleted: function (slideId, completion) { + var slide = findSlide(this.slides, {id: slideId}); + slide.completed = true; + this.sidebar.setSlideCompleted(slide.id); + this.sidebar.updateProgressbar(completion); + }, /** * Extend the slide data list to add informations about rendering method, and other * specific values according to their slide_type. @@ -459,9 +465,7 @@ odoo.define('website_slides.fullscreen', function (require) { slide_id: slide.id, } }).then(function (data){ - slide.completed = true; - self.sidebar.setSlideCompleted(slide.id); - self.sidebar.updateProgressbar(data.channel_completion); + self._markAsCompleted(slideId, data.channel_completion); }); } return $.when(); @@ -504,13 +508,23 @@ odoo.define('website_slides.fullscreen', function (require) { }); this.set('slide', newSlide); }, + /** + * Triggered when subwidget has mark the slide as done, and the UI need to be adapted. + * + * @private + */ + _onSlideCompleted: function (ev) { + var slide = ev.data.slide; + var completion = ev.data.completion; + this._markAsCompleted(slide.id, completion); + }, /** * Triggered when sub widget business is done and that slide * can now be marked as done. * * @private */ - _onSlideCompleted: function (ev) { + _onSlideToComplete: function (ev) { if (!session.is_website_user) { // no useless RPC call var slideId = ev.data.id; this._setCompleted(slideId); diff --git a/addons/website_slides/static/src/js/slides_course_quiz.js b/addons/website_slides/static/src/js/slides_course_quiz.js index c969e38623bd..9e2b9b7ece50 100644 --- a/addons/website_slides/static/src/js/slides_course_quiz.js +++ b/addons/website_slides/static/src/js/slides_course_quiz.js @@ -177,15 +177,6 @@ odoo.define('website_slides.quiz', function (require) { QWeb.render('slide.slide.quiz.validation', {'widget': this}) ); }, - - /** - * Set the slide as completed and done. Trigger up the completion. - * - * @param {Integer} completion - */ - _setCompleted: function () { - this.trigger_up('quiz_completed', this.slide); - }, /* * Submit the given answer, and display the result * @@ -203,13 +194,12 @@ odoo.define('website_slides.quiz', function (require) { if (data.error) { self._alertShow(data.error); } else { - self.slide.completed = data.completed; self.quiz = _.extend(self.quiz, data); self._renderAnswersHighlighting(); self._renderValidationInfo(); - if (self.slide.completed) { + if (data.completed) { self._renderSuccessModal(data); - self._setCompleted(); + self.trigger_up('slide_completed', {slide: self.slide, completion: data.channel_completion}); } } }); @@ -266,10 +256,10 @@ odoo.define('website_slides.quiz', function (require) { }); sAnimations.registry.websiteSlidesQuizNoFullscreen = sAnimations.Class.extend({ - selector: '.o_wslides_js_lesson_quiz', + selector: '.o_wslides_lesson_main', // selector of complete page, as we need slide content and aside content table custom_events: { slide_go_next: '_onQuizNextSlide', - quiz_completed: '_onQuizCompleted', + slide_completed: '_onQuizCompleted', }, //---------------------------------------------------------------------- @@ -282,8 +272,9 @@ odoo.define('website_slides.quiz', function (require) { */ start: function () { var self = this; + this.quizWidgets = []; var defs = [this._super.apply(this, arguments)]; - $('.o_wslides_js_lesson_quiz').each(function () { + this.$('.o_wslides_js_lesson_quiz').each(function () { var slideData = $(this).data(); slideData.quizData = { questions: self._extractQuestionsAndAnswers(), @@ -300,13 +291,17 @@ odoo.define('website_slides.quiz', function (require) { //---------------------------------------------------------------------- // Handlers //--------------------------------------------------------------------- - - _onQuizCompleted: function (slideId) { - console.log('set completed', slideId); + _onQuizCompleted: function (ev) { + var self = this; + var slide = ev.data.slide; + var completion = ev.data.completion; + this.$('#o_wslides_lesson_aside_slide_check_' + slide.id).addClass('text-success fa-check-circle').removeClass('text-600 fa-circle-o'); + // need to use global selector as progress bar is ouside this animation widget scope + $('.o_wslides_lesson_header .progress-bar').css('width', completion + "%"); + $('.o_wslides_lesson_header .progress span').text(_.str.sprintf("%s %%", completion)); }, - _onQuizNextSlide: function () { - var url = this.$el.data('next-slide-url'); + var url = this.$('.o_wslides_js_lesson_quiz').data('next-slide-url'); window.location.replace(url); }, diff --git a/addons/website_slides_survey/controllers/slides.py b/addons/website_slides_survey/controllers/slides.py index 9396de502b8d..a7dad0b175d1 100644 --- a/addons/website_slides_survey/controllers/slides.py +++ b/addons/website_slides_survey/controllers/slides.py @@ -1,8 +1,10 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.website_slides.controllers.main import WebsiteSlides +import werkzeug +from odoo.addons.website_slides.controllers.main import WebsiteSlides +from odoo import _ from odoo.http import request @@ -49,6 +51,13 @@ class WebsiteSlides(WebsiteSlides): return result + # Utils + # --------------------------------------------------- + def _set_completed_slide(self, slide, quiz_attempts_inc=False): + if slide.slide_type == 'certification': + raise werkzeug.exceptions.Forbidden(_("Certification slides are completed when the survey is succeeded.")) + return super(WebsiteSlides, self)._set_completed_slide(slide, quiz_attempts_inc=quiz_attempts_inc) + # Profile # --------------------------------------------------- def _prepare_user_slides_profile(self, user): -- GitLab