From 5798ca28bfa1dc082fedff5e68ab3f7eb6236687 Mon Sep 17 00:00:00 2001 From: David Beguin Date: Thu, 14 Mar 2019 17:35:50 +0000 Subject: [PATCH] [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 --- addons/website_slides/controllers/main.py | 18 +++++++------ addons/website_slides/models/slide_channel.py | 8 +++--- addons/website_slides/models/slide_slide.py | 25 ++++++++++++++++++- .../static/src/js/slides_slide_like.js | 6 +++-- .../static/src/scss/website_slides.scss | 6 +++-- .../views/website_slides_templates_course.xml | 15 +++++------ .../views/website_slides_templates_lesson.xml | 6 ++--- 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//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 @@ -356,6 +357,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 login to vote this slide'), (document.URL))); + self._popoverAlert(self.$el, _.str.sprintf(_t('Please login 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 @@
-
+
+ +
@@ -438,15 +440,14 @@