[IMP] website_slides: allow to remove attendees

PURPOSE

Improve attendees management by adding a button to remove them in backend
of eLearning.

SPECIFCIATIONS

In order to easily remove a attendee from a channel, we add a button in
the slide_channel_partner tree view, accessible from channels (attendees).
Remove a slide_channel_partner implies to remove the related slide_slide_partner.
Also code backtracking for the view of attendees of a course: we redirect
to the slide.channel.partner model instead of res.parter because
we want the possibility to create/remove/edit attendees for a
course and not making action on res.partner model itself.

Task ID 2045620
This commit is contained in:
ryv-odoo
2019-08-12 15:40:36 +00:00
committed by Thibault Delavallée
parent 691439ade5
commit 9c1f2f87ef
4 changed files with 65 additions and 31 deletions
+23 -26
View File
@@ -6,7 +6,7 @@ import uuid
from odoo import api, fields, models, tools, _
from odoo.addons.http_routing.models.ir_http import slug
from odoo.addons.gamification.models.gamification_karma_rank import KarmaError
from odoo.exceptions import UserError
from odoo.exceptions import UserError, AccessError
from odoo.osv import expression
@@ -73,6 +73,23 @@ class ChannelUsersRelation(models.Model):
def _post_completion_hook(self):
pass
def unlink(self):
"""
Override unlink method :
Remove attendee from a channel, then also remove slide.slide.partner related to.
"""
removed_slide_partner_domain = []
for channel_partner in self:
# find all slide link to the channel and the partner
removed_slide_partner_domain = expression.OR([
removed_slide_partner_domain,
[('partner_id', '=', channel_partner.partner_id.id),
('slide_id', 'in', channel_partner.channel_id.slide_ids.ids)]
])
if removed_slide_partner_domain:
self.env['slide.slide.partner'].search(removed_slide_partner_domain).unlink()
return super(ChannelUsersRelation, self).unlink()
class Channel(models.Model):
""" A channel is a container of slides. """
@@ -384,23 +401,13 @@ class Channel(models.Model):
# ---------------------------------------------------------
def action_redirect_to_members(self, state=None):
action = self.env.ref('website_slides.res_partner_action_slide_channel').read()[0]
action['context'] = {'active_test': False}
if state == 'running':
action['domain'] = [('id', 'in', self.env['slide.channel.partner'].sudo().search([
('channel_id', 'in', self.ids),
('completed', '=', False)
]).mapped('partner_id').ids)]
elif state == 'completed':
action['domain'] = [('id', 'in', self.env['slide.channel.partner'].sudo().search([
('channel_id', 'in', self.ids),
('completed', '=', True)
]).mapped('partner_id').ids)]
else:
action['domain'] = [('id', 'in', self.mapped('partner_ids').ids)]
action = self.env.ref('website_slides.slide_channel_partner_action').read()[0]
action['domain'] = [('channel_id', 'in', self.ids)]
if len(self) == 1:
action['display_name'] = _('Attendees of %s') % self.name
action['context'] = {'active_test': False, 'default_channel_id': self.id}
if state:
action['domain'] += [('completed', '=', state == 'completed')]
return action
def action_redirect_to_running_members(self):
@@ -479,28 +486,18 @@ class Channel(models.Model):
def _remove_membership(self, partner_ids):
""" Unlink (!!!) the relationships between the passed partner_ids
and the channels and their slides. """
and the channels and their slides (done in the unlink of slide.channel.partner model). """
if not partner_ids:
raise ValueError("Do not use this method with an empty partner_id recordset")
removed_slide_partner_domain = []
removed_channel_partner_domain = []
for channel in self:
removed_slide_partner_domain = expression.OR([
removed_slide_partner_domain,
[('partner_id', 'in', partner_ids.ids),
('slide_id', 'in', channel.slide_ids.ids)]
])
removed_channel_partner_domain = expression.OR([
removed_channel_partner_domain,
[('partner_id', 'in', partner_ids.ids),
('channel_id', '=', channel.id)]
])
if removed_slide_partner_domain:
self.env['slide.slide.partner'].sudo().search(removed_slide_partner_domain).unlink()
if removed_channel_partner_domain:
self.env['slide.channel.partner'].sudo().search(removed_channel_partner_domain).unlink()
@@ -123,6 +123,40 @@ class TestAccess(common.SlidesCase):
self.slide.with_user(self.user_public).read(['name'])
@tagged('functional', 'security')
class TestRemoveMembership(common.SlidesCase):
def setUp(self):
super(TestRemoveMembership, self).setUp()
self.channel_partner = self.env['slide.channel.partner'].create({
'channel_id': self.channel.id,
'partner_id': self.customer.id,
})
self.slide_partner = self.env['slide.slide.partner'].create({
'slide_id': self.slide.id,
'channel_id': self.channel.id,
'partner_id': self.customer.id
})
def test_security_unlink(self):
# Only the publisher can unlink channel_partner (and slide_partner by extension)
with self.assertRaises(AccessError):
self.channel_partner.with_user(self.user_public).unlink()
with self.assertRaises(AccessError):
self.channel_partner.with_user(self.user_portal).unlink()
with self.assertRaises(AccessError):
self.channel_partner.with_user(self.user_emp).unlink()
def test_slide_partner_remove(self):
id_slide_partner = self.slide_partner.id
id_channel_partner = self.channel_partner.id
self.channel_partner.with_user(self.user_publisher).unlink()
self.assertFalse(self.env['slide.channel.partner'].search([('id', '=', '%d' % id_channel_partner)]))
# Slide(s) related to the channel and the partner is unlink too.
self.assertFalse(self.env['slide.slide.partner'].search([('id', '=', '%d' % id_slide_partner)]))
@tagged('functional')
class TestAccessFeatures(common.SlidesCase):
@@ -28,9 +28,4 @@
</field>
</record>
<record id="res_partner_action_slide_channel" model="ir.actions.act_window">
<field name="name">Attendees</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
</record>
</data></odoo>
@@ -29,8 +29,16 @@
<field name="partner_id" string="Contact"/>
<field name="partner_email"/>
<field name="channel_id" string="Channel" invisible="context.get('default_channel_id',False)" />
<button name="unlink" class="text-danger" string="Remove"
icon="fa-times-circle" type="object"/>
</tree>
</field>
</record>
<record id="slide_channel_partner_action" model="ir.actions.act_window">
<field name="name">Attendees</field>
<field name="res_model">slide.channel.partner</field>
<field name="view_mode">tree,form</field>
</record>
</data>
</odoo>