diff --git a/addons/website_event/__manifest__.py b/addons/website_event/__manifest__.py index 54df14666d4..41fb932b683 100644 --- a/addons/website_event/__manifest__.py +++ b/addons/website_event/__manifest__.py @@ -28,6 +28,8 @@ 'views/website_templates.xml', 'views/event_event_views.xml', 'views/event_type_views.xml', + 'views/website_event_menu_views.xml', + 'views/event_menus.xml', 'security/ir.model.access.csv', 'security/event_security.xml', ], diff --git a/addons/website_event/controllers/__init__.py b/addons/website_event/controllers/__init__.py index 65a8c12013d..88cf7794fab 100644 --- a/addons/website_event/controllers/__init__.py +++ b/addons/website_event/controllers/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- from . import main +from . import community diff --git a/addons/website_event_track_online/controllers/community.py b/addons/website_event/controllers/community.py similarity index 72% rename from addons/website_event_track_online/controllers/community.py rename to addons/website_event/controllers/community.py index 2720a94931f..57a8cc4694d 100644 --- a/addons/website_event_track_online/controllers/community.py +++ b/addons/website_event/controllers/community.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo.addons.website_event.controllers.main import WebsiteEventController -from odoo import fields, http, modules, tools +from odoo import http from odoo.http import request -class WebsiteEventCommunityController(http.Controller): + +class EventCommunityController(http.Controller): @http.route('/event//community', type="http", auth="public", website=True) def community(self, event, lang=None, **kwargs): diff --git a/addons/website_event/models/__init__.py b/addons/website_event/models/__init__.py index cf46b000f81..f49b644b04f 100644 --- a/addons/website_event/models/__init__.py +++ b/addons/website_event/models/__init__.py @@ -3,3 +3,5 @@ from . import event_event from . import event_type from . import website +from . import website_event_menu +from . import website_menu diff --git a/addons/website_event/models/event_event.py b/addons/website_event/models/event_event.py index e796b916705..7cf5f4e6b05 100644 --- a/addons/website_event/models/event_event.py +++ b/addons/website_event/models/event_event.py @@ -36,6 +36,13 @@ class Event(models.Model): help="Creates menus Introduction, Location and Register on the page " "of the event on the website.") menu_id = fields.Many2one('website.menu', 'Event Menu', copy=False) + community_menu = fields.Boolean( + "Community Menu", compute="_compute_community_menu", + readonly=False, store=True, + help="Display community tab on website") + community_menu_ids = fields.One2many( + "website.event.menu", "event_id", string="Event Community Menus", + domain=[("menu_type", "=", "community")]) def _compute_is_participating(self): # we don't allow public user to see participating label @@ -47,13 +54,6 @@ class Event(models.Model): else: self.is_participating = False - @api.depends('name') - def _compute_website_url(self): - super(Event, self)._compute_website_url() - for event in self: - if event.id: # avoid to perform a slug on a not yet saved record in case of an onchange. - event.website_url = '/event/%s' % slug(event) - @api.depends('event_type_id') def _compute_website_menu(self): """ Also ensure a value for website_menu as it is a trigger notably for @@ -64,6 +64,24 @@ class Event(models.Model): elif not event.website_menu: event.website_menu = False + @api.depends("event_type_id", "website_menu", "community_menu") + def _compute_community_menu(self): + """ At type onchange: synchronize. At website_menu update: synchronize. """ + for event in self: + if event.event_type_id and event.event_type_id != event._origin.event_type_id: + event.community_menu = event.event_type_id.community_menu + elif event.website_menu and event.website_menu != event._origin.website_menu or not event.community_menu: + event.community_menu = True + elif not event.website_menu: + event.community_menu = False + + @api.depends('name') + def _compute_website_url(self): + super(Event, self)._compute_website_url() + for event in self: + if event.id: # avoid to perform a slug on a not yet saved record in case of an onchange. + event.website_url = '/event/%s' % slug(event) + @api.model def create(self, vals): res = super(Event, self).create(vals) @@ -91,7 +109,10 @@ class Event(models.Model): :return list: list of fields, each of which triggering a menu update like website_menu, website_track, ... """ - return ['website_menu'] + return ['website_menu', 'community_menu'] + + def _get_menu_type_field_matching(self): + return {'community': 'community_menu'} def _split_menus_state_by_field(self): """ For each field linked to a menu, get the set of events having this @@ -135,7 +156,7 @@ class Event(models.Model): menus_update_by_field[fname] |= menus_state_by_field[fname]['deactivated'].filtered(lambda event: event[fname]) return menus_update_by_field - def _get_menu_entries(self): + def _get_website_menu_entries(self): """ Method returning menu entries to display on the website view of the event, possibly depending on some options in inheriting modules. @@ -143,14 +164,22 @@ class Event(models.Model): * 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); + * sequence: specific sequence of menu entry to be set on the menu; + * menu_type: type of menu entry (used in inheriting modules to ease + menu management; not used in this module in 13.3 due to technical + limitations); """ self.ensure_one() return [ - (_('Introduction'), False, 'website_event.template_intro'), - (_('Location'), False, 'website_event.template_location'), - (_('Register'), '/event/%s/register' % slug(self), False), + (_('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), ] + 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. @@ -161,8 +190,44 @@ 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 - for sequence, (name, url, xml_id) in enumerate(event._get_menu_entries()): - event._create_menu(sequence, name, url, xml_id) + 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') + + def _update_website_menu_entry(self, fname_bool, fname_o2m, method_name): + """ 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 + while developing. + + :param fname_bool: field name (e.g. website_track) + :param fname_o2m: o2m linking towards website.event.menu matching the + boolean fields (normally an entry ot website.event.menu with type matching + the boolean field name) + :param method_name: method returning menu entries information: url, sequence, ... + """ + self.ensure_one() + new_menu = None + + 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) + 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 @@ -184,6 +249,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, + }) return website_menu # ------------------------------------------------------------ diff --git a/addons/website_event/models/event_type.py b/addons/website_event/models/event_type.py index 6aee644c7d3..b89d3af9518 100644 --- a/addons/website_event/models/event_type.py +++ b/addons/website_event/models/event_type.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import fields, models +from odoo import api, fields, models class EventType(models.Model): @@ -9,3 +9,12 @@ class EventType(models.Model): _inherit = ['event.type'] website_menu = fields.Boolean('Display a dedicated menu on Website') + community_menu = fields.Boolean( + "Community Menu", compute="_compute_community_menu", + readonly=False, store=True, + help="Display community tab on website") + + @api.depends('website_menu') + def _compute_community_menu(self): + for event_type in self: + event_type.community_menu = event_type.website_menu diff --git a/addons/website_event/models/website_event_menu.py b/addons/website_event/models/website_event_menu.py new file mode 100644 index 00000000000..b19c7d8ca75 --- /dev/null +++ b/addons/website_event/models/website_event_menu.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import fields, models + + +class EventMenu(models.Model): + _name = "website.event.menu" + _description = "Website Event Menu" + + 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) diff --git a/addons/website_event/models/website_menu.py b/addons/website_event/models/website_menu.py new file mode 100644 index 00000000000..1b96cd8552c --- /dev/null +++ b/addons/website_event/models/website_menu.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models + + +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. """ + event_updates = {} + website_event_menus = self.env['website.event.menu'].search([('menu_id', 'in', self.ids)]) + for event_menu in website_event_menus: + to_update = event_updates.setdefault(event_menu.event_id, list()) + for menu_type, fname in event_menu.event_id._get_menu_type_field_matching().items(): + if event_menu.menu_type == menu_type: + to_update.append(fname) + + # call super that resumes the unlink of menus entries (including website event menus) + res = super(WebsiteMenu, self).unlink() + + # update events + for event, to_update in event_updates.items(): + if to_update: + event.write(dict((fname, False) for fname in to_update)) + + return res diff --git a/addons/website_event/security/ir.model.access.csv b/addons/website_event/security/ir.model.access.csv index 985c14e5190..e865d4a1581 100644 --- a/addons/website_event/security/ir.model.access.csv +++ b/addons/website_event/security/ir.model.access.csv @@ -6,3 +6,5 @@ access_event_event_ticket_public,event.event.ticket.public,event.model_event_eve access_event_event_ticket_portal,event.event.ticket.portal,event.model_event_event_ticket,base.group_portal,1,0,0,0 access_event_category_public,event.tag.category.public,event.model_event_tag_category,,1,0,0,0 access_event_tag_public,event.tag.public,event.model_event_tag,,1,0,0,0 +access_website_event_menu_public,website.event.menu,model_website_event_menu,,1,0,0,0 +access_website_event_menu_manager,website.event.menu,model_website_event_menu,event.group_event_manager,1,1,1,1 diff --git a/addons/website_event/tests/test_event_internals.py b/addons/website_event/tests/test_event_internals.py index 9e99815fd67..9339da20e6a 100644 --- a/addons/website_event/tests/test_event_internals.py +++ b/addons/website_event/tests/test_event_internals.py @@ -17,6 +17,7 @@ class TestEventWebsite(TestWebsiteEventCommon): '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) @@ -27,6 +28,7 @@ class TestEventWebsite(TestWebsiteEventCommon): '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) diff --git a/addons/website_event/views/event_event_views.xml b/addons/website_event/views/event_event_views.xml index 40b949e23bc..6b03966b5aa 100644 --- a/addons/website_event/views/event_event_views.xml +++ b/addons/website_event/views/event_event_views.xml @@ -19,6 +19,14 @@ type="object" string="Preview Badges"/> + +
+
+
diff --git a/addons/website_event/views/event_menus.xml b/addons/website_event/views/event_menus.xml new file mode 100644 index 00000000000..623a223679b --- /dev/null +++ b/addons/website_event/views/event_menus.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/addons/website_event/views/event_type_views.xml b/addons/website_event/views/event_type_views.xml index 8ace9ddc2d7..e35070a93ab 100644 --- a/addons/website_event/views/event_type_views.xml +++ b/addons/website_event/views/event_type_views.xml @@ -19,6 +19,9 @@ website: registrations, schedule, map, ... +
+
diff --git a/addons/website_event_track/views/website_event_menu_views.xml b/addons/website_event/views/website_event_menu_views.xml similarity index 100% rename from addons/website_event_track/views/website_event_menu_views.xml rename to addons/website_event/views/website_event_menu_views.xml diff --git a/addons/website_event_meet/controllers/community.py b/addons/website_event_meet/controllers/community.py index c653b9fa9f9..291a6017dfc 100644 --- a/addons/website_event_meet/controllers/community.py +++ b/addons/website_event_meet/controllers/community.py @@ -8,13 +8,13 @@ from werkzeug.utils import redirect from odoo import exceptions, http from odoo.http import request from odoo.addons.http_routing.models.ir_http import slug -from odoo.addons.website_event_track_online.controllers.community import WebsiteEventCommunityController +from odoo.addons.website_event.controllers.community import EventCommunityController from odoo.osv import expression _logger = logging.getLogger(__name__) -class WebsiteEventMeetController(WebsiteEventCommunityController): +class WebsiteEventMeetController(EventCommunityController): def _get_event_rooms_base_domain(self, event): search_domain_base = [('event_id', '=', event.id), ('is_published', '=', True)] diff --git a/addons/website_event_meet/models/website_event_menu.py b/addons/website_event_meet/models/website_event_menu.py index 827d3bc1fa4..0902dde05f2 100644 --- a/addons/website_event_meet/models/website_event_menu.py +++ b/addons/website_event_meet/models/website_event_menu.py @@ -7,4 +7,6 @@ from odoo import fields, models class EventMenu(models.Model): _inherit = "website.event.menu" - menu_type = fields.Selection(selection_add=[("meeting_room", "Event Meeting Room Menus")]) + menu_type = fields.Selection( + selection_add=[("meeting_room", "Event Meeting Room Menus")], + ondelete={'meeting_room': 'cascade'}) diff --git a/addons/website_event_meet/views/event_event_views.xml b/addons/website_event_meet/views/event_event_views.xml index 08d5c46e86b..798be072310 100644 --- a/addons/website_event_meet/views/event_event_views.xml +++ b/addons/website_event_meet/views/event_event_views.xml @@ -4,7 +4,7 @@ event.event.view.form.inherit.meet event.event - +