Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IMP] Slides: Add elearning feature to slides #29876

Conversation

tde-banana-odoo
Copy link
Contributor

@tde-banana-odoo tde-banana-odoo commented Jan 3, 2019

Purpose of this commit is to introduce a new way of displaying and managing
slides in eLearning module. Its purpose is to give a better experience to
users when going through a course. Notably a fullscreen mode allows to take
lessons one by one without going out of the elearning display. Integration
of all slide types eases taking the course step by step.

Quiz are introduced in this commit. Those are an addition to slides with
some question / answers (multiple choice). It allows customer to gain karma
and improves gamification. Certifications are still done using the survey
application. Quiz targets only small tests at the end of a given slide.

A new widget is added to display and control slide display in fullscreen
mode. Old display is still available for documentation channels or when
going out of fullscreen mode, to see details on comments / review / statistics
and have access to share options.

This commit is linked to task ID 1902304 and PR #29876. It closes the main
work on refactoring website slides into eLearning, with other tasks already
merged in current community [1][2][3][4][5].

[1] Task ID 1940360 landed at b2149bc: certification inclusion
[2] Task ID 1936153 landed at 6c6179e: homepage inclusion
[3] Task ID 1937160 landed at 8b7605c: selling courses
[4] Task ID 1922159 and 1940516 landed at 5fa651c and 6a64c3c:
new user profile and gamification of slides / forum
[5] Task ID 1938643 landed at 77b5673: upload channel/slide

@C3POdoo C3POdoo added the RD research & development, internal work label Jan 3, 2019
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch from 410c4c4 to 958af36 Compare January 4, 2019 14:57
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch 2 times, most recently from 6ef57c0 to f32b090 Compare January 25, 2019 12:59
Copy link
Contributor

@jem-odoo jem-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First pass of review. I have some questions and remarks.
This is a good start, but I think we need to clean a bit before going further.

  • MODELS
    1/ I thought a course was a slide. What it the purpose of slide.course then ?
    2/ what is the role of slide.resource ? It does not seem used. Moreover, if it contains a link to the slide, we should give it a more explicit name

  • CONTROLLERS
    Simply global comment before examinating the methods.
    Try to namespace all the route. As we are in slides module, the root NS should be /slides/. Then partition it with /slide, /course, /section, ... So, you should have something like that:

HTTP pages

/slides/<object>
/slides/slide/<object>
/slides/course/<object>

HTTP action routes

/slides/slide/<object>/<action>
/slides/course/<object>/<action>
/slides/section/<object>/<action>

JSON action routes

/slides/slide/<action>
/slides/course/<action>
/slides/section/<action>

To avoid breaking the existing, do not rename badly named existing routes. Simply modify the controller method.

  • VIEWS
    Some remarks on the xml id. Pay attention to the indentation in your xml files.

  • JS
    not reviewed yet. But don't forget at the end to remove all your console.log() ;)

addons/website_slides/models/slide_channel.py Outdated Show resolved Hide resolved
addons/website_slides/models/slide_channel.py Outdated Show resolved Hide resolved
addons/website_slides/models/slide_channel.py Outdated Show resolved Hide resolved
addons/website_slides/models/slide_channel.py Outdated Show resolved Hide resolved
@@ -50,6 +62,16 @@ def _compute_promoted_slide_id(self):
limit=1, order=self._order_by_strategy[record.promote_strategy])
record.promoted_slide_id = slides and slides[0] or False

course_content_infos = fields.Char('Content of the course', compute="_compute_course_content_infos")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to put all field definition, then the computed method, but not field definition, compute method, second field definition, ... to be guidelines compliant.

addons/website_slides/controllers/slide.py Outdated Show resolved Hide resolved

@http.route('/slide/setstate', website=True, type="json", auth="user")
def set_status_as_done(self, **kw):
slide = request.env['slide.slide'].browse(kw['slide'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make explicit and correclty named parameters: slide_id, user_id. Using only **kwargs allows human to call your controller without required parameters.

addons/website_slides/controllers/slide.py Outdated Show resolved Hide resolved
def update_course(self, **kw):
course = request.env['slide.channel'].browse(kw['channel_id'])
kw.pop('channel_id')
course.write(kw)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should restrict the fields you can write via this controller. Otherwise, you can write all you want here.
If so, then maybe use directly the write method might be a good idea.

addons/website_slides/__manifest__.py Outdated Show resolved Hide resolved
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch from f32b090 to 54d3696 Compare January 30, 2019 09:46
Copy link
Contributor

@jem-odoo jem-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2nd review: mostly controller, and still models

Some questions about flows and business, some remarks on models.
Still not review: all views and templates, and javascripts widgets ...

addons/website_slides/models/slide_channel.py Outdated Show resolved Hide resolved
else:
course.course_content_infos = " %s videos" % (course.nbr_videos)

total = fields.Integer(compute='_count_presentations', store=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this field ? total is not very precise IMHO.
Also, call the compute method _compute_<field name> ;)

@@ -28,6 +34,23 @@ class SlideUsersRelation(models.Model):
user_id = fields.Many2one('res.users', index=True, required=True)
vote = fields.Integer('Vote', default=0)

is_completed = fields.Boolean('Is completed',required=True)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no blank line


#Quiz related fields
question_ids = fields.One2many("slide.question","slide_id", string="Questions")
quiz_first_attempt_reward = fields.Integer(default=10,string="First Attempt")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

string attributes first (without string=), then the others. Space after coma.
Tip: use a linter ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alsi "First Attempt" does not really match the field name "_reward".
Maybe "First Attempt Reward" ?

Same for other fields.

if answer.is_correct:
good_answer_count += 1
if good_answer_count > 1:
raise models.ValidationError('A question can only have one good answer')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from odoo.exceptions import ValidationError in the import list, as the error classes are not defined in models.

'is_completed': not bad_answers
})
return {
'goodAnswers':[good_answer.id for good_answer in good_answers],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good_answer.ids will do the job ;)

points = slide[possible_points[user_slide_relation.quiz_attempts_count]]
else:
points = slide.quiz_fourth_attempt_reward
user_slide_relation.sudo().write({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to sudo as the search is already done in sudo

})
return {
'goodAnswers':[good_answer.id for good_answer in good_answers],
'badAnswers': [bad_answer.id for bad_answer in bad_answers],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

underscore notation please ;)

@http.route('/slide/setstate', website=True, type="json", auth="user")
def set_status_as_done(self, **kw):
slide = request.env['slide.slide'].browse(kw['slide'])
user = request.env['res.users'].browse(kw['user'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any user can call this controller and set the relation slide-user to complete to every other user. We have a security issue here. Avoid giving the user and take the current one maybe.

'user': request.env.user,
'is_public_user': request.env.user == request.website.user_id,
})
else:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else is not needed

tde-banana-odoo pushed a commit to odoo-dev/odoo that referenced this pull request Feb 7, 2019
…to gamification

Purpose of this commit is to prepare addition of gamification in slides /
eLearning platform. In order to be able to use karma and the badges in other
modules we move those models in gamification.

Partial commit linked to eLearning project. Main specifications related
to gamification and user profile can be found on task 1922159 (PR odoo#30514).
Main specifications related to eLearning can be found on task 1902304
(PR odoo#29876).
tde-banana-odoo pushed a commit to odoo-dev/odoo that referenced this pull request Feb 7, 2019
To encourage forum and slides users to be more active ranks are now added.
They are directly linked to karma. The more the user has karma the more his
rank will be high.

The default rank is Newbie, with 1 point of karma. Users with 0 karma are
considered as inactive on forum or slides. When a user reach a new rank
a mail is sent to him to congratulate him with his new rank.

To add a button in the mail template to allow users to go directly on
a website section (like forum or slides) simply override
get_gamification_redirection_data to add the target url.

Partial commit linked to eLearning project. Main specifications related
to gamification and user profile can be found on task 1922159 (PR odoo#30514).
Main specifications related to eLearning can be found on task 1902304
(PR odoo#29876).
tde-banana-odoo added a commit to odoo-dev/odoo that referenced this pull request Feb 7, 2019
…mification

Purpose is to be able to re-use frontend-related model, data and tools
for gamification. Currently only forum uses gamification. Soon slides module
will use them and user profile / biography will be expanded. This commit
prepares those features by already preparing the bridge module and adding
a publish option on badges.

Partial commit linked to eLearning project. Main specifications related
to gamification and user profile can be found on task 1922159 (PR odoo#30514).
Main specifications related to eLearning can be found on task 1902304
(PR odoo#29876).

Co-Authored-By: David Beguin <dbe@odoo.com>
Co-Authored-By: Thibault Delavallee <tde@odoo.com>
tde-banana-odoo added a commit to odoo-dev/odoo that referenced this pull request Feb 7, 2019
Purpose is to prepare the use of gamification tools in slides. In this commit
we add the dependency on website_profile (gamification front-end) in slides
and add the slides category on challenges.

Partial commit linked to eLearning project. Main specifications related
to gamification and user profile can be found on task 1922159 (PR odoo#30514).
Main specifications related to eLearning can be found on task 1902304
(PR odoo#29876).

Co-Authored-By: David Beguin <dbe@odoo.com>
Co-Authored-By: Thibault Delavallee <tde@odoo.com>
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch from 5335027 to e3a7341 Compare February 7, 2019 12:37
Copy link
Contributor

@awa-odoo awa-odoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not done yet but I've had enough JS for today ^^

@@ -0,0 +1,394 @@
var onYouTubeIframeAPIReady;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic comment: Your JS methods lack docstring.

Widget are usually split between private and public methods and every method should have its own docstring with "@OverRide", "@Private", "@param", ...

You can check out basic_fields.js for a good example of what it should ideally look like.

You probably planned to do it when everything is working and it's fine. But I have noticed it's easier to do it while coding the methods (or at least regularly) when you have a huge amount of JS (and it seems to be the case here).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I'm not sure that your JS linter is correctly configured.
Here is my config for eslint just in case (using VS Code):

{ "env": { "commonjs": true, "es6": true }, "extends": "eslint:recommended", "parserOptions": { "sourceType": "module" }, "rules": { "indent": [ "off", 4, { "SwitchCase": 1 } ], "linebreak-style": [ "error", "unix" ], "quotes": [ "off", "double" ], "semi": [ "error", "always" ], "comma-dangle": [ "off" ], "no-console": [ "warn", { "allow": ["warn", "error"] } ], "no-unused-vars": [ "warn", { "args": "none" } ], "no-empty": [ "warn" ], "eqeqeq": [ "error", "smart" ], "space-before-function-paren": [ "warn", {"anonymous": "always", "named": "never"} ], "keyword-spacing": [ "warn" ], "no-use-before-define": [ "warn", "nofunc" ] }, "globals": { "$": false, "jQuery": false, "_": false, "openerp": true, "odoo": true, "CKEDITOR": true, "google": false, "window": false, "setTimeout": false, "clearTimeout": false, "document": false, "console": false, "QUnit": false, "moment": false, "FileReader": false, "nv": false, "d3": false, "ace": false, "Option": false, "py": false, "XMLHttpRequest": false, "setInterval": false, "clearInterval": false, "Image": false, "jstz": false, "ZeroClipboard": false, "sessionStorage": false, "Node": false, "history": false, "gapi": false, "Event": false, "Gravitec": false, "navigator": false, "OneSignal": false } }

},
start: function(){
this._super.apply(this, arguments);
var user_id = this.$el.attr('user_id');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably use camel case for JS variable names.

firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);


var VideoPlayer = Widget.extend({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably use camel case for JS variable names.

},
_getSlides: function(){
var self = this;
var slides = $('.slide-list-cell');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably use $('.slide-list-cell').each(function() {}) here.

self.slides.push({
id: parseInt(slide.attr('slide_id'), 10),
name: slide.attr('slide_name'),
embed_code: slide.attr('slide_embed_code'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use camel case for JS variables.

},
_onAnswerClick: function(ev){
var self = this;
var target = $(ev.currentTarget)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of missing trailing ; here

var self = this;
switch(ev.key){
case "ArrowRight":
self._goToNextSlide();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing one level of indentation on this line and the break;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I know that pressing left/right arrow on YT forwards the video by 5 seconds.
It may collide with this? Or maybe not since the event is caught by the iframe?

// $('quiz-answer').not('.quiz-good-answer,.quiz-bad-answer').addClass('quiz-ignored-answer');
if(data.passed){
self.slide.done = true;
$('#check-'+self.slide.id).removeClass('text-muted');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again you can chain the calls with one selector.

}
})
} else {
$('.quiz-questions').append($('<p class="quiz-danger text-danger mt-1">All questions must be answered !</p>'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you need to translate this with _t()

})
}
for(var i = 0; i < answers.badAnswers.length; i++){
$('#'+ answers.badAnswers[i]).removeClass('quiz-good-answer');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$badAnswer = $('#'+ answers.badAnswers[i])
$badAnswer.removeClass('quiz-good-answer')
    .addClass('quiz-bad-answer')
    .unbind('click');

$badAnswer.find('.radio-box span').replaceWith($('<i class="fa fa-times "></i>'));
$badAnswer.find('.radio-box input').prop('checked', false);

Or something like that but you get the point.

robodoo pushed a commit that referenced this pull request Feb 7, 2019
…to gamification

Purpose of this commit is to prepare addition of gamification in slides /
eLearning platform. In order to be able to use karma and the badges in other
modules we move those models in gamification.

Partial commit linked to eLearning project. Main specifications related
to gamification and user profile can be found on task 1922159 (PR #30514).
Main specifications related to eLearning can be found on task 1902304
(PR #29876).
robodoo pushed a commit that referenced this pull request Feb 7, 2019
To encourage forum and slides users to be more active ranks are now added.
They are directly linked to karma. The more the user has karma the more his
rank will be high.

The default rank is Newbie, with 1 point of karma. Users with 0 karma are
considered as inactive on forum or slides. When a user reach a new rank
a mail is sent to him to congratulate him with his new rank.

To add a button in the mail template to allow users to go directly on
a website section (like forum or slides) simply override
get_gamification_redirection_data to add the target url.

Partial commit linked to eLearning project. Main specifications related
to gamification and user profile can be found on task 1922159 (PR #30514).
Main specifications related to eLearning can be found on task 1902304
(PR #29876).
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch from 6cfe905 to 290ee6c Compare February 19, 2019 11:38
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch from 290ee6c to 09658b2 Compare February 19, 2019 11:45
@qmo-odoo qmo-odoo force-pushed the master-slides-becomes-courses-qmo branch from 09658b2 to 9abcae3 Compare February 19, 2019 11:54
@tde-banana-odoo
Copy link
Contributor Author

@robodoo r+

@tde-banana-odoo
Copy link
Contributor Author

@robodoo r+

Purpose of this commit is to introduce a new way of displaying and managing
slides in eLearning module. Its purpose is to give a better experience to
users when going through a course. Notably a fullscreen mode allows to take
lessons one by one without going out of the elearning display. Integration
of all slide types eases taking the course step by step.

Quiz are introduced in this commit. Those are an addition to slides with
some question / answers (multiple choice). It allows customer to gain karma
and improves gamification. Certifications are still done using the survey
application. Quiz targets only small tests at the end of a given slide.

A new widget is added to display and control slide display in fullscreen
mode. Old display is still available for documentation channels or when
going out of fullscreen mode, to see details on comments / review / statistics
and have access to share options.

This commit is linked to task ID 1902304 and PR odoo#29876. It closes the main
work on refactoring website slides into eLearning, with other tasks already
merged in current community [1][2][3][4][5].

[1] Task ID 1940360 landed at b2149bc: certification inclusion
[2] Task ID 1936153 landed at 6c6179e: homepage inclusion
[3] Task ID 1937160 landed at 8b7605c: selling courses
[4] Task ID 1922159 and 1940516 landed at 5fa651c and 6a64c3c:
    new user profile and gamification of slides / forum
[5] Task ID 1938643 landed at 77b5673: upload channel/slide
@tde-banana-odoo
Copy link
Contributor Author

@robodoo r+

@robodoo robodoo added the CI 🤖 Robodoo has seen passing statuses label Feb 19, 2019
robodoo pushed a commit that referenced this pull request Feb 19, 2019
Purpose of this commit is to introduce a new way of displaying and managing
slides in eLearning module. Its purpose is to give a better experience to
users when going through a course. Notably a fullscreen mode allows to take
lessons one by one without going out of the elearning display. Integration
of all slide types eases taking the course step by step.

Quiz are introduced in this commit. Those are an addition to slides with
some question / answers (multiple choice). It allows customer to gain karma
and improves gamification. Certifications are still done using the survey
application. Quiz targets only small tests at the end of a given slide.

A new widget is added to display and control slide display in fullscreen
mode. Old display is still available for documentation channels or when
going out of fullscreen mode, to see details on comments / review / statistics
and have access to share options.

This commit is linked to task ID 1902304 and PR #29876. It closes the main
work on refactoring website slides into eLearning, with other tasks already
merged in current community [1][2][3][4][5].

[1] Task ID 1940360 landed at b2149bc: certification inclusion
[2] Task ID 1936153 landed at 6c6179e: homepage inclusion
[3] Task ID 1937160 landed at 8b7605c: selling courses
[4] Task ID 1922159 and 1940516 landed at 5fa651c and 6a64c3c:
    new user profile and gamification of slides / forum
[5] Task ID 1938643 landed at 77b5673: upload channel/slide
@tde-banana-odoo tde-banana-odoo deleted the master-slides-becomes-courses-qmo branch February 19, 2019 17:23
@robodoo robodoo added closed 💔 and removed r+ 👌 CI 🤖 Robodoo has seen passing statuses labels Feb 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RD research & development, internal work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants