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

Closed
wants to merge 1 commit into
base: master
from

Conversation

Projects
None yet
7 participants
@tde-banana-odoo
Copy link
Contributor

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

@robodoo robodoo added the seen 🙂 label Jan 3, 2019

@C3POdoo C3POdoo added the RD label Jan 3, 2019

@qmo-odoo qmo-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch Jan 4, 2019

@qmo-odoo qmo-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch 2 times, most recently Jan 24, 2019

@jem-odoo
Copy link
Contributor

jem-odoo left a comment

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() ;)

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 addons/website_slides/models/slide_channel.py Outdated
addons/website_slides/models/slide_channel.py Outdated
@@ -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")

This comment has been minimized.

@jem-odoo

jem-odoo Jan 29, 2019

Contributor

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

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

@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'])

This comment has been minimized.

@jem-odoo

jem-odoo Jan 29, 2019

Contributor

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

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

This comment has been minimized.

@jem-odoo

jem-odoo Jan 29, 2019

Contributor

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.

Show resolved Hide resolved addons/website_slides/__manifest__.py Outdated

@qmo-odoo qmo-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch Jan 30, 2019

@jem-odoo
Copy link
Contributor

jem-odoo left a comment

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 ...

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

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

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

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)

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

no blank line

addons/website_slides/models/slide_slide.py Outdated

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

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

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

This comment has been minimized.

@awa-odoo

awa-odoo Feb 15, 2019

Contributor

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

Same for other fields.

addons/website_slides/models/slide_slide.py Outdated
if answer.is_correct:
good_answer_count += 1
if good_answer_count > 1:
raise models.ValidationError('A question can only have one good answer')

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

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

addons/website_slides/controllers/slide.py Outdated
'is_completed': not bad_answers
})
return {
'goodAnswers':[good_answer.id for good_answer in good_answers],

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

good_answer.ids will do the job ;)

addons/website_slides/controllers/slide.py Outdated
points = slide[possible_points[user_slide_relation.quiz_attempts_count]]
else:
points = slide.quiz_fourth_attempt_reward
user_slide_relation.sudo().write({

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

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

addons/website_slides/controllers/slide.py Outdated
})
return {
'goodAnswers':[good_answer.id for good_answer in good_answers],
'badAnswers': [bad_answer.id for bad_answer in bad_answers],

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

underscore notation please ;)

addons/website_slides/controllers/slide.py Outdated
@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'])

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

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.

addons/website_slides/controllers/slide.py Outdated
'user': request.env.user,
'is_public_user': request.env.user == request.website.user_id,
})
else:

This comment has been minimized.

@jem-odoo

jem-odoo Feb 6, 2019

Contributor

else is not needed

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

[REF] gamification, website_forum: move karma, badge and badge level …
…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 added a commit to odoo-dev/odoo that referenced this pull request Feb 7, 2019

[IMP] gamification : add ranks based on karma
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

[ADD] website_profile: new module holding website-related code for ga…
…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

[IMP] website_slides: add dependency on website profile
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 odoo-dev:master-slides-becomes-courses-qmo branch Feb 7, 2019

@awa-odoo
Copy link
Contributor

awa-odoo left a comment

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

@@ -0,0 +1,394 @@
var onYouTubeIframeAPIReady;

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

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).

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

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');

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

Should probably use camel case for JS variable names.

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);


var VideoPlayer = Widget.extend({

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

Should probably use camel case for JS variable names.

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
},
_getSlides: function(){
var self = this;
var slides = $('.slide-list-cell');

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

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

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
self.slides.push({
id: parseInt(slide.attr('slide_id'), 10),
name: slide.attr('slide_name'),
embed_code: slide.attr('slide_embed_code'),

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

Should use camel case for JS variables.

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
},
_onAnswerClick: function(ev){
var self = this;
var target = $(ev.currentTarget)

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

A lot of missing trailing ; here

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
var self = this;
switch(ev.key){
case "ArrowRight":
self._goToNextSlide();

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

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

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

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?

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
// $('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');

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

Again you can chain the calls with one selector.

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
}
})
} else {
$('.quiz-questions').append($('<p class="quiz-danger text-danger mt-1">All questions must be answered !</p>'));

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor

I think you need to translate this with _t()

addons/website_slides/static/src/js/slides_course_fullscreen_player.js Outdated
})
}
for(var i = 0; i < answers.badAnswers.length; i++){
$('#'+ answers.badAnswers[i]).removeClass('quiz-good-answer');

This comment has been minimized.

@awa-odoo

awa-odoo Feb 7, 2019

Contributor
$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

[REF] gamification, website_forum: move karma, badge and badge level …
…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

[IMP] gamification : add ranks based on karma
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).
@dbeguin
Copy link
Contributor

dbeguin left a comment

Last comments =) I guess to do after merge / freeze in a fix branch
bisous !

channel_slides = [s.id for s in slide.channel_id.slide_ids]
slide_index = channel_slides.index(slide.id)
previous_slide = None
next_slide = None

This comment has been minimized.

@dbeguin

dbeguin Feb 19, 2019

Contributor

you could use conditional declaration :

channel_slide_ids = slide.channel_id.slide_ids.ids
slide_index = channel_slide_ids.index(slide.id)
previous_slide = slide.channel_id.slide_ids[slide_index-1] if slide_index > 0 else None
next_slide = slide.channel_id.slide_ids[slide_index+1] if slide_index < len(channel_slide_ids) - 1 else None
addons/website_slides/controllers/main.py Outdated
if slide_partner.quiz_attempts_count < len(possible_points):
points = possible_points[slide_partner.quiz_attempts_count]
else:
points = possible_points[len(possible_points)-1]

This comment has been minimized.

@dbeguin

dbeguin Feb 19, 2019

Contributor

same remark, use conditional declaration
And, because it's second time you compute this in the controler, maybe extract this into

def _get_quiz_points(self, slide, attempt_count):
    possible_points = [slide.quiz_first_attempt_reward,slide.quiz_second_attempt_reward,slide.quiz_third_attempt_reward, slide.quiz_fourth_attempt_reward]
    return possible_points[attempt_count] if attempt_count < len(possible_points) else possible_points[len(possible_points) - 1]
addons/website_slides/controllers/main.py Outdated
good_answers = answers.search([('id', 'in', answer_ids),('is_correct', '=', True)])
bad_answers = answers - good_answers
slide_partner = request.env['slide.slide.partner'].search([('slide_id', '=', slide_id),('partner_id', '=', request.env.user.partner_id.id)])
possible_points = [slide.quiz_first_attempt_reward,slide.quiz_second_attempt_reward,slide.quiz_third_attempt_reward, slide.quiz_fourth_attempt_reward]

This comment has been minimized.

@dbeguin

dbeguin Feb 19, 2019

Contributor

instead, extract directly in a get_quiz_point method (see bellow)

def resequence_slides(self, slides_data=None, **kw):
channel_user = None
for slide in slides_data:
s = request.env['slide.slide'].browse(slide['id'])

This comment has been minimized.

@dbeguin

dbeguin Feb 19, 2019

Contributor

aaand name it slide, instead of s, because it's more self_speaking :)
Like :

for slide in request.env['slide.slide'].search([('id', 'in', [slide['id'] for slide in slides_data])]):
   doStuff()

@qmo-odoo qmo-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch Feb 19, 2019

@qmo-odoo qmo-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch Feb 19, 2019

@qmo-odoo qmo-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch Feb 19, 2019

@tde-banana-odoo

This comment has been minimized.

Copy link
Contributor Author

tde-banana-odoo commented Feb 19, 2019

@robodoo robodoo added the r+ 👌 label Feb 19, 2019

@tde-banana-odoo tde-banana-odoo force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch Feb 19, 2019

@robodoo robodoo removed the r+ 👌 label Feb 19, 2019

@tde-banana-odoo

This comment has been minimized.

Copy link
Contributor Author

tde-banana-odoo commented Feb 19, 2019

@robodoo robodoo added the r+ 👌 label Feb 19, 2019

[IMP] website_slides: Add elearning feature to slides
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 force-pushed the odoo-dev:master-slides-becomes-courses-qmo branch to a50600d Feb 19, 2019

@tde-banana-odoo

This comment has been minimized.

Copy link
Contributor Author

tde-banana-odoo commented Feb 19, 2019

@robodoo robodoo added the CI 🤖 label Feb 19, 2019

robodoo pushed a commit that referenced this pull request Feb 19, 2019

[IMP] website_slides: Add elearning feature to slides
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 odoo-dev:master-slides-becomes-courses-qmo branch Feb 19, 2019

@robodoo robodoo added closed 💔 and removed r+ 👌 CI 🤖 labels Feb 19, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.