[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:
committed by
Thibault Delavallée
parent
691439ade5
commit
9c1f2f87ef
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user