From 77d7a3cf6a2cf07e18804a2d9b59e3697b11006e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 18 Aug 2020 13:56:08 +0000 Subject: [PATCH] [MOV] website_event(_track): move website event menu into website event PURPOSE Clean organization and models linked to Event Online feature introduced in semi stable saas-13.3 at odoo/odoo@981f95bbf46658eda9f2d33751b9310cc67d86aa and odoo/enterprise@14722028ae0773c3710ea48ce48ff44703e83b5a Also clean website event menu not being available in website event but only in website event track, which implies some extra-code to manage it. In short: merge website_event_online in website_event, website_event_track _(online/session) in website_event_track. RATIONALE _online modules have been added to extend content of website_event and website_event_track without having any impact on those module. First step of cleaning is to move this content directly in base module. track_session module is mainly a rewrite of track module. Second step of cleaning is to move its content directly in website_event_track. SPECIFICATIONS Move website event menu model directly into website event. Website event menu model has been introduced to help dealing with event-specific menus and website menus. This is some kind of glue to synchronize both of them as people could either * update an event (website_menu, website_track) that updates website menus availability; * update menus through website that should update event field value and menu computation; Having a model introduced in website event track forces to have override and code split across website_event, website_event_track, and now also in both _online version of those two as menu management was improved. In this commit we simplify all this code by moving most of menu management code in website_event, leaving only business-specific code (fields and their menus) to sub modules. SPECIFICATIONS: WEBSITE EVENT MENU Make type required as we don't support entries without type. Indeed this model is used to automate menus generation / destruction, and not for hand-made menus. We therefore set type as required and add a cascade ondelete for selection. SPECIFCIATIONS: COMMUNITY MENU Doing this change allows to define community menu in website_event and re-use it in website_event_meet and website_event_track_quiz, removing some unnecessary dependencies. This menu is void in website_event, and displays either meeting rooms (in meet) or quiz points leaderboard (in quiz), or a mix of both if the two features are installed. LINKS Task ID-2319779 COM odoo/odoo#56067 ENT odoo/enterprise#12520 UPG odoo/upgrade#165 --- addons/website_event/__manifest__.py | 2 + addons/website_event/controllers/__init__.py | 1 + .../controllers/community.py | 6 +- addons/website_event/models/__init__.py | 2 + addons/website_event/models/event_event.py | 99 ++++++++++++++++--- addons/website_event/models/event_type.py | 11 ++- .../models/website_event_menu.py | 15 +++ addons/website_event/models/website_menu.py | 29 ++++++ .../security/ir.model.access.csv | 2 + .../tests/test_event_internals.py | 2 + .../website_event/views/event_event_views.xml | 8 ++ addons/website_event/views/event_menus.xml | 11 +++ .../website_event/views/event_type_views.xml | 3 + .../views/website_event_menu_views.xml | 0 .../controllers/community.py | 4 +- .../models/website_event_menu.py | 4 +- .../views/event_event_views.xml | 2 +- .../controllers/community.py | 10 +- .../models/event_event.py | 37 ------- .../views/event_event_views.xml | 4 +- addons/website_event_track/__manifest__.py | 1 - .../website_event_track/models/event_event.py | 56 ++--------- .../models/website_event_menu.py | 12 +-- .../models/website_menu.py | 3 - .../security/ir.model.access.csv | 2 - .../tests/test_website_event.py | 11 ++- .../website_event_track/views/event_menus.xml | 7 -- .../models/website_event_menu.py | 4 +- .../__manifest__.py | 1 - .../controllers/__init__.py | 1 - .../models/__init__.py | 3 - .../models/event_event.py | 67 ------------- .../models/event_type.py | 18 ---- .../models/website_event_menu.py | 12 --- .../views/event_event_views.xml | 4 - .../views/event_type_views.xml | 16 --- .../controllers/community.py | 4 +- 37 files changed, 208 insertions(+), 266 deletions(-) rename addons/{website_event_track_online => website_event}/controllers/community.py (72%) create mode 100644 addons/website_event/models/website_event_menu.py create mode 100644 addons/website_event/models/website_menu.py create mode 100644 addons/website_event/views/event_menus.xml rename addons/{website_event_track => website_event}/views/website_event_menu_views.xml (100%) delete mode 100644 addons/website_event_track_online/models/event_event.py delete mode 100644 addons/website_event_track_online/models/event_type.py delete mode 100644 addons/website_event_track_online/models/website_event_menu.py delete mode 100644 addons/website_event_track_online/views/event_type_views.xml 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 - +