[REF] website_slides: introduce slide / user relationship and use it for vote
Purpose of this commit is to store a relationship between slides and users. Indeed starting from now we will track more user interaction with the slides module. In this commit we introduce a model that is used to populate and decorate the relationship between slides and users, slide.users. From slides or users point of view it behaves like a many2many. It can also be used to store more information about the user interaction with the slide. We use it here to store the user vote. Like and dislike are not static counters anymore but computed fields based on user votes. It is implemented as a tristate field. As it is a technical model no access on slide.users is granted. Controllers and methods grant access to the relationship in order to avoid information lead and keep technical details private. Future commits improving the eLearning use of slides will notably store information about user having read the slide, taken a quizz or gaining karma depending on some actions performed on the slide. This commit is linked to task ID 1934488 and PR #30620 .
This commit is contained in:
@@ -35,28 +35,6 @@ class WebsiteSlides(http.Controller):
|
||||
request.session[slide_key] = viewed_slides
|
||||
return True
|
||||
|
||||
def _check_session_slide_vote(self, slide, upvote=True):
|
||||
if not request.session.get('__wslides_upvote'):
|
||||
request.session['__wslides_upvote'] = []
|
||||
if not request.session.get('__wslides_downvote'):
|
||||
request.session['__wslides_downvote'] = []
|
||||
if upvote and slide.id in request.session['__wslides_upvote']:
|
||||
return False
|
||||
if not upvote and slide.id in request.session['__wslides_downvote']:
|
||||
return False
|
||||
if upvote and slide.id in request.session['__wslides_downvote']:
|
||||
request.session['__wslides_downvote'].remove(slide.id)
|
||||
return 0
|
||||
if not upvote and slide.id in request.session['__wslides_upvote']:
|
||||
request.session['__wslides_upvote'].remove(slide.id)
|
||||
return 0
|
||||
if upvote:
|
||||
request.session['__wslides_upvote'].append(slide.id)
|
||||
return 1
|
||||
if not upvote:
|
||||
request.session['__wslides_downvote'].append(slide.id)
|
||||
return -1
|
||||
|
||||
def _get_slide_detail(self, slide):
|
||||
most_viewed_slides = slide.get_most_viewed_slides(self._slides_per_list)
|
||||
related_slides = slide.get_related_slides(self._slides_per_list)
|
||||
@@ -234,21 +212,19 @@ class WebsiteSlides(http.Controller):
|
||||
def slide_like(self, slide_id, upvote):
|
||||
if request.website.is_public_user():
|
||||
return {'error': 'public_user'}
|
||||
slide = request.env['slide.slide'].browse(int(slide_id))
|
||||
slide.check_access_rights('read')
|
||||
slide.check_access_rule('read')
|
||||
check = self._check_session_slide_vote(slide, upvote=upvote)
|
||||
if check is False:
|
||||
slide_users = request.env['slide.users'].sudo().search([
|
||||
('slide_id', '=', slide_id),
|
||||
('user_id', '=', request.env.uid)
|
||||
])
|
||||
if (upvote and slide_users.vote == 1) or (not upvote and slide_users.vote == -1):
|
||||
return {'error': 'vote_done'}
|
||||
if check == 1:
|
||||
slide.sudo().likes += 1
|
||||
elif check == 0 and upvote:
|
||||
slide.sudo().dislikes -= 1
|
||||
elif check == 0 and not upvote:
|
||||
slide.sudo().likes -= 1
|
||||
slide = request.env['slide.slide'].browse(int(slide_id))
|
||||
if upvote:
|
||||
slide.action_like()
|
||||
else:
|
||||
slide.sudo().dislikes += 1
|
||||
return {'state': check, 'likes': slide.likes, 'dislikes': slide.dislikes}
|
||||
slide.action_dislike()
|
||||
slide.invalidate_cache()
|
||||
return slide.read(['likes', 'dislikes', 'user_vote'])[0]
|
||||
|
||||
@http.route(['/slides/slide/send_share_email'], type='json', auth='user', website=True)
|
||||
def slide_send_share_email(self, slide_id, email):
|
||||
|
||||
@@ -19,6 +19,16 @@ from odoo.http import request
|
||||
from odoo.addons.http_routing.models.ir_http import url_for
|
||||
|
||||
|
||||
class SlideUsersRelation(models.Model):
|
||||
_name = 'slide.users'
|
||||
_description = 'Slide / Users decorated m2m'
|
||||
_table = 'slide_users'
|
||||
|
||||
slide_id = fields.Many2one('slide.slide', index=True, required=True)
|
||||
user_id = fields.Many2one('res.users', index=True, required=True)
|
||||
vote = fields.Integer('Vote', default=0)
|
||||
|
||||
|
||||
class EmbeddedSlide(models.Model):
|
||||
""" Embedding in third party websites. Track view count, generate statistics. """
|
||||
_name = 'slide.embed'
|
||||
@@ -93,6 +103,10 @@ class Slide(models.Model):
|
||||
image = fields.Binary('Image', attachment=True)
|
||||
image_medium = fields.Binary('Medium', compute="_get_image", store=True, attachment=True)
|
||||
image_thumb = fields.Binary('Thumbnail', compute="_get_image", store=True, attachment=True)
|
||||
# subscribers
|
||||
user_ids = fields.Many2many('res.users', 'slide_users', 'slide_id', 'user_id',
|
||||
string='Subscribers', groups='base.group_system')
|
||||
slide_user_ids = fields.One2many('slide.users', 'slide_id', string='Subscribers information', groups='base.group_system')
|
||||
|
||||
@api.depends('image')
|
||||
def _get_image(self):
|
||||
@@ -135,8 +149,9 @@ class Slide(models.Model):
|
||||
# website
|
||||
website_id = fields.Many2one(related='channel_id.website_id', readonly=True)
|
||||
date_published = fields.Datetime('Publish Date')
|
||||
likes = fields.Integer('Likes')
|
||||
dislikes = fields.Integer('Dislikes')
|
||||
likes = fields.Integer('Likes', compute='_compute_user_info', store=True)
|
||||
dislikes = fields.Integer('Dislikes', compute='_compute_user_info', store=True)
|
||||
user_vote = fields.Integer('User vote', compute='_compute_user_info')
|
||||
# views
|
||||
embedcount_ids = fields.One2many('slide.embed', 'slide_id', string="Embed Count")
|
||||
slide_views = fields.Integer('# of Website Views')
|
||||
@@ -148,6 +163,24 @@ class Slide(models.Model):
|
||||
for record in self:
|
||||
record.total_views = record.slide_views + record.embed_views
|
||||
|
||||
@api.depends('slide_user_ids.vote')
|
||||
def _compute_user_info(self):
|
||||
slide_data = dict.fromkeys(self.ids, dict({'likes': 0, 'dislikes': 0, 'user_vote': False}))
|
||||
slide_users = self.env['slide.users'].sudo().search([
|
||||
('slide_id', 'in', self.ids)
|
||||
])
|
||||
for slide_user in slide_users:
|
||||
if slide_user.vote == 1:
|
||||
slide_data[slide_user.slide_id.id]['likes'] += 1
|
||||
if slide_user.user_id == self.env.user:
|
||||
slide_data[slide_user.slide_id.id]['user_vote'] = 1
|
||||
elif slide_user.vote == -1:
|
||||
slide_data[slide_user.slide_id.id]['dislikes'] += 1
|
||||
if slide_user.user_id == self.env.user:
|
||||
slide_data[slide_user.slide_id.id]['user_vote'] = -1
|
||||
for slide_sudo in self.sudo():
|
||||
slide_sudo.update(slide_data[slide_sudo.id])
|
||||
|
||||
embed_code = fields.Text('Embed Code', readonly=True, compute='_get_embed_code')
|
||||
|
||||
def _get_embed_code(self):
|
||||
@@ -305,6 +338,43 @@ class Slide(models.Model):
|
||||
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||
return self.channel_id.share_template_id.with_context(email=email, base_url=base_url).send_mail(self.id, notif_layout='mail.mail_notification_light')
|
||||
|
||||
def action_like(self):
|
||||
self.check_access_rights('read')
|
||||
self.check_access_rule('read')
|
||||
return self._action_vote(upvote=True)
|
||||
|
||||
def action_dislike(self):
|
||||
self.check_access_rights('read')
|
||||
self.check_access_rule('read')
|
||||
return self._action_vote(upvote=False)
|
||||
|
||||
def _action_vote(self, upvote=True):
|
||||
""" Private implementation of voting. It does not check for any real access
|
||||
rights; public methods should grant access before calling this method.
|
||||
|
||||
:param upvote: if True, is a like; if False, is a dislike
|
||||
"""
|
||||
self_sudo = self.sudo()
|
||||
SlideUsersSudo = self.env['slide.users'].sudo()
|
||||
slide_users = SlideUsersSudo.search([
|
||||
('slide_id', 'in', self.ids),
|
||||
('user_id', '=', self.env.uid)
|
||||
])
|
||||
new_slides = self_sudo - slide_users.mapped('slide_id')
|
||||
|
||||
for slide_user in slide_users:
|
||||
if upvote:
|
||||
new_vote = 0 if slide_user.vote == -1 else 1
|
||||
else:
|
||||
new_vote = 0 if slide_user.vote == 1 else -1
|
||||
slide_user.vote = new_vote
|
||||
|
||||
for new_slide in new_slides:
|
||||
new_vote = 1 if upvote else -1
|
||||
new_slide.write({
|
||||
'slide_user_ids': [(0, 0, {'vote': new_vote, 'user_id': self.env.uid})]
|
||||
})
|
||||
|
||||
# --------------------------------------------------
|
||||
# Parsing methods
|
||||
# --------------------------------------------------
|
||||
|
||||
@@ -2,6 +2,8 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_slide_slide_public,slide.slide.public,model_slide_slide,base.group_public,1,0,0,0
|
||||
access_slide_slide_portal,slide.slide.portal,model_slide_slide,base.group_portal,1,0,0,0
|
||||
access_slide_slide_user,slide.slide.user,model_slide_slide,base.group_user,1,1,1,1
|
||||
access_slide_users_all,slide.users.all,model_slide_users,,0,0,0,0
|
||||
access_slide_users_system,slide.users.system,model_slide_users,base.group_system,1,1,1,1
|
||||
access_slide_tag_public,slide.tag.public,model_slide_tag,base.group_public,1,0,0,0
|
||||
access_slide_tag_portal,slide.tag.portal,model_slide_tag,base.group_portal,1,0,0,0
|
||||
access_slide_tag_user,slide.tag.user,model_slide_tag,base.group_user,1,1,1,1
|
||||
|
||||
|
Reference in New Issue
Block a user