summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Beguin <dbe@odoo.com>2019-03-14 17:35:50 +0000
committerDavid Beguin <dbe@odoo.com>2019-03-15 15:05:54 +0000
commit5798ca28bfa1dc082fedff5e68ab3f7eb6236687 (patch)
tree3de6accf55085fc5c2d46b7227d5f00d5cda5590
parentd4db21a9cc89bc09acb64f8743bf12df910abc96 (diff)
[IMP] website_slides : improve get slide access computation
As slides are returned in sudo to the template, the user rights were checked via a can_access variable set in the template directly. In order to disable the vote for user that cannot get access to the course all the checks are now done in backend (also to avoid to get access to slides in sudo mode with rpc calls). We add now, for each slide on the course view, the access and vote rights to the template : can_access and can_vote. Those two are computed in backend, using the user's access right instead of admin's. But, as if the user is not member of the channel, he cannot get access to the course slides (expect for Free Peview ones), so the check on can_vote will crash. This is why we check the access rights before checking can_vote, for each slides (as free preview slides are still accessible, even if the user is not in channel members). The vote widget is disabled if user's can_access or can_vote = False, enabled otherwise. If user have access but have not enough karma, the controller will handle this case and return an error to the user telling him he has not enough karma to vote. If user can vote but cannot access, the controller will handle this case and return an error to the user telling him he has no access to the lesson. Task ID: 1943788 PR #31321
-rw-r--r--addons/website_slides/controllers/main.py18
-rw-r--r--addons/website_slides/models/slide_channel.py8
-rw-r--r--addons/website_slides/models/slide_slide.py25
-rw-r--r--addons/website_slides/static/src/js/slides_slide_like.js6
-rw-r--r--addons/website_slides/static/src/scss/website_slides.scss6
-rw-r--r--addons/website_slides/views/website_slides_templates_course.xml15
-rw-r--r--addons/website_slides/views/website_slides_templates_lesson.xml6
7 files changed, 59 insertions, 25 deletions
diff --git a/addons/website_slides/controllers/main.py b/addons/website_slides/controllers/main.py
index 83934343402..da9fe1a7b81 100644
--- a/addons/website_slides/controllers/main.py
+++ b/addons/website_slides/controllers/main.py
@@ -45,10 +45,7 @@ class WebsiteSlides(WebsiteProfile):
slide = request.env['slide.slide'].browse(int(slide_id)).exists()
if not slide:
return {'error': 'slide_wrong'}
- try:
- slide.check_access_rights('read')
- slide.check_access_rule('read')
- except:
+ if not slide._check_read_access():
return {'error': 'slide_access'}
return {'slide': slide}
@@ -370,7 +367,6 @@ class WebsiteSlides(WebsiteProfile):
'user': request.env.user,
'pager': pager,
'is_public_user': request.website.is_public_user(),
- 'is_slides_publisher': request.env.user.has_group('website.group_website_publisher'),
}
if not request.env.user._is_public():
last_message_values = request.env['mail.message'].search([
@@ -402,10 +398,11 @@ class WebsiteSlides(WebsiteProfile):
force_void=True,
limit=self._slides_per_category if channel.channel_type == 'documentation' else False,
offset=pager['offset'])
+
+ values['slide_promoted_access'] = values['slide_promoted'].sudo(request.env.user)._get_slide_action_access()[values['slide_promoted'].id]
values['channel_progress'] = self._get_channel_progress(channel, include_quiz=True)
values = self._prepare_additional_channel_values(values, **kw)
-
return request.render('website_slides.course_main', values)
# SLIDE.CHANNEL UTILS
@@ -494,6 +491,8 @@ class WebsiteSlides(WebsiteProfile):
if 'fullscreen' in kwargs:
return request.render("website_slides.slide_fullscreen", values)
+ else:
+ values['slide_access'] = slide.sudo(request.env.user)._get_slide_action_access()[slide.id]
return request.render("website_slides.slide_main", values)
@http.route('''/slides/slide/<model("slide.slide"):slide>/pdf_content''',
@@ -576,7 +575,12 @@ class WebsiteSlides(WebsiteProfile):
])
if (upvote and slide_partners.vote == 1) or (not upvote and slide_partners.vote == -1):
return {'error': 'vote_done'}
- slide = request.env['slide.slide'].browse(int(slide_id))
+ # check slide access
+ fetch_res = self._fetch_slide(slide_id)
+ if fetch_res.get('error'):
+ return fetch_res
+ # check slide operation
+ slide = fetch_res['slide']
if not slide.channel_id.allow_comment:
return {'error': 'comment_disabled'}
if not slide.can_vote:
diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py
index cd7565bd41a..e0af206ff80 100644
--- a/addons/website_slides/models/slide_channel.py
+++ b/addons/website_slides/models/slide_channel.py
@@ -453,22 +453,24 @@ class Channel(models.Model):
if uncategorized_slides or force_void:
category_data.append({
'category': False, 'id': False,
- 'name': _('Uncategorized'), 'slug_name': _('Uncategorized'),
+ 'name': _('Uncategorized'), 'slug_name': _('Uncategorized'),
'total_slides': len(uncategorized_slides),
'slides': uncategorized_slides[(offset or 0):(limit or len(uncategorized_slides))],
+ 'slides_access': uncategorized_slides.sudo(self.env.user)._get_slide_action_access()
})
# Then all categories by natural order
for category in all_categories:
category_slides = all_slides.filtered(lambda slide: slide.category_id == category)
if not category_slides and not force_void:
continue
+ slides = category_slides[(offset or 0):(limit or len(category_slides))]
category_data.append({
'category': category, 'id': category.id,
'name': category.name, 'slug_name': slug(category),
'total_slides': len(category_slides),
- 'slides': category_slides[(offset or 0):(limit or len(category_slides))],
+ 'slides': slides,
+ 'slides_access': slides.sudo(self.env.user)._get_slide_action_access()
})
-
return category_data
diff --git a/addons/website_slides/models/slide_slide.py b/addons/website_slides/models/slide_slide.py
index a4a96001673..dfd7cc29a46 100644
--- a/addons/website_slides/models/slide_slide.py
+++ b/addons/website_slides/models/slide_slide.py
@@ -14,7 +14,7 @@ from werkzeug import urls
from odoo import api, fields, models, _
from odoo.addons.http_routing.models.ir_http import slug
from odoo.addons.gamification.models.gamification_karma_rank import KarmaError
-from odoo.exceptions import Warning, UserError
+from odoo.exceptions import Warning, UserError, AccessError
from odoo.http import request
from odoo.addons.http_routing.models.ir_http import url_for
@@ -273,6 +273,7 @@ class Slide(models.Model):
@api.multi
def _compute_karma_rights(self):
+ """ This method supposed current user have access to the slide. If not, I will crash, meaning he can not execute the action """
for slide in self:
slide.can_comment = self.env.user.karma >= slide.channel_id.karma_slide_comment
slide.can_vote = self.env.user.karma >= slide.channel_id.karma_slide_vote
@@ -357,6 +358,28 @@ class Slide(models.Model):
return groups
# ---------------------------------------------------------
+ # Access Rights Methods
+ # ---------------------------------------------------------
+
+ def _check_read_access(self):
+ try:
+ self.check_access_rights('read')
+ self.check_access_rule('read')
+ except AccessError:
+ return False
+ return True
+
+ def _get_slide_action_access(self):
+ result = dict((slide_id, dict(can_access=False, can_vote=False, can_comment=False)) for slide_id in self.ids)
+ for slide in self:
+ can_access = slide._check_read_access()
+ if can_access and (slide.channel_id.is_member or slide.is_preview or slide.can_publish):
+ result[slide.id]['can_access'] = True
+ result[slide.id]['can_vote'] = slide.can_vote
+ result[slide.id]['can_comment'] = slide.can_comment
+ return result
+
+ # ---------------------------------------------------------
# Business Methods
# ---------------------------------------------------------
diff --git a/addons/website_slides/static/src/js/slides_slide_like.js b/addons/website_slides/static/src/js/slides_slide_like.js
index bb0542a5f7e..6609cc0ca92 100644
--- a/addons/website_slides/static/src/js/slides_slide_like.js
+++ b/addons/website_slides/static/src/js/slides_slide_like.js
@@ -56,9 +56,11 @@ var SlideLikeWidget = Widget.extend({
self.$el.find('span.o_wslides_js_slide_like_down span').text(data.dislikes);
} else {
if (data.error === 'public_user') {
- self._popoverAlert(self.$el, _.str.sprintf(_t('Please <a href="/web/login?redirect=%s">login</a> to vote this slide'), (document.URL)));
+ self._popoverAlert(self.$el, _.str.sprintf(_t('Please <a href="/web/login?redirect=%s">login</a> to vote this lesson'), (document.URL)));
} else if (data.error === 'vote_done') {
- self._popoverAlert(self.$el, _t('You have already voted for this slide'));
+ self._popoverAlert(self.$el, _t('You have already voted for this lesson'));
+ } else if (data.error === 'slide_access') {
+ self._popoverAlert(self.$el, _t('You don\'t have access to this lesson'));
} else if (data.error === 'comment_disabled') {
self._popoverAlert(self.$el, _t('Votes and comments are disabled for this channel'));
} else if (data.error === 'missing_karma') {
diff --git a/addons/website_slides/static/src/scss/website_slides.scss b/addons/website_slides/static/src/scss/website_slides.scss
index 4e83de3b44d..bbe635a89fa 100644
--- a/addons/website_slides/static/src/scss/website_slides.scss
+++ b/addons/website_slides/static/src/scss/website_slides.scss
@@ -32,8 +32,10 @@ $o-enterprise-radient-color: #62495B !default;
.o_wslides_js_slide_like_up,
.o_wslides_js_slide_like_down {
- cursor: pointer;
- color: $link-color;
+ &:not(.disabled) {
+ cursor: pointer;
+ color: $link-color;
+ }
}
.o_wslides_js_lesson_quiz_question {
diff --git a/addons/website_slides/views/website_slides_templates_course.xml b/addons/website_slides/views/website_slides_templates_course.xml
index e3a6583ca8b..50f118f71eb 100644
--- a/addons/website_slides/views/website_slides_templates_course.xml
+++ b/addons/website_slides/views/website_slides_templates_course.xml
@@ -387,7 +387,7 @@
</div>
<div class="col-8">
<h3 class="w-100" t-att-title="slide_promoted.name">
- <t t-if="slide_promoted.is_preview or channel.is_member or is_slides_publisher">
+ <t t-if="slide_promoted_access['can_access']">
<a t-attf-href="/slides/slide/#{slug(slide_promoted)}" class="font-weight-bold text-muted" t-field="slide_promoted.name"/>
</t>
<t t-else="">
@@ -420,7 +420,9 @@
</div>
<div class="row mx-n2 mt8">
<t t-foreach="category['slides']" t-as="slide">
- <div class="col-md-3 col-sm-6 px-2 col-xs-12 d-flex flex-grow-1" t-call="website_slides.lesson_card"/>
+ <div class="col-md-3 col-sm-6 px-2 col-xs-12 d-flex flex-grow-1" t-call="website_slides.lesson_card">
+ <t t-set="slide_access" t-value="category['slides_access'][slide.id]"/>
+ </div>
</t>
</div>
</div>
@@ -438,15 +440,14 @@
<template id='lesson_card' name="Lesson Card">
<div class="card w-100 o_wslides_lesson_card mb-4">
<t t-set="lesson_image" t-value="'/slides/slide/%s/get_image?field=image_large' % slide.id"/>
- <t t-set="can_access" t-value="slide.is_preview or channel.is_member or is_slides_publisher"/>
- <a t-if="can_access" t-attf-href="/slides/slide/#{slug(slide)}" t-title="slide.name">
+ <a t-if="slide_access['can_access']" t-attf-href="/slides/slide/#{slug(slide)}" t-title="slide.name">
<div class="card-img-top" t-attf-style="padding-top: 50%; background-image: url(#{lesson_image}); background-size: cover; background-position:center"/>
</a>
<t t-else="">
<div class="card-img-top" t-attf-style="padding-top: 50%; background-image: url(#{lesson_image}); background-size: cover; background-position:center"/>
</t>
<div class="card-body">
- <a t-if="can_access" class="card-title h5" t-attf-href="/slides/slide/#{slug(slide)}" t-esc="slide.name"/>
+ <a t-if="slide_access['can_access']" class="card-title h5" t-attf-href="/slides/slide/#{slug(slide)}" t-esc="slide.name"/>
<span t-else="" class="card-title h5 text-muted" t-esc="slide.name"/>
<div class="card-subtitle mb-2 text-muted">
<t t-if="slide.is_preview">
@@ -469,11 +470,11 @@
<div class="d-flex align-items-center small">
<span class="font-weight-bold mr-auto" t-field="slide.completion_time" t-options='{"widget": "float_time"}'/>
<div class="o_wslides_js_slide_like mr-2">
- <span class="o_wslides_js_slide_like_up" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
+ <span t-att-class="('o_wslides_js_slide_like_up %s') % ('disabled' if not (slide_access['can_access'] and slide_access['can_vote']) else '')" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
<i class="fa fa-thumbs-up fa-1x" role="img" aria-label="Likes" title="Likes"></i>
<span t-esc="slide.likes"/>
</span>
- <span class="o_wslides_js_slide_like_down" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
+ <span t-att-class="('o_wslides_js_slide_like_down %s') % ('disabled' if not (slide_access['can_access'] and slide_access['can_vote']) else '')" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
<i class="fa fa-thumbs-down fa-1x" role="img" aria-label="Dislikes" title="Dislikes"></i>
<span t-esc="slide.dislikes"/>
</span>
diff --git a/addons/website_slides/views/website_slides_templates_lesson.xml b/addons/website_slides/views/website_slides_templates_lesson.xml
index c589092aaa4..c7f1cd8a7e1 100644
--- a/addons/website_slides/views/website_slides_templates_lesson.xml
+++ b/addons/website_slides/views/website_slides_templates_lesson.xml
@@ -241,11 +241,11 @@
<span class="text-muted font-weight-bold mr-3">Rating</span>
<div class="text-muted border-left pl-3">
<div class="o_wslides_js_slide_like mr-2">
- <span class="o_wslides_js_slide_like_up" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
+ <span t-att-class="('o_wslides_js_slide_like_up %s') % ('disabled' if not (slide_access['can_access'] and slide_access['can_vote']) else '')" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
<i class="fa fa-thumbs-up fa-1x" role="img" aria-label="Likes" title="Likes"></i>
<span t-esc="slide.likes"/>
</span>
- <span class="o_wslides_js_slide_like_down ml-3" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
+ <span t-att-class="('o_wslides_js_slide_like_down ml-3 %s') % ('disabled' if not (slide_access['can_access'] and slide_access['can_vote']) else '')" tabindex="0" data-toggle="popover" t-att-data-slide-id="slide.id">
<i class="fa fa-thumbs-down fa-1x" role="img" aria-label="Dislikes" title="Dislikes"></i>
<span t-esc="slide.dislikes"/>
</span>
@@ -289,7 +289,7 @@
<div role="tabpanel" t-att-class="comments and 'tab-pane fade in show active' or 'tab-pane fade'" id="discuss">
<t t-call="portal.message_thread">
<t t-set="object" t-value="slide"/>
- <t t-set="disable_composer" t-value="not (slide.can_comment and slide.channel_id.allow_comment and slide.channel_id.channel_type == 'training')"/>
+ <t t-set="disable_composer" t-value="not (slide_access['can_comment'] and slide.channel_id.allow_comment and slide.channel_id.channel_type == 'training')"/>
<t t-set="display_rating" t-value="False"/>
</t>
</div>