diff --git a/addons/website_slides/tests/__init__.py b/addons/website_slides/tests/__init__.py new file mode 100644 index 00000000000..bb7921266e3 --- /dev/null +++ b/addons/website_slides/tests/__init__.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import common +from . import test_security diff --git a/addons/website_slides/tests/common.py b/addons/website_slides/tests/common.py new file mode 100644 index 00000000000..5bf179cbdc8 --- /dev/null +++ b/addons/website_slides/tests/common.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from contextlib import contextmanager +from functools import partial + +from odoo.tests import common, new_test_user + +slides_new_test_user = partial(new_test_user, context={'mail_create_nolog': True, 'mail_create_nosubscribe': True, 'mail_notrack': True, 'no_reset_password': True}) + + +class SlidesCase(common.SavepointCase): + + def setUp(self): + super(SlidesCase, self).setUp() + + self.user_publisher = slides_new_test_user( + self.env, name='Paul Publisher', login='user_publisher', email='publisher@example.com', + groups='base.group_user,website.group_website_publisher' + ) + + self.user_emp = slides_new_test_user( + self.env, name='Eglantine Employee', login='user_emp', email='employee@example.com', + groups='base.group_user' + ) + + self.user_portal = slides_new_test_user( + self.env, name='Patrick Portal', login='user_portal', email='portal@example.com', + groups='base.group_portal' + ) + + self.user_public = slides_new_test_user( + self.env, name='Pauline Public', login='user_public', email='public@example.com', + groups='base.group_public' + ) + + self.customer = self.env['res.partner'].create({ + 'name': 'Caroline Customer', + 'email': 'customer@example.com', + 'customer': True, + }) + + self.channel = self.env['slide.channel'].sudo(self.user_publisher).create({ + 'name': 'Test Channel', + 'promote_strategy': 'most_voted', + 'visibility': 'public', + 'website_published': True, + }) + self.slide = self.env['slide.slide'].sudo(self.user_publisher).create({ + 'name': 'How To Cook Humans', + 'channel_id': self.channel.id, + 'slide_type': 'presentation', + 'website_published': True, + }) + + @contextmanager + def sudo(self, user): + """ Quick sudo environment """ + old_uid = self.uid + try: + self.uid = user.id + self.env = self.env(user=self.uid) + yield + finally: + # back + self.uid = old_uid + self.env = self.env(user=self.uid) diff --git a/addons/website_slides/tests/test_security.py b/addons/website_slides/tests/test_security.py new file mode 100644 index 00000000000..c73af1d932a --- /dev/null +++ b/addons/website_slides/tests/test_security.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.website_slides.tests import common +from odoo.exceptions import AccessError, UserError +from odoo.tests import tagged +from odoo.tests.common import users +from odoo.tools import mute_logger + + +@tagged('security') +class TestAccess(common.SlidesCase): + + @mute_logger('odoo.models') + def test_access_channel_invite(self): + """ Invite channels don't give visibility if not member """ + self.channel.write({'visibility': 'invite'}) + + self.channel.sudo(self.user_publisher).read(['name']) + self.channel.sudo(self.user_emp).read(['name']) + self.channel.sudo(self.user_portal).read(['name']) + self.channel.sudo(self.user_public).read(['name']) + + self.slide.sudo(self.user_publisher).read(['name']) + + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_portal).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_portal).read(['name']) + + # if member -> can read + membership = self.env['slide.channel.partner'].create({ + 'channel_id': self.channel.id, + 'state': 'confirmed', + 'partner_id': self.user_emp.partner_id.id, + }) + self.channel.sudo(self.user_emp).read(['name']) + self.slide.sudo(self.user_emp).read(['name']) + + # unvalidated member -> cannot read + membership.write({ + 'state': 'draft', + }) + self.channel.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + + # not member anymore -> cannot read + membership.unlink() + self.channel.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + + @mute_logger('odoo.models') + def test_access_channel_public(self): + """ Public channels don't give visibility if not member """ + self.channel.write({'visibility': 'public'}) + + self.channel.sudo(self.user_publisher).read(['name']) + self.channel.sudo(self.user_emp).read(['name']) + self.channel.sudo(self.user_portal).read(['name']) + self.channel.sudo(self.user_public).read(['name']) + + self.slide.sudo(self.user_publisher).read(['name']) + + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_portal).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_public).read(['name']) + + @mute_logger('odoo.models') + def test_access_channel_publish(self): + """ Unpublished channels and their content are visible only to website people """ + self.channel.write({'website_published': False, 'visibility': 'public'}) + + # channel available only to website + self.channel.sudo(self.user_publisher).read(['name']) + with self.assertRaises(AccessError): + self.channel.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.channel.sudo(self.user_portal).read(['name']) + with self.assertRaises(AccessError): + self.channel.sudo(self.user_public).read(['name']) + + # slide available only to website + self.slide.sudo(self.user_publisher).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_portal).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_public).read(['name']) + + # even members cannot see unpublished content + self.env['slide.channel.partner'].create({ + 'channel_id': self.channel.id, + 'state': 'confirmed', + 'partner_id': self.user_emp.partner_id.id, + }) + with self.assertRaises(AccessError): + self.channel.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + + # publish channel but content unpublished (even if can be previewed) still unavailable + self.channel.write({'website_published': True}) + self.slide.write({ + 'is_preview': True, + 'website_published': False, + }) + + self.slide.sudo(self.user_publisher).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_emp).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_portal).read(['name']) + with self.assertRaises(AccessError): + self.slide.sudo(self.user_public).read(['name']) + + @mute_logger('odoo.models') + def test_access_slide_preview(self): + """ Slides with preview flag are always visible even to non members if published """ + self.channel.write({'visibility': 'invite'}) + self.slide.write({'is_preview': True}) + + self.slide.sudo(self.user_publisher).read(['name']) + self.slide.sudo(self.user_emp).read(['name']) + self.slide.sudo(self.user_portal).read(['name']) + self.slide.sudo(self.user_public).read(['name'])