diff --git a/addons/website_slides/models/slide_channel.py b/addons/website_slides/models/slide_channel.py
index 626edb66c31..a740d8a2ac9 100644
--- a/addons/website_slides/models/slide_channel.py
+++ b/addons/website_slides/models/slide_channel.py
@@ -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()
diff --git a/addons/website_slides/tests/test_security.py b/addons/website_slides/tests/test_security.py
index b1e6a979a9d..0ac21ba813d 100644
--- a/addons/website_slides/tests/test_security.py
+++ b/addons/website_slides/tests/test_security.py
@@ -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):
diff --git a/addons/website_slides/views/res_partner_views.xml b/addons/website_slides/views/res_partner_views.xml
index 8a202cb0311..4f4f9d3c425 100644
--- a/addons/website_slides/views/res_partner_views.xml
+++ b/addons/website_slides/views/res_partner_views.xml
@@ -28,9 +28,4 @@
-
- Attendees
- res.partner
- kanban,tree,form
-
diff --git a/addons/website_slides/views/slide_channel_partner_views.xml b/addons/website_slides/views/slide_channel_partner_views.xml
index fb5901d15da..05720fcfb03 100644
--- a/addons/website_slides/views/slide_channel_partner_views.xml
+++ b/addons/website_slides/views/slide_channel_partner_views.xml
@@ -29,8 +29,16 @@
+
+
+
+ Attendees
+ slide.channel.partner
+ tree,form
+