[IMP] website_slides: update course visibility

before this commit,
the wording of the visibility options can be quite confusing.

after this commit,
- Visibility has been updated
	- Visible to all: I see those training to the public
	- Visible to logged users only: I am a B2B business, and I do not want the
          public to see what I offer + the pricing I have on those
	- Visible to members only: I am a school, I want to invite my students but
          external visitors should not be able to enroll
- Move the field above the "enroll policy"
- Enroll Policy has been set to invite when visibility is set as a Course
  attendee  and hide the enroll policy

task- 2862003

closes odoo/odoo#102085

Related: odoo/upgrade#3946
Signed-off-by: Stéphane Debauche (std) <std@odoo.com>
This commit is contained in:
Nikunj Ladava
2023-02-03 11:45:30 +01:00
committed by Sahil Patel
parent d9548b6681
commit df09c5c20f
11 changed files with 279 additions and 27 deletions
@@ -12,6 +12,18 @@
<field name="image_1920" type="base64" file="website_sale_slides/static/img/channel_demo_tree_1.jpg"/>
</record>
<!-- CHANNEL 5: Basics of Furniture Creation -->
<!-- ================================================== -->
<record id="product_course_channel_5" model="product.product">
<field name="name">Basics of Furniture Creation</field>
<field name="standard_price">200.0</field>
<field name="list_price">200.0</field>
<field name="detailed_type">course</field>
<field name="invoice_policy">order</field>
<field name="is_published" eval="True"/>
<field name="image_1920" type="base64" file="website_sale_slides/static/img/channel_demo_furniture_2.jpg"/>
</record>
<!-- CHANNEL 6: DIY Furniture -->
<!-- ================================================== -->
<record id="product_course_channel_6" model="product.product">
@@ -53,6 +53,29 @@
<field name="price_unit">100.0</field>
</record>
<!-- CHANNEL 5: Basics of Furniture Creation -->
<!-- ================================================== -->
<record id="sale_order_course_3" model="sale.order">
<field name="create_date" eval="DateTime.now() - relativedelta(days=31)"/>
<field name="partner_id" ref="base.partner_demo"/>
<field name="partner_invoice_id" ref="base.partner_demo"/>
<field name="partner_shipping_id" ref="base.partner_demo"/>
<field name="user_id" ref="base.user_admin"/>
<field name="date_order" eval="DateTime.now() - relativedelta(days=30)"/>
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
<field name="website_id" eval="1"/>
<field name="state">sale</field>
</record>
<record id="sale_order_course_3_line_1" model="sale.order.line">
<field name="order_id" ref="sale_order_course_3"/>
<field name="name" model="sale.order.line" eval="obj().env.ref('website_sale_slides.product_course_channel_5').get_product_multiline_description_sale()"/>
<field name="product_id" ref="website_sale_slides.product_course_channel_5"/>
<field name="product_uom_qty">1</field>
<field name="product_uom" ref="uom.product_uom_unit"/>
<field name="price_unit">200.0</field>
</record>
<record id="website_sale_slides_activity_1" model="mail.activity">
<field name="res_id" ref="website_sale_slides.sale_order_course_1"/>
<field name="res_model_id" ref="sale.model_sale_order"/>
@@ -75,4 +98,5 @@
<!-- Confirm sales -->
<function model="sale.order" name="action_confirm" eval="[[ref('sale_order_course_1')]]"/>
<function model="sale.order" name="action_confirm" eval="[[ref('sale_order_course_2')]]"/>
<function model="sale.order" name="action_confirm" eval="[[ref('sale_order_course_3')]]"/>
</data></odoo>
@@ -7,6 +7,13 @@
<field name="product_id" ref="product_course_channel_1"/>
</record>
<!-- CHANNEL 5: Basics of Furniture Creation -->
<!-- ================================================== -->
<record id="website_slides.slide_channel_demo_5_furn2" model="slide.channel">
<field name="enroll">payment</field>
<field name="product_id" ref="product_course_channel_5"/>
</record>
<!-- CHANNEL 6: DIY Furniture -->
<!-- ================================================== -->
<record id="website_slides.slide_channel_demo_6_furn3" model="slide.channel">
Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

@@ -99,6 +99,7 @@ will learn the basics of wood characteristics.</field>
<field name="name">Basics of Furniture Creation</field>
<field name="user_id" ref="base.user_admin"/>
<field name="enroll">invite</field>
<field name="visibility">connected</field>
<field name="channel_type">training</field>
<field name="allow_comment" eval="True"/>
<field name="promote_strategy">latest</field>
+18 -3
View File
@@ -287,7 +287,8 @@ class Channel(models.Model):
default=lambda self: self.env['ir.model.data']._xmlid_to_res_id('website_slides.mail_template_channel_completed'),
domain=[('model', '=', 'slide.channel.partner')])
enroll = fields.Selection([
('public', 'Public'), ('invite', 'On Invitation')],
('public', 'Open'), ('invite', 'On Invitation')],
compute='_compute_enroll', store=True, readonly=False,
default='public', string='Enroll Policy', required=True,
help='Defines how people can enroll to your Course.', copy=False)
enroll_msg = fields.Html(
@@ -295,8 +296,10 @@ class Channel(models.Model):
default=_get_default_enroll_msg, translate=tools.html_translate, sanitize_attributes=False)
enroll_group_ids = fields.Many2many('res.groups', string='Auto Enroll Groups', help="Members of those groups are automatically added as members of the channel.")
visibility = fields.Selection([
('public', 'Open To All'), ('members', 'Members Only')],
default='public', string='Visibility', required=True,
('public', 'Everyone'),
('connected', 'Signed In'),
('members', 'Course Attendees')
], default='public', string='Show Course To', required=True,
help='Defines who can access your courses and their content.')
partner_ids = fields.Many2many(
'res.partner', 'slide_channel_partner', 'channel_id', 'partner_id',
@@ -327,6 +330,18 @@ class Channel(models.Model):
can_comment = fields.Boolean('Can Comment', compute='_compute_action_rights', compute_sudo=False)
can_vote = fields.Boolean('Can Vote', compute='_compute_action_rights', compute_sudo=False)
_sql_constraints = [
(
"check_enroll",
"CHECK(visibility != 'members' OR enroll = 'invite')",
"The Enroll Policy should be set to 'On Invitation' when visibility is set to 'Course Attendees'"
),
]
@api.depends('visibility')
def _compute_enroll(self):
self.filtered(lambda channel: channel.visibility == 'members').enroll = 'invite'
@api.depends('slide_ids.is_published')
def _compute_slide_last_update(self):
for record in self:
@@ -29,11 +29,29 @@
<field name="domain_force">[(1, '=', 1)]</field>
</record>
<record id="rule_slide_channel_not_website" model="ir.rule">
<field name="name">Channel: public/portal/user: restricted to published and (public or member only)</field>
<record id="rule_slide_channel_visibility_public_user" model="ir.rule">
<field name="name">Channel: public: restricted to public and published</field>
<field name="model_id" ref="model_slide_channel"/>
<field name="groups" eval="[(4, ref('base.group_public')), (4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">['&amp;', ('website_published', '=', True), '|', ('visibility', '=', 'public'), ('partner_ids', '=', user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="domain_force">[('website_published', '=', True), ('visibility', '=', 'public')]</field>
<field name="perm_unlink" eval="0"/>
<field name="perm_write" eval="0"/>
<field name="perm_read" eval="1"/>
<field name="perm_create" eval="0"/>
</record>
<record id="rule_slide_channel_visibility_signed_in_user" model="ir.rule">
<field name="name">Channel: portal/user: restricted to published, public or connected User</field>
<field name="model_id" ref="model_slide_channel"/>
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">[
'&amp;',
('website_published', '=', True),
'|',
('visibility', 'in', ('public', 'connected')),
('partner_ids', '=', user.partner_id.id),
]
</field>
<field name="perm_unlink" eval="0"/>
<field name="perm_write" eval="0"/>
<field name="perm_read" eval="1"/>
@@ -90,15 +108,45 @@
<field name="domain_force">[(1, '=', 1)]</field>
</record>
<record id="rule_slide_slide_not_website" model="ir.rule">
<field name="name">Slide: public/portal/user: restricted to published or uploaded by user, and either channel member or public channel &amp; (category or previewable)</field>
<record id="rule_slide_slide_public_user" model="ir.rule">
<field name="name">Slide: public: restricted to published or public channel &amp; (category or previewable)</field>
<field name="model_id" ref="model_slide_slide"/>
<field name="groups" eval="[(4, ref('base.group_public')), (4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">['&amp;',
'|',
'&amp;', ('channel_id.visibility', '=', 'public'), '|', ('is_category','=', True), ('is_preview', '=', True),
('channel_id.partner_ids', '=', user.partner_id.id),
'&amp;', ('channel_id.website_published', '=', True), '|', ('user_id', '=', user.id), ('website_published', '=', True)]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
<field name="domain_force">[
('channel_id.website_published', '=', True),
('website_published', '=', True),
('channel_id.visibility', '=', 'public'),
'|',
('is_category','=', True),
('is_preview', '=', True),
]
</field>
<field name="perm_unlink" eval="0"/>
<field name="perm_write" eval="0"/>
<field name="perm_read" eval="1"/>
<field name="perm_create" eval="0"/>
</record>
<record id="rule_slide_slide_signed_in_user" model="ir.rule">
<field name="name">Slide: portal/user: restricted to published and connected user</field>
<field name="model_id" ref="model_slide_slide"/>
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">[
'&amp;',
'|',
('user_id', '=', user.id),
'&amp;',
('website_published', '=', True),
('channel_id.website_published', '=', True),
'|',
'&amp;',
('channel_id.visibility', 'in', ('public','connected')),
'|',
('is_category', '=', True),
('is_preview', '=', True),
('channel_id.partner_ids', 'in', user.partner_id.ids),
]
</field>
<field name="perm_unlink" eval="0"/>
<field name="perm_write" eval="0"/>
<field name="perm_read" eval="1"/>
@@ -152,6 +152,95 @@ class TestAccess(common.SlidesCase):
self.slide.with_user(self.user_portal).read(['name'])
self.slide.with_user(self.user_public).read(['name'])
@mute_logger('odoo.models', 'odoo.addons.base.models.ir_rule')
def test_access_channel_visibility_public(self):
self.channel.write({'visibility': 'public'})
self.slide.write({'is_preview': True})
self.slide.flush_model()
self.channel.with_user(self.user_officer).read(['name'])
self.channel.with_user(self.user_manager).read(['name'])
self.channel.with_user(self.user_emp).read(['name'])
self.channel.with_user(self.user_portal).read(['name'])
self.channel.with_user(self.user_public).read(['name'])
self.slide.with_user(self.user_officer).read(['name'])
self.slide.with_user(self.user_manager).read(['name'])
self.slide.with_user(self.user_emp).read(['name'])
self.slide.with_user(self.user_portal).read(['name'])
self.slide.with_user(self.user_public).read(['name'])
@mute_logger('odoo.models', 'odoo.addons.base.models.ir_rule')
def test_access_channel_public_with_website_published(self):
self.channel.write({'visibility': 'public', 'website_published': False})
self.channel.with_user(self.user_officer).read(['name'])
self.channel.with_user(self.user_manager).read(['name'])
with self.assertRaises(AccessError):
self.channel.with_user(self.user_emp).read(['name'])
with self.assertRaises(AccessError):
self.channel.with_user(self.user_portal).read(['name'])
with self.assertRaises(AccessError):
self.channel.with_user(self.user_public).read(['name'])
self.slide.with_user(self.user_officer).read(['name'])
self.slide.with_user(self.user_manager).read(['name'])
with self.assertRaises(AccessError):
self.slide.with_user(self.user_emp).read(['name'])
with self.assertRaises(AccessError):
self.slide.with_user(self.user_portal).read(['name'])
with self.assertRaises(AccessError):
self.slide.with_user(self.user_public).read(['name'])
@mute_logger('odoo.models', 'odoo.addons.base.models.ir_rule')
def test_access_channel_visibility_members(self):
self.channel.write({'visibility': 'members'})
self.channel.flush_model()
user_emp_membership = self.env['slide.channel.partner'].create({
'channel_id': self.channel.id,
'partner_id': self.user_emp.partner_id.id,
})
self.channel.with_user(self.user_emp).read(['name'])
with self.assertRaises(AccessError):
self.channel.with_user(self.user_portal).read(['name'])
user_emp_membership.unlink()
with self.assertRaises(AccessError):
self.channel.with_user(self.user_emp).read(['name'])
@mute_logger('odoo.models', 'odoo.addons.base.models.ir_rule')
def test_access_channel_members_with_website_published(self):
self.channel.write({'visibility': 'members', 'website_published': False})
self.channel.flush_model()
with self.assertRaises(AccessError):
self.channel.with_user(self.user_emp).read(['name'])
with self.assertRaises(AccessError):
self.channel.with_user(self.user_portal).read(['name'])
@mute_logger('odoo.models', 'odoo.addons.base.models.ir_rule')
def test_access_channel_visibility_connected(self):
self.channel.write({'visibility': 'connected'})
self.channel.with_user(self.user_officer).read(['name'])
self.channel.with_user(self.user_manager).read(['name'])
self.channel.with_user(self.user_emp).read(['name'])
self.channel.with_user(self.user_portal).read(['name'])
with self.assertRaises(AccessError):
self.channel.with_user(self.user_public).read(['name'])
self.slide.with_user(self.user_officer).read(['name'])
self.slide.with_user(self.user_manager).read(['name'])
with self.assertRaises(AccessError):
self.slide.with_user(self.user_emp).read(['name'])
with self.assertRaises(AccessError):
self.slide.with_user(self.user_portal).read(['name'])
with self.assertRaises(AccessError):
self.slide.with_user(self.user_public).read(['name'])
@tagged('functional', 'security')
class TestRemoveMembership(common.SlidesCase):
@@ -220,3 +220,20 @@ class TestSequencing(slides_common.SlidesCase):
self.assertEqual(self.category.sequence, 4)
self.assertEqual(self.slide_2.sequence, 5)
self.assertEqual([s.id for s in self.channel.slide_ids], [self.slide.id, new_category.id, self.slide_3.id, self.category.id, self.slide_2.id])
@users('user_officer')
def test_channel_enroll_policy(self):
channel = self.env['slide.channel'].create({
'name': 'Test Course 2',
'slide_ids': [(0, 0, {
'name': 'Test Slide 1'
})],
})
self.assertEqual(channel.visibility, 'public')
self.assertEqual(channel.enroll, 'public')
channel.write({'visibility': 'members'})
self.assertEqual(channel.visibility, 'members')
self.assertEqual(channel.enroll, 'invite')
@@ -100,7 +100,8 @@
<field name="website_id" options="{'no_create': True}" groups="website.group_multi_website"/>
</group>
<group name="access_rights" string="Access Rights">
<field name="enroll" widget="radio" options="{'horizontal': true}"/>
<field name="visibility" widget="radio" options="{'horizontal': true}"/>
<field name="enroll" widget="radio" options="{'horizontal': true}" attrs="{'invisible': [('visibility', '=', 'course_attendees')]}"/>
<field name="upload_group_ids" widget="many2many_tags" groups="base.group_no_one"/>
<field name="enroll_group_ids" widget="many2many_tags" groups="base.group_no_one"/>
<field name="enroll_msg" attrs="{'invisible': [('enroll', '!=', 'invite')]}"/>
@@ -116,7 +117,6 @@
</group>
<group name="display" string="Display">
<field string="Type" name="channel_type" widget="radio" options="{'horizontal': true}"/>
<field name="visibility" widget="radio" options="{'horizontal': true}"/>
<field name="promote_strategy" widget="selection"
attrs="{'invisible': [('channel_type', '=', 'training')]}"/>
<field name="promoted_slide_id"
@@ -162,8 +162,8 @@
<field name="user_id" widget="many2one_avatar_user"/>
<field name="website_id" groups="website.group_multi_website"/>
<field name="channel_type" string="Course Type"/>
<field name="visibility" optional="hide"/>
<field name="enroll" widget="badge" decoration-success="enroll == 'public'" decoration-info="enroll == 'invite'" decoration-warning="enroll == 'payment'"/>
<field name="visibility"/>
<field name="enroll" widget="badge" decoration-success="enroll == 'public'" decoration-info="enroll == 'invite'" decoration-warning="enroll == 'payment'" optional="hide"/>
<field name="active" invisible="1"/>
</tree>
</field>
@@ -1,10 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<record id="website_slides_forum_public" model="ir.rule">
<field name="name">Website forum: User can only access to forum related to followed courses</field>
<field name="name">Website forum: User can only access to forum related to public courses</field>
<field name="model_id" ref="website_forum.model_forum_forum"/>
<field name="domain_force">['&amp;', ('slide_channel_ids.website_published', '=', True), '|', ('slide_channel_ids.visibility', '=', 'public'), ('slide_channel_ids.partner_ids', 'in', user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('base.group_public')), (4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">[('slide_channel_ids.website_published', '=', True), ('slide_channel_ids.visibility', '=', 'public')]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
</record>
<record id="website_slides_forum_signed_in_user" model="ir.rule">
<field name="name">Website forum: Signed In user can only access to forum related to courses</field>
<field name="model_id" ref="website_forum.model_forum_forum"/>
<field name="domain_force">[
'&amp;',
('slide_channel_ids.website_published', '=', True),
'|',
('slide_channel_ids.visibility', 'in', ('public','connected')),
('slide_channel_ids.partner_ids', 'in', user.partner_id.id)
]
</field>
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
</record>
<record id="website_slides_forum_website_slides_officer" model="ir.rule">
<field name="name">Website forum: website slides officer can access all forum</field>
@@ -16,8 +29,21 @@
<record id="website_slides_forum_public_post" model="ir.rule">
<field name="name">Website forum post: User can only access to post linked to forum related to followed courses</field>
<field name="model_id" ref="website_forum.model_forum_post"/>
<field name="domain_force">['&amp;', ('forum_id.slide_channel_ids.website_published', '=', True), '|', ('forum_id.slide_channel_ids.visibility', '=', 'public'), ('forum_id.slide_channel_ids.partner_ids', 'in', user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('base.group_public')), (4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">[('forum_id.slide_channel_ids.website_published', '=', True), ('forum_id.slide_channel_ids.visibility', '=', 'public')]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
</record>
<record id="website_slides_forum_post_signed_in_user" model="ir.rule">
<field name="name">Website forum: Signed In user can only access to post linked to forum related to courses</field>
<field name="model_id" ref="website_forum.model_forum_post"/>
<field name="domain_force">[
'&amp;',
('forum_id.slide_channel_ids.website_published', '=', True),
'|',
('forum_id.slide_channel_ids.visibility', 'in', ('public','connected')),
('forum_id.slide_channel_ids.partner_ids', 'in', user.partner_id.id)
]
</field>
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
</record>
<record id="website_slides_forum_website_slides_officer_post" model="ir.rule">
<field name="name">Website forum post: website slides officer can access all post</field>
@@ -27,10 +53,23 @@
</record>
<record id="website_slides_forum_public_tag" model="ir.rule">
<field name="name">Website slides forum tag: User can only access to tag linked to forum related to followed courses</field>
<field name="name">Website slides forum tag: Public User can only access to tag linked to forum related to public courses</field>
<field name="model_id" ref="website_forum.model_forum_tag"/>
<field name="domain_force">['&amp;', ('forum_id.slide_channel_ids.website_published', '=', True), '|', ('forum_id.slide_channel_ids.visibility', '=', 'public'), ('forum_id.slide_channel_ids.partner_ids', 'in', user.partner_id.id)]</field>
<field name="groups" eval="[(4, ref('base.group_public')), (4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
<field name="domain_force">[('forum_id.slide_channel_ids.website_published', '=', True), ('forum_id.slide_channel_ids.visibility', '=', 'public')]</field>
<field name="groups" eval="[(4, ref('base.group_public'))]"/>
</record>
<record id="website_slides_forum_tag_signed_in_user" model="ir.rule">
<field name="name">Website forum: Signed In users can access tags linked to public or connected users-visibility courses</field>
<field name="model_id" ref="website_forum.model_forum_tag"/>
<field name="domain_force">[
'&amp;',
('forum_id.slide_channel_ids.website_published', '=', True),
'|',
('forum_id.slide_channel_ids.visibility', 'in', ('public','connected')),
('forum_id.slide_channel_ids.partner_ids', 'in', user.partner_id.id)
]
</field>
<field name="groups" eval="[(4, ref('base.group_portal')), (4, ref('base.group_user'))]"/>
</record>
<record id="website_slides_forum_website_slides_officer_tag" model="ir.rule">
<field name="name">Website slides forum tag: website slides officer can access all tag</field>