[MERGE] website_event_*: always link event menus to website.event.menu records and clean tests

In website_event some event-specific frontend menus are not linked to
``website.event.menu`` like track or exhibitor sub-modules menus. This
comes from initial implementation of ``website.event.menu`` that was
available only for ``website_event_track``.

Using ``website.event.menu`` eases menu management as it allows to have
an object making a link between the event and the website menu. Notably
when checking / unchecking in backend submenus it eases management.
It also eases management when people manually edit menus from frontend
as otherwise we have to manually manage ``ir.ui.view`` based on some
naming manipulation.

Task ID-2577079

closes odoo/odoo#72411

Related: odoo/enterprise#19484
Related: odoo/upgrade#2573
Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Odoo's Mergebot
2021-07-07 13:16:03 +02:00
committed by GitHub
24 changed files with 416 additions and 397 deletions
+5 -3
View File
@@ -573,7 +573,7 @@ class Website(models.Model):
page_url = '/' + slugify(name, max_length=1024, path=True)
page_url = self.get_unique_path(page_url)
page_key = slugify(name)
result = dict({'url': page_url, 'view_id': False})
result = {'url': page_url}
if not name:
name = 'Home'
@@ -588,6 +588,7 @@ class Website(models.Model):
'arch': template_record.arch.replace(template, key),
'name': name,
})
result['view_id'] = view.id
if view.arch_fs:
view.arch_fs = False
@@ -600,15 +601,16 @@ class Website(models.Model):
'view_id': view.id,
'track': True,
})
result['view_id'] = view.id
result['page_id'] = page.id
if add_menu:
self.env['website.menu'].create({
menu = self.env['website.menu'].create({
'name': name,
'url': page_url,
'parent_id': website.menu_id.id,
'page_id': page.id,
'website_id': website.id,
})
result['menu_id'] = menu.id
return result
@api.model
+1 -1
View File
@@ -3,7 +3,7 @@
{
'name': 'Events',
'version': '1.3',
'version': '1.4',
'category': 'Marketing/Events',
'sequence': 140,
'summary': 'Publish events, sell tickets',
+79 -41
View File
@@ -36,12 +36,30 @@ class Event(models.Model):
website_menu = fields.Boolean(
string='Website Menu',
compute='_compute_website_menu', readonly=False, store=True,
help="Creates menus Introduction, Location and Register on the page "
"of the event on the website.")
help="Allows to display and manage event-specific menus on website.")
menu_id = fields.Many2one('website.menu', 'Event Menu', copy=False)
menu_register_cta = fields.Boolean(
'Extra Register Button', compute='_compute_menu_register_cta',
readonly=False, store=True)
# sub-menus management
introduction_menu = fields.Boolean(
"Introduction Menu", compute="_compute_website_menu_data",
readonly=False, store=True)
introduction_menu_ids = fields.One2many(
"website.event.menu", "event_id", string="Introduction Menus",
domain=[("menu_type", "=", "introduction")])
location_menu = fields.Boolean(
"Location Menu", compute="_compute_website_menu_data",
readonly=False, store=True)
location_menu_ids = fields.One2many(
"website.event.menu", "event_id", string="Location Menus",
domain=[("menu_type", "=", "location_menu")])
register_menu = fields.Boolean(
"Register Menu", compute="_compute_website_menu_data",
readonly=False, store=True)
register_menu_ids = fields.One2many(
"website.event.menu", "event_id", string="Register Menus",
domain=[("menu_type", "=", "register")])
community_menu = fields.Boolean(
"Community Menu", compute="_compute_community_menu",
readonly=False, store=True,
@@ -120,6 +138,15 @@ class Event(models.Model):
for event in self:
event.community_menu = False
@api.depends("website_menu")
def _compute_website_menu_data(self):
""" Synchronize with website_menu at change and let people update them
at will afterwards. """
for event in self:
event.introduction_menu = event.website_menu
event.location_menu = event.website_menu
event.register_menu = event.website_menu
@api.depends("event_type_id", "website_menu")
def _compute_menu_register_cta(self):
""" At type onchange: synchronize. At website_menu update: synchronize. """
@@ -186,10 +213,15 @@ class Event(models.Model):
:return list: list of fields, each of which triggering a menu update
like website_menu, website_track, ... """
return ['website_menu', 'community_menu']
return ['community_menu', 'introduction_menu', 'location_menu', 'register_menu']
def _get_menu_type_field_matching(self):
return {'community': 'community_menu'}
return {
'community': 'community_menu',
'introduction': 'introduction_menu',
'location': 'location_menu',
'register': 'register_menu',
}
def _split_menus_state_by_field(self):
""" For each field linked to a menu, get the set of events having this
@@ -248,15 +280,12 @@ class Event(models.Model):
"""
self.ensure_one()
return [
(_('Introduction'), False, 'website_event.template_intro', 1, False),
(_('Location'), False, 'website_event.template_location', 50, False),
(_('Register'), '/event/%s/register' % slug(self), False, 100, False),
(_('Introduction'), False, 'website_event.template_intro', 1, 'introduction'),
(_('Location'), False, 'website_event.template_location', 50, 'location'),
(_('Register'), '/event/%s/register' % slug(self), False, 100, 'register'),
(_('Community'), '/event/%s/community' % slug(self), False, 80, 'community'),
]
def _get_community_menu_entries(self):
self.ensure_one()
return [(_('Community'), '/event/%s/community' % slug(self), False, 80, 'community')]
def _update_website_menus(self, menus_update_by_field=None):
""" Synchronize event configuration and its menu entries for frontend.
@@ -267,13 +296,16 @@ class Event(models.Model):
elif event.website_menu and not event.menu_id:
root_menu = self.env['website.menu'].sudo().create({'name': event.name, 'website_id': event.website_id.id})
event.menu_id = root_menu
if event.website_menu and (not menus_update_by_field or event in menus_update_by_field.get('website_menu')):
for name, url, xml_id, menu_sequence, menu_type in event._get_website_menu_entries():
event._create_menu(menu_sequence, name, url, xml_id, menu_type=menu_type)
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('community_menu')):
event._update_website_menu_entry('community_menu', 'community_menu_ids', '_get_community_menu_entries')
event._update_website_menu_entry('community_menu', 'community_menu_ids', 'community')
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('introduction_menu')):
event._update_website_menu_entry('introduction_menu', 'introduction_menu_ids', 'introduction')
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('location_menu')):
event._update_website_menu_entry('location_menu', 'location_menu_ids', 'location')
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('register_menu')):
event._update_website_menu_entry('register_menu', 'register_menu_ids', 'register')
def _update_website_menu_entry(self, fname_bool, fname_o2m, method_name):
def _update_website_menu_entry(self, fname_bool, fname_o2m, fmenu_type):
""" Generic method to create menu entries based on a flag on event. This
method is a bit obscure, but is due to preparation of adding new menus
entries and pages for event in a stable version, leading to some constraints
@@ -288,38 +320,44 @@ class Event(models.Model):
self.ensure_one()
new_menu = None
menu_data = [menu_info for menu_info in self._get_website_menu_entries()
if menu_info[4] == fmenu_type]
if self[fname_bool] and not self[fname_o2m]:
# menus not found but boolean True: get menus to create
for sequence, menu_data in enumerate(getattr(self, method_name)()):
# some modules have 4 data: name, url, xml_id, menu_type; however we
# plan to support sequence in future modules, so this hackish code is
# necessary to avoid crashing. Not nice, but stable target = meh.
if len(menu_data) == 4:
(name, url, xml_id, menu_type) = menu_data
menu_sequence = sequence
elif len(menu_data) == 5:
(name, url, xml_id, menu_sequence, menu_type) = menu_data
new_menu = self._create_menu(menu_sequence, name, url, xml_id, menu_type=menu_type)
for name, url, xml_id, menu_sequence, menu_type in menu_data:
new_menu = self._create_menu(menu_sequence, name, url, xml_id, menu_type)
elif not self[fname_bool]:
# will cascade delete to the website.event.menu
self[fname_o2m].mapped('menu_id').sudo().unlink()
return new_menu
def _create_menu(self, sequence, name, url, xml_id, menu_type=False):
""" If url: create a website menu. Menu leads directly to the URL that
should be a valid route. If xml_id: create a new page, take its url back
thanks to new_page of website, then link it to a menu. Template is
duplicated and linked to a new url, meaning each menu will have its own
copy of the template.
def _create_menu(self, sequence, name, url, xml_id, menu_type):
""" Create a new menu for the current event.
If url: create a website menu. Menu leads directly to the URL that
should be a valid route.
If xml_id: create a new page using the qweb template given by its
xml_id. Take its url back thanks to new_page of website, then link
it to a menu. Template is duplicated and linked to a new url, meaning
each menu will have its own copy of the template. This is currently
limited to two menus: introduction and location.
:param menu_type: type of menu. Mainly used for inheritance purpose
allowing more fine-grain tuning of menus. """
allowing more fine-grain tuning of menus.
"""
self.check_access_rights('write')
view_id = False
if not url:
self.env['ir.ui.view'].with_context(_force_unlink=True).sudo().search([('name', '=', name + ' ' + self.name)]).unlink()
page_result = self.env['website'].sudo().new_page(name + ' ' + self.name, template=xml_id, ispage=False)
# add_menu=False, ispage=False -> simply create a new ir.ui.view with name
# and template
page_result = self.env['website'].sudo().new_page(
name=name + ' ' + self.name, template=xml_id,
add_menu=False, ispage=False)
url = "/event/" + slug(self) + "/page" + page_result['url'] # url contains starting "/"
view_id = page_result['view_id']
website_menu = self.env['website.menu'].sudo().create({
'name': name,
'url': url,
@@ -327,12 +365,12 @@ class Event(models.Model):
'sequence': sequence,
'website_id': self.website_id.id,
})
if menu_type:
self.env['website.event.menu'].create({
'menu_id': website_menu.id,
'event_id': self.id,
'menu_type': menu_type,
})
self.env['website.event.menu'].create({
'menu_id': website_menu.id,
'event_id': self.id,
'menu_type': menu_type,
'view_id': view_id,
})
return website_menu
# ------------------------------------------------------------
@@ -10,6 +10,14 @@ class EventMenu(models.Model):
menu_id = fields.Many2one('website.menu', string='Menu', ondelete='cascade')
event_id = fields.Many2one('event.event', string='Event', ondelete='cascade')
menu_type = fields.Selection([
('community', 'Community Menu')], string="Menu Type",
ondelete={'community': 'cascade'}, required=True)
view_id = fields.Many2one('ir.ui.view', string='View', ondelete='cascade', help='Used when not being an url based menu')
menu_type = fields.Selection(
[('community', 'Community Menu'),
('introduction', 'Introduction'),
('location', 'Location'),
('register', 'Register'),
], string="Menu Type", required=True)
def unlink(self):
self.view_id.sudo().unlink()
return super(EventMenu, self).unlink()
+4 -3
View File
@@ -8,8 +8,7 @@ class WebsiteMenu(models.Model):
_inherit = "website.menu"
def unlink(self):
""" Override to synchronize event configuration fields with menu deletion.
This should be cleaned in upcoming versions. """
""" Override to synchronize event configuration fields with menu deletion. """
event_updates = {}
website_event_menus = self.env['website.event.menu'].search([('menu_id', 'in', self.ids)])
for event_menu in website_event_menus:
@@ -18,7 +17,9 @@ class WebsiteMenu(models.Model):
if event_menu.menu_type == menu_type:
to_update.append(fname)
# call super that resumes the unlink of menus entries (including website event menus)
# manually remove website_event_menus to call their ``unlink`` method. Otherwise
# super unlinks at db level and skip model-specific behavior.
website_event_menus.unlink()
res = super(WebsiteMenu, self).unlink()
# update events
+2 -5
View File
@@ -1,9 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import common
from . import test_event_internals
from . import test_ui
from . import test_visitor_events
from . import test_event_menus
from . import test_event_visitor
from . import test_website_event
from . import test_website_event_access
+11 -11
View File
@@ -73,28 +73,28 @@ class TestWebsiteEventCommon(TestEventCommon):
)
def _get_menus(self):
return set(['Introduction', 'Location', 'Register'])
return set(['Introduction', 'Location', 'Register', 'Community'])
def _assert_website_menus(self, event, menu_entries=None):
def _assert_website_menus(self, event, menus_in=None, menus_out=None):
self.assertTrue(event.menu_id)
if menu_entries is None:
menu_entries = self._get_menus()
if menus_in is None:
menus_in = list(self._get_menus())
menus = self.env['website.menu'].search([('parent_id', '=', event.menu_id.id)])
self.assertEqual(len(menus), len(menu_entries))
self.assertEqual(set(menus.mapped('name')), menu_entries)
self.assertTrue(len(menus) >= len(menus_in))
self.assertTrue(all(menu_name in menus.mapped('name') for menu_name in menus_in))
if menus_out:
self.assertTrue(all(menu_name not in menus.mapped('name') for menu_name in menus_out))
for page_specific in ['Introduction', 'Location']:
view = self.env['ir.ui.view'].search(
[('name', '=', page_specific + ' ' + event.name)]
)
if page_specific in menu_entries:
if page_specific in menus_in:
self.assertTrue(bool(view))
# TDE FIXME: page deletion not done in 13.3 for Introduction/Location, difficult to fix
# without website.event.menu model (or crappy code based on name)
# else:
# self.assertFalse(bool(view))
else:
self.assertFalse(bool(view))
class TestEventOnlineCommon(TestEventCommon, EventDtPatcher):
@@ -1,47 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from odoo import fields
from odoo.addons.website_event.tests.common import TestWebsiteEventCommon
from odoo.tests.common import users
class TestEventWebsite(TestWebsiteEventCommon):
@users('user_eventmanager')
def test_menu_create(self):
event = self.env['event.event'].create({
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
'community_menu': False,
})
self._assert_website_menus(event)
@users('user_event_web_manager')
def test_menu_management_frontend(self):
event = self.env['event.event'].create({
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
'community_menu': False,
})
self.assertTrue(event.website_menu)
self._assert_website_menus(event)
introduction_menu = event.menu_id.child_id.filtered(lambda menu: menu.name == 'Introduction')
introduction_menu.unlink()
self.assertTrue(event.website_menu)
self._assert_website_menus(event, set(['Location', 'Register']))
@users('user_eventmanager')
def test_menu_update(self):
event = self.env['event.event'].browse(self.event_0.id)
self.assertFalse(event.menu_id)
event.website_menu = True
self._assert_website_menus(event)
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from odoo import fields
from odoo.addons.website_event.tests.common import TestWebsiteEventCommon
from odoo.tests.common import users
class TestEventMenus(TestWebsiteEventCommon):
@users('user_eventmanager')
def test_menu_management(self):
event = self.env['event.event'].create({
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
'community_menu': False,
})
self.assertTrue(event.website_menu)
self.assertTrue(event.introduction_menu)
self.assertTrue(event.location_menu)
self.assertTrue(event.register_menu)
self.assertFalse(event.community_menu)
self._assert_website_menus(event, ['Introduction', 'Location', 'Register'], menus_out=['Community'])
event.community_menu = True
self._assert_website_menus(event, ['Introduction', 'Location', 'Register', 'Community'])
# test create without any requested menus
event = self.env['event.event'].create({
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': False,
})
self.assertFalse(event.website_menu)
self.assertFalse(event.introduction_menu)
self.assertFalse(event.location_menu)
self.assertFalse(event.register_menu)
self.assertFalse(event.community_menu)
self.assertFalse(event.menu_id)
# test update of website_menu triggering 3 sub menus
event.write({'website_menu': True})
self._assert_website_menus(event, ['Introduction', 'Location', 'Register'], menus_out=['Community'])
@users('user_event_web_manager')
def test_menu_management_frontend(self):
event = self.env['event.event'].create({
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
'community_menu': False,
})
self._assert_website_menus(event, ['Introduction', 'Location', 'Register'], menus_out=['Community'])
# simulate menu removal from frontend: aka unlinking a menu
event.menu_id.child_id.filtered(lambda menu: menu.name == 'Introduction').unlink()
self.assertTrue(event.website_menu)
self._assert_website_menus(event, ['Location', 'Register'], menus_out=['Introduction', 'Community'])
# re-created from backend
event.introduction_menu = True
self._assert_website_menus(event, ['Introduction', 'Location', 'Register'], menus_out=['Community'])
@@ -4,10 +4,11 @@
from datetime import datetime, timedelta
from odoo import fields
from odoo.addons.event.tests.common import TestEventCommon
from odoo.addons.website_event.tests.common import TestWebsiteEventCommon
class TestVisitorEvents(TestEventCommon):
class TestEventVisitor(TestWebsiteEventCommon):
def test_visitor_events(self):
event_1 = self.env['event.event'].create({
'name': 'OtherEvent',
-11
View File
@@ -1,11 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import odoo.tests
from odoo import tools
@odoo.tests.tagged('post_install', '-at_install')
class TestUi(odoo.tests.HttpCase):
def test_admin(self):
self.start_tour("/", 'website_event_tour', login='admin', step_delay=100)
@@ -1,13 +1,121 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from odoo.addons.base.tests.common import HttpCaseWithUserDemo
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.addons.website.tests.test_base_url import TestUrlCommon
from odoo.addons.website_event.tests.common import TestWebsiteEventCommon
from odoo.tests import tagged
from odoo.tools import mute_logger
@tagged('post_install', '-at_install')
class TestUi(HttpCaseWithUserDemo):
def test_website_event_tour_admin(self):
self.start_tour("/", 'website_event_tour', login='admin', step_delay=100)
@tagged('-at_install', 'post_install')
class TestUrlCanonical(TestUrlCommon):
class TestURLs(TestUrlCommon):
def test_01_canonical_url(self):
def test_canonical_url(self):
self._assertCanonical('/event?date=all', self.domain + '/event')
self._assertCanonical('/event?date=old', self.domain + '/event?date=old')
@tagged('post_install', '-at_install')
class TestWebsiteAccess(HttpCaseWithUserDemo, TestWebsiteEventCommon):
def setUp(self):
super(TestWebsiteAccess, self).setUp()
self.events = self.env['event.event'].create([{
'name': 'Event 0 - Sitemap test',
'website_published': True,
'date_begin': datetime.today() - timedelta(days=1),
'date_end': datetime.today() + timedelta(days=1),
}, {
'name': 'Event 1 - Sitemap test',
'website_published': True,
'date_begin': datetime.today() - timedelta(days=1),
'date_end': datetime.today() + timedelta(days=1),
}, {
'name': 'Event 2 - Sitemap test',
'date_begin': datetime.today() - timedelta(days=1),
'date_end': datetime.today() + timedelta(days=1),
}])
self.portal_user = mail_new_test_user(
self.env, name='Smeagol', login='user_portal', password='user_portal', email='portal@example.com',
groups='base.group_portal'
)
def test_website_access_event_manager(self):
""" Event managers are allowed to access both published and unpublished events """
self.authenticate('user_eventmanager', 'user_eventmanager')
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Managers must have access to published event.')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 200, 'Managers must have access to unpublished event.')
resp = self.url_open('/event')
self.assertTrue(published_events[0].name in resp.text, 'Managers must see the unpublished events.')
self.assertTrue(unpublished_events[0].name in resp.text, 'Managers must see the published events.')
def test_website_access_event_uer(self):
""" Event users are allowed to access both published and unpublished events """
self.authenticate('user_eventuser', 'user_eventuser')
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Event user must have access to published event.')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 200, 'Event user must have access to unpublished event.')
resp = self.url_open('/event')
self.assertTrue(published_events[0].name in resp.text, 'Event user must see the unpublished events.')
self.assertTrue(unpublished_events[0].name in resp.text, 'Event user must see the published events.')
@mute_logger('odoo.addons.http_routing.models.ir_http')
def test_website_access_portal(self):
""" Portal users access only published events """
self.authenticate('user_portal', 'user_portal')
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Portal user must have access to published event.')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 403, 'Portal user must not have access to unpublished event.')
resp = self.url_open('/event')
self.assertTrue(published_events[0].name in resp.text, 'Portal must see the published events.')
self.assertFalse(unpublished_events[0].name in resp.text, 'Portal should not see the unpublished events.')
@mute_logger('odoo.addons.http_routing.models.ir_http')
def test_website_access_public(self):
""" Public users access only published events """
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Public must have access to published event')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 403, 'Public must not have access to unpublished event')
resp = self.url_open('/event')
self.assertTrue(published_events[0].name in resp.text, 'Public must see the published events.')
self.assertFalse(unpublished_events[0].name in resp.text, 'Public should not see the unpublished events.')
def test_sitemap(self):
resp = self.url_open('/sitemap.xml')
self.assertTrue('/event/event-0' in resp.text, 'Published events must be present in the sitemap')
self.assertTrue('/event/event-1' in resp.text, 'Published events must be present in the sitemap')
self.assertFalse('/event/event-2' in resp.text, 'Unpublished events must not be present in the sitemap')
@@ -1,125 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from odoo.addons.mail.tests.common import mail_new_test_user
from odoo.tests import HttpCase, tagged
from odoo.tools import mute_logger
@tagged('post_install', '-at_install')
class TestWebsiteEventAccess(HttpCase):
def setUp(self):
super(TestWebsiteEventAccess, self).setUp()
self.events = self.env['event.event'].create([{
'name': 'Event 0 - Sitemap test',
'website_published': True,
'date_begin': datetime.today() - timedelta(days=1),
'date_end': datetime.today() + timedelta(days=1),
}, {
'name': 'Event 1 - Sitemap test',
'website_published': True,
'date_begin': datetime.today() - timedelta(days=1),
'date_end': datetime.today() + timedelta(days=1),
}, {
'name': 'Event 2 - Sitemap test',
'date_begin': datetime.today() - timedelta(days=1),
'date_end': datetime.today() + timedelta(days=1),
}])
self.event_manager = mail_new_test_user(
self.env, name='Gandalf le blanc', login='event_manager', password='event_manager', email='event.manager@example.com',
groups='event.group_event_manager,base.group_user'
)
self.event_user = mail_new_test_user(
self.env, name='Frodon Sacquet', login='event_user', password='event_user', email='event.user@example.com',
groups='event.group_event_user,base.group_user'
)
self.portal_user = mail_new_test_user(
self.env, name='Smeagol', login='user_portal', password='user_portal', email='portal@example.com',
groups='base.group_portal'
)
def test_sitemap(self):
resp = self.url_open('/sitemap.xml')
self.assertTrue('/event/event-0' in resp.text, 'Published events must be present in the sitemap')
self.assertTrue('/event/event-1' in resp.text, 'Published events must be present in the sitemap')
self.assertFalse('/event/event-2' in resp.text, 'Unpublished events must not be present in the sitemap')
def test_events_access_1(self):
"""Access to a published event with public user."""
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'We must have access to published event')
def test_events_access_2(self):
"""Access to an unpublished event with public user."""
with mute_logger('odoo.addons.http_routing.models.ir_http'):
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 403, 'We must not have access to unpublished event')
def test_events_access_3(self):
"""Access to an published event with admin user."""
self.authenticate('event_manager', 'event_manager')
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Admin must have access to published event.')
def test_events_access_4(self):
"""Access to an unpublished event with admin user."""
self.authenticate('event_manager', 'event_manager')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 200, 'Admin must have access to unpublished event.')
def test_events_access_5(self):
"""Access to an published event with event user."""
self.authenticate('event_user', 'event_user')
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Event user must have access to published event.')
def test_events_access_6(self):
"""Access to an unpublished event with event user."""
self.authenticate('event_user', 'event_user')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 200, 'Event user must have access to unpublished event.')
def test_events_access_7(self):
"""Access to an published event with portal user."""
self.authenticate('user_portal', 'user_portal')
published_events = self.events.filtered(lambda event: event.website_published)
resp = self.url_open('/event/%i' % published_events[0].id)
self.assertEqual(resp.status_code, 200, 'Portal user must have access to published event.')
def test_events_access_8(self):
"""Access to an unpublished event with portal user."""
with mute_logger('odoo.addons.http_routing.models.ir_http'):
self.authenticate('user_portal', 'user_portal')
unpublished_events = self.events.filtered(lambda event: not event.website_published)
resp = self.url_open('/event/%i' % unpublished_events[0].id)
self.assertEqual(resp.status_code, 403, 'Portal user must not have access to unpublished event.')
def test_events_home_page_1(self):
"""Portal can only view the published events."""
self.authenticate('user_portal', 'user_portal')
published_event = self.events.filtered(lambda event: event.website_published)[0]
unpublished_event = self.events.filtered(lambda event: not event.website_published)[0]
resp = self.url_open('/event')
self.assertTrue(unpublished_event.name not in resp.text, 'Portal should not see the unpublished events.')
self.assertTrue(published_event.name in resp.text, 'Portal must see the published events.')
def test_events_home_page_2(self):
"""Admin can see all the events."""
self.authenticate('event_manager', 'event_manager')
published_event = self.events.filtered(lambda event: event.website_published)[0]
unpublished_event = self.events.filtered(lambda event: not event.website_published)[0]
resp = self.url_open('/event')
self.assertTrue(unpublished_event.name in resp.text, 'Admin must see the unpublished events.')
self.assertTrue(published_event.name in resp.text, 'Admin must see the published events.')
@@ -23,6 +23,10 @@
<div name="event_menu_configuration" groups="base.group_no_one">
<label for="website_menu" string="Website Submenu"/>
<field name="website_menu"/>
<!-- hidden sub-menus, they are triggered all at once based on "website_menu" -->
<field name="introduction_menu" invisible="1"/>
<field name="location_menu" invisible="1"/>
<field name="register_menu" invisible="1"/>
<label for="menu_register_cta" string="Extra Register Button"/>
<field name="menu_register_cta"/>
<label for="community_menu" string="Community" invisible="1"/>
@@ -9,6 +9,7 @@
<field name="menu_id"/>
<field name="event_id"/>
<field name="menu_type"/>
<field name="view_id"/>
</search>
</field>
</record>
@@ -23,6 +24,7 @@
<field name="menu_id"/>
<field name="event_id"/>
<field name="menu_type"/>
<field name="view_id"/>
</group>
</sheet>
</form>
@@ -37,6 +39,7 @@
<field name="menu_id"/>
<field name="event_id"/>
<field name="menu_type"/>
<field name="view_id"/>
</tree>
</field>
</record>
@@ -49,13 +49,15 @@ class EventEvent(models.Model):
super(EventEvent, self)._update_website_menus(menus_update_by_field=menus_update_by_field)
for event in self:
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('exhibitor_menu')):
event._update_website_menu_entry('exhibitor_menu', 'exhibitor_menu_ids', '_get_exhibitor_menu_entries')
event._update_website_menu_entry('exhibitor_menu', 'exhibitor_menu_ids', 'exhibitor')
def _get_menu_type_field_matching(self):
res = super(EventEvent, self)._get_menu_type_field_matching()
res['exhibitor'] = 'exhibitor_menu'
return res
def _get_exhibitor_menu_entries(self):
def _get_website_menu_entries(self):
self.ensure_one()
return [(_('Exhibitors'), '/event/%s/exhibitors' % slug(self), False, 60, 'exhibitor')]
return super(EventEvent, self)._get_website_menu_entries() + [
(_('Exhibitors'), '/event/%s/exhibitors' % slug(self), False, 60, 'exhibitor')
]
@@ -1,10 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="event.event_0" model="event.event">
<field name="website_menu" eval="True"/>
<field name="website_track" eval="True"/>
<field name="website_track_proposal" eval="True"/>
</record>
<record id="event.event_7" model="event.event">
<field name="website_menu" eval="True"/>
<field name="website_track" eval="True"/>
<field name="website_track_proposal" eval="True"/>
</record>
@@ -73,33 +73,19 @@ class Event(models.Model):
super(Event, self)._update_website_menus(menus_update_by_field=menus_update_by_field)
for event in self:
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('website_track')):
event._update_website_menu_entry('website_track', 'track_menu_ids', '_get_track_menu_entries')
event._update_website_menu_entry('website_track', 'track_menu_ids', 'track')
if event.menu_id and (not menus_update_by_field or event in menus_update_by_field.get('website_track_proposal')):
event._update_website_menu_entry('website_track_proposal', 'track_proposal_menu_ids', '_get_track_proposal_menu_entries')
event._update_website_menu_entry('website_track_proposal', 'track_proposal_menu_ids', 'track_proposal')
def _get_menu_type_field_matching(self):
res = super(Event, self)._get_menu_type_field_matching()
res['track_proposal'] = 'website_track_proposal'
return res
def _get_track_menu_entries(self):
""" Method returning menu entries to display on the website view of the
event, possibly depending on some options in inheriting modules.
Each menu entry is a tuple containing :
* name: menu item name
* url: if set, url to a route (do not use xml_id in that case);
* xml_id: template linked to the page (do not use url in that case);
* menu_type: key linked to the menu, used to categorize the created
website.event.menu;
"""
def _get_website_menu_entries(self):
self.ensure_one()
return [
return super(Event, self)._get_website_menu_entries() + [
(_('Talks'), '/event/%s/track' % slug(self), False, 10, 'track'),
(_('Agenda'), '/event/%s/agenda' % slug(self), False, 70, 'track')
(_('Agenda'), '/event/%s/agenda' % slug(self), False, 70, 'track'),
(_('Talk Proposals'), '/event/%s/track_proposal' % slug(self), False, 15, 'track_proposal')
]
def _get_track_proposal_menu_entries(self):
""" See website_event_track._get_track_menu_entries() """
self.ensure_one()
return [(_('Talk Proposals'), '/event/%s/track_proposal' % slug(self), False, 15, 'track_proposal')]
@@ -8,14 +8,14 @@ class EventType(models.Model):
_inherit = 'event.type'
website_track = fields.Boolean(
string='Tracks on Website', compute='_compute_website_menu_data',
string='Tracks on Website', compute='_compute_website_track_menu_data',
readonly=False, store=True)
website_track_proposal = fields.Boolean(
string='Tracks Proposals on Website', compute='_compute_website_menu_data',
string='Tracks Proposals on Website', compute='_compute_website_track_menu_data',
readonly=False, store=True)
@api.depends('website_menu')
def _compute_website_menu_data(self):
def _compute_website_track_menu_data(self):
""" Simply activate or de-activate all menus at once. """
for event_type in self:
event_type.website_track = event_type.website_menu
+1 -1
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_event_menus
from . import test_track_internals
from . import test_website
from . import test_website_event
@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from datetime import datetime, timedelta
from odoo import fields
from odoo.addons.website_event.tests.common import TestWebsiteEventCommon
from odoo.tests.common import users
class TestEventWebsiteTrack(TestWebsiteEventCommon):
def _get_menus(self):
return super(TestEventWebsiteTrack, self)._get_menus() | set(['Talks', 'Agenda', 'Talk Proposals'])
@users('user_eventmanager')
def test_create_menu(self):
vals = {
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'registration_ids': [(0, 0, {
'partner_id': self.user_eventuser.partner_id.id,
'name': 'test_reg',
})],
'website_menu': True,
'community_menu': True,
'website_track': True,
'website_track_proposal': True,
}
event = self.env['event.event'].create(vals)
self._assert_website_menus(event)
event.write({
'website_track': False,
'website_track_proposal': False,
})
self._assert_website_menus(event, ['Introduction', 'Location', 'Register', 'Community'], menus_out=['Talks', 'Agenda', 'Talk Proposals'])
@users('user_event_web_manager')
def test_menu_management_frontend(self):
vals = {
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
'community_menu': True,
'website_track': True,
'website_track_proposal': True,
}
event = self.env['event.event'].create(vals)
self.assertTrue(event.website_track)
self.assertTrue(event.website_track_proposal)
self._assert_website_menus(event, self._get_menus())
introduction_menu = event.menu_id.child_id.filtered(lambda menu: menu.name == 'Introduction')
introduction_menu.unlink()
self._assert_website_menus(event, ['Location', 'Register', 'Community', 'Talks', 'Agenda', 'Talk Proposals'], menus_out=["Introduction"])
menus = event.menu_id.child_id.filtered(lambda menu: menu.name in ['Agenda', 'Talk Proposals'])
menus.unlink()
self.assertTrue(event.website_track)
self.assertFalse(event.website_track_proposal)
menus = event.menu_id.child_id.filtered(lambda menu: menu.name in ['Talks'])
menus.unlink()
self.assertFalse(event.website_track)
self.assertFalse(event.website_track_proposal)
self._assert_website_menus(event, ['Location', 'Register', 'Community'], menus_out=["Introduction", "Talks", "Agenda", "Talk Proposals"])
event.write({'website_track_proposal': True})
self.assertFalse(event.website_track)
self.assertTrue(event.website_track_proposal)
self._assert_website_menus(event, ['Location', 'Register', 'Community', 'Talk Proposals'], menus_out=["Introduction", "Talks", "Agenda"])
event.write({'website_track': True})
self.assertTrue(event.website_track)
self.assertTrue(event.website_track_proposal)
self._assert_website_menus(event, ['Location', 'Register', 'Community', 'Talks', 'Agenda', 'Talk Proposals'], menus_out=["Introduction"])
@@ -1,21 +0,0 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# -*- coding: utf-8 -*-
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
@tagged('post_install','-at_install')
class TestWebsite(TransactionCase):
def test_event_app_name(self):
website0 = self.env['website'].create({'name': 'Foo'})
self.assertEqual(website0.events_app_name, 'Foo Events')
website1 = self.env['website'].create({'name': 'Foo', 'events_app_name': 'Bar Events'})
self.assertEqual(website1.events_app_name, 'Bar Events')
website2 = self.env['website'].create({'name': 'Foo'})
self.assertEqual(website2.events_app_name, 'Foo Events')
website2.write({'name': 'Bar'})
self.assertEqual(website2.events_app_name, 'Foo Events')
@@ -1,102 +1,21 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
# -*- coding: utf-8 -*-
from datetime import datetime, timedelta
from odoo import fields
from odoo.addons.website_event.tests.common import TestWebsiteEventCommon
from odoo.tests.common import users
from odoo.tests import tagged
from odoo.tests.common import TransactionCase
class TestEventWebsiteTrack(TestWebsiteEventCommon):
@tagged('post_install', '-at_install')
class TestWebsiteEvent(TransactionCase):
def _get_menus(self):
return super(TestEventWebsiteTrack, self)._get_menus() | set(['Community', 'Talks', 'Agenda', 'Talk Proposals'])
def test_event_app_name(self):
website0 = self.env['website'].create({'name': 'Foo'})
self.assertEqual(website0.events_app_name, 'Foo Events')
@users('user_eventmanager')
def test_create_menu(self):
vals = {
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'registration_ids': [(0, 0, {
'partner_id': self.user_eventuser.partner_id.id,
'name': 'test_reg',
})],
'website_menu': True,
'community_menu': True,
'website_track': True,
'website_track_proposal': True,
}
if 'exhibitor_menu' in self.env['event.event']:
vals['exhibitor_menu'] = False
website1 = self.env['website'].create({'name': 'Foo', 'events_app_name': 'Bar Events'})
self.assertEqual(website1.events_app_name, 'Bar Events')
event = self.env['event.event'].create(vals)
self._assert_website_menus(event)
@users('user_event_web_manager')
def test_menu_management_frontend(self):
vals = {
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': True,
'community_menu': True,
'website_track': True,
'website_track_proposal': True,
}
if 'exhibitor_menu' in self.env['event.event']:
vals['exhibitor_menu'] = False
event = self.env['event.event'].create(vals)
self.assertTrue(event.website_track)
self.assertTrue(event.website_track_proposal)
self._assert_website_menus(event)
introduction_menu = event.menu_id.child_id.filtered(lambda menu: menu.name == 'Introduction')
introduction_menu.unlink()
self._assert_website_menus(event, set(['Location', 'Register', 'Community', 'Talks', 'Agenda', 'Talk Proposals']))
menus = event.menu_id.child_id.filtered(lambda menu: menu.name in ['Agenda', 'Talk Proposals'])
menus.unlink()
self.assertTrue(event.website_track)
self.assertFalse(event.website_track_proposal)
menus = event.menu_id.child_id.filtered(lambda menu: menu.name in ['Talks'])
menus.unlink()
self.assertFalse(event.website_track)
self.assertFalse(event.website_track_proposal)
self._assert_website_menus(event, set(['Location', 'Register', 'Community']))
event.write({'website_track_proposal': True})
self.assertFalse(event.website_track)
self.assertTrue(event.website_track_proposal)
self._assert_website_menus(event, set(['Location', 'Register', 'Community', 'Talk Proposals']))
event.write({'website_track': True})
self.assertTrue(event.website_track)
self.assertTrue(event.website_track_proposal)
self._assert_website_menus(event, set(['Location', 'Register', 'Community', 'Talks', 'Agenda', 'Talk Proposals']))
@users('user_eventmanager')
def test_write_menu(self):
event = self.env['event.event'].create({
'name': 'TestEvent',
'date_begin': fields.Datetime.to_string(datetime.today() + timedelta(days=1)),
'date_end': fields.Datetime.to_string(datetime.today() + timedelta(days=15)),
'website_menu': False,
})
self.assertFalse(event.menu_id)
vals = {
'website_menu': True,
'community_menu': True,
'website_track': True,
'website_track_proposal': True,
}
if 'exhibitor_menu' in self.env['event.event']:
vals['exhibitor_menu'] = False
event.write(vals)
self._assert_website_menus(event)
website2 = self.env['website'].create({'name': 'Foo'})
self.assertEqual(website2.events_app_name, 'Foo Events')
website2.write({'name': 'Bar'})
self.assertEqual(website2.events_app_name, 'Foo Events')
+3
View File
@@ -136,6 +136,9 @@ def new_test_user(env, login='', groups='base.group_user', context=None, **kwarg
# automatically generate a name as "Login (groups)" to ease user comprehension
if not create_values.get('name'):
create_values['name'] = '%s (%s)' % (login, groups)
# automatically give a password equal to login
if not create_values.get('password'):
create_values['password'] = login + 'x' * (8 - len(login))
# generate email if not given as most test require an email
if 'email' not in create_values:
if single_email_re.match(login):