diff --git a/addons/event/security/event_security.xml b/addons/event/security/event_security.xml
index 613625f2c78..1059c26c9c0 100644
--- a/addons/event/security/event_security.xml
+++ b/addons/event/security/event_security.xml
@@ -29,27 +29,18 @@
Event: multi-company
- ['|',
- ('company_id', '=', False),
- ('company_id', 'in', company_ids),
- ]
-
+ ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]
Event/Registration: multi-company
- ['|',
- ('company_id', '=', False),
- ('company_id', 'in', company_ids),
- ]
-
+ ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]
-
- Event/Registration: Portal
-
-
- ['|', ('email', '=', user.partner_id.email), ('partner_id', '=', user.partner_id.id)]
-
+
+ Event/Ticket: multi-company
+
+ ['|', ('event_id.company_id', '=', False), ('event_id.company_id', 'in', company_ids)]
+
diff --git a/addons/event/security/ir.model.access.csv b/addons/event/security/ir.model.access.csv
index 909f21e4b80..3bc63e6c9e4 100644
--- a/addons/event/security/ir.model.access.csv
+++ b/addons/event/security/ir.model.access.csv
@@ -9,8 +9,7 @@ access_event_event_manager,event.event.manager,model_event_event,event.group_eve
access_event_event_ticket_user,event.event.ticket.user,model_event_event_ticket,event.group_event_user,1,0,0,0
access_event_event_ticket_manager,event.event.ticket.manager,model_event_event_ticket,event.group_event_manager,1,1,1,1
access_event_registration,event.registration,model_event_registration,event.group_event_user,1,1,1,1
-access_event_registration_employee,event.registration,model_event_registration,base.group_user,1,0,0,0
-access_event_registration_portal,event.registration,model_event_registration,base.group_portal,1,0,0,0
+access_event_registration_all,event.registration,model_event_registration,,0,0,0,0
access_event_mail,event.mail,model_event_mail,event.group_event_user,1,0,0,0
access_event_mail_manager,event.mail manager,model_event_mail,event.group_event_manager,1,1,1,1
access_event_mail_registration,event.mail.registration,model_event_mail_registration,event.group_event_user,1,0,0,0
@@ -21,5 +20,5 @@ access_event_stage_user,event.stage.user,model_event_stage,event.group_event_use
access_event_stage_manager,event.stage.manager,model_event_stage,event.group_event_manager,1,1,1,1
access_event_category,event.tag.category,model_event_tag_category,event.group_event_user,1,0,0,0
access_event_category_manager,event.tag.category manager,model_event_tag_category,event.group_event_manager,1,1,1,1
-access_event_tag,event.tag,model_event_tag,event.group_event_user,1,0,0,0
+access_event_tag,event.tag,model_event_tag,event.group_event_user,1,1,0,0
access_event_tag_manager,event.tag manager,model_event_tag,event.group_event_manager,1,1,1,1
diff --git a/addons/event/tests/test_event_security.py b/addons/event/tests/test_event_security.py
index 019458e2fd9..573dc57a515 100644
--- a/addons/event/tests/test_event_security.py
+++ b/addons/event/tests/test_event_security.py
@@ -58,11 +58,6 @@ class TestEventSecurity(TestEventCommon):
'name': 'TestEvent Modified',
})
- # with self.assertRaises(AccessError):
- # self.env['event.stage'].create({
- # 'name': 'TestStage',
- # })
-
@users('user_eventmanager')
@mute_logger('odoo.models.unlink', 'odoo.addons.base.models.ir_model')
def test_event_access_event_manager(self):
diff --git a/addons/event_sale/models/event_ticket.py b/addons/event_sale/models/event_ticket.py
index 0b899f79269..7759a547d84 100644
--- a/addons/event_sale/models/event_ticket.py
+++ b/addons/event_sale/models/event_ticket.py
@@ -24,7 +24,7 @@ class EventTemplateTicket(models.Model):
digits='Product Price', readonly=False, store=True)
price_reduce = fields.Float(
string="Price Reduce", compute="_compute_price_reduce",
- digits='Product Price')
+ compute_sudo=True, digits='Product Price')
@api.depends('product_id')
def _compute_price(self):
@@ -47,7 +47,7 @@ class EventTemplateTicket(models.Model):
def _compute_price_reduce(self):
for ticket in self:
product = ticket.product_id
- discount = product.lst_price and (product.lst_price - product.price) / product.lst_price or 0.0
+ discount = (product.lst_price - product.price) / product.lst_price if product.lst_price else 0.0
ticket.price_reduce = (1.0 - discount) * ticket.price
def _init_column(self, column_name):
@@ -97,14 +97,16 @@ class EventTicket(models.Model):
_order = "event_id, price"
# product
- price_reduce_taxinc = fields.Float(string='Price Reduce Tax inc', compute='_compute_price_reduce_taxinc')
+ price_reduce_taxinc = fields.Float(
+ string='Price Reduce Tax inc', compute='_compute_price_reduce_taxinc',
+ compute_sudo=True)
def _compute_price_reduce_taxinc(self):
- for record in self:
+ for event in self:
# sudo necessary here since the field is most probably accessed through the website
- tax_ids = record.sudo().product_id.taxes_id.filtered(lambda r: r.company_id == record.event_id.company_id)
- taxes = tax_ids.compute_all(record.price_reduce, record.event_id.company_id.currency_id, 1.0, product=record.product_id)
- record.price_reduce_taxinc = taxes['total_included']
+ tax_ids = event.product_id.taxes_id.filtered(lambda r: r.company_id == event.event_id.company_id)
+ taxes = tax_ids.compute_all(event.price_reduce, event.event_id.company_id.currency_id, 1.0, product=event.product_id)
+ event.price_reduce_taxinc = taxes['total_included']
@api.depends('product_id.active')
def _compute_sale_available(self):
diff --git a/addons/website_event/controllers/main.py b/addons/website_event/controllers/main.py
index 66a94677953..0665dce85bb 100644
--- a/addons/website_event/controllers/main.py
+++ b/addons/website_event/controllers/main.py
@@ -5,6 +5,7 @@ import babel.dates
import re
import werkzeug
from werkzeug.datastructures import OrderedMultiDict
+from werkzeug.exceptions import NotFound
from ast import literal_eval
from collections import defaultdict
@@ -14,6 +15,7 @@ from dateutil.relativedelta import relativedelta
from odoo import fields, http, _
from odoo.addons.http_routing.models.ir_http import slug
from odoo.addons.website.controllers.main import QueryURL
+from odoo.addons.event.controllers.main import EventController
from odoo.http import request
from odoo.osv import expression
from odoo.tools.misc import get_lang, format_date
@@ -28,7 +30,7 @@ class WebsiteEventController(http.Controller):
@http.route(['/event', '/event/page/', '/events', '/events/page/'], type='http', auth="public", website=True, sitemap=sitemap_event)
def events(self, page=1, **searches):
Event = request.env['event.event']
- EventType = request.env['event.type']
+ SudoEventType = request.env['event.type'].sudo()
searches.setdefault('search', '')
searches.setdefault('date', 'all')
@@ -96,7 +98,7 @@ class WebsiteEventController(http.Controller):
current_date = date[1]
if searches["type"] != 'all':
- current_type = EventType.browse(int(searches['type']))
+ current_type = SudoEventType.browse(int(searches['type']))
domain_search["type"] = [("event_type_id", "=", int(searches["type"]))]
if searches["country"] != 'all' and searches["country"] != 'online':
@@ -297,6 +299,9 @@ class WebsiteEventController(http.Controller):
@http.route(['/event//registration/new'], type='json', auth="public", methods=['POST'], website=True)
def registration_new(self, event, **post):
+ if not event.can_access_from_current_website():
+ raise werkzeug.exceptions.NotFound()
+
tickets = self._process_tickets_form(event, post)
availability_check = True
if event.seats_limited:
@@ -355,11 +360,11 @@ class WebsiteEventController(http.Controller):
raise werkzeug.exceptions.NotFound()
registrations = self._process_attendees_form(event, post)
- attendees = self._create_attendees_from_registration_post(event, registrations)
+ attendees_sudo = self._create_attendees_from_registration_post(event, registrations)
urls = event._get_event_resource_urls()
return request.render("website_event.registration_complete", {
- 'attendees': attendees,
+ 'attendees': attendees_sudo,
'event': event,
'google_url': urls.get('google_url'),
'iCal_url': urls.get('iCal_url')
@@ -373,6 +378,6 @@ class WebsiteEventController(http.Controller):
except:
pass
else:
- # perform a search to filter on existing / valid tags implicitely
+ # perform a search to filter on existing / valid tags implicitely + apply rules on color
tags = request.env['event.tag'].search([('id', 'in', tag_ids)])
return tags
diff --git a/addons/website_event/models/event_event.py b/addons/website_event/models/event_event.py
index 01d76489777..925aed32996 100644
--- a/addons/website_event/models/event_event.py
+++ b/addons/website_event/models/event_event.py
@@ -45,7 +45,7 @@ class Event(models.Model):
email = self.env.user.partner_id.email
for event in self:
domain = ['&', '|', ('email', '=', email), ('partner_id', '=', self.env.user.partner_id.id), ('event_id', '=', event.id)]
- event.is_participating = self.env['event.registration'].search_count(domain)
+ event.is_participating = self.env['event.registration'].sudo().search_count(domain)
else:
self.is_participating = False
@@ -193,6 +193,10 @@ class Event(models.Model):
# ------------------------------------------------------------
def google_map_link(self, zoom=8):
+ """ Temporary method for stable """
+ return self._google_map_link(zoom=zoom)
+
+ def _google_map_link(self, zoom=8):
self.ensure_one()
if self.address_id:
return self.sudo().address_id.google_map_link(zoom=zoom)
diff --git a/addons/website_event/security/event_security.xml b/addons/website_event/security/event_security.xml
index d34a1f76a48..857e758e9c0 100644
--- a/addons/website_event/security/event_security.xml
+++ b/addons/website_event/security/event_security.xml
@@ -2,7 +2,7 @@
- event: Public
+ Event: public/portal: published read
[('website_published', '=', True)]
@@ -13,7 +13,7 @@
- Event ticket: public/portal may read published
+ Event Ticket: public/portal: published read
[('event_id.website_published', '=', True)]
diff --git a/addons/website_event/security/ir.model.access.csv b/addons/website_event/security/ir.model.access.csv
index e55cfc58bbf..985c14e5190 100644
--- a/addons/website_event/security/ir.model.access.csv
+++ b/addons/website_event/security/ir.model.access.csv
@@ -1,7 +1,7 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_event_event_public,event.event.public,event.model_event_event,base.group_public,1,0,0,0
access_event_event_portal,event.event.portal,event.model_event_event,base.group_portal,1,0,0,0
-access_event_type_public,event.type.public,event.model_event_type,,1,0,0,0
+access_event_type_public,event.type.public,event.model_event_type,,0,0,0,0
access_event_event_ticket_public,event.event.ticket.public,event.model_event_event_ticket,base.group_public,1,0,0,0
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
diff --git a/addons/website_event/tests/__init__.py b/addons/website_event/tests/__init__.py
index 6986da4eab7..41f5bb1157f 100644
--- a/addons/website_event/tests/__init__.py
+++ b/addons/website_event/tests/__init__.py
@@ -5,3 +5,4 @@ from . import common
from . import test_event_internals
from . import test_ui
from . import test_website_event
+from . import test_website_event_access
diff --git a/addons/website_event/tests/test_website_event_access.py b/addons/website_event/tests/test_website_event_access.py
new file mode 100644
index 00000000000..64da6f4c6c5
--- /dev/null
+++ b/addons/website_event/tests/test_website_event_access.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from functools import partial
+from datetime import datetime, timedelta
+
+from odoo.tests import HttpCase, new_test_user, 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),
+ }])
+
+ event_new_test_user = partial(new_test_user, context={'mail_create_nolog': True, 'mail_create_nosubscribe': True, 'mail_notrack': True, 'no_reset_password': True})
+ self.event_manager = event_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 = event_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 = event_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.')
diff --git a/addons/website_event/views/event_templates.xml b/addons/website_event/views/event_templates.xml
index c3cf0609461..5cf6550e94e 100644
--- a/addons/website_event/views/event_templates.xml
+++ b/addons/website_event/views/event_templates.xml
@@ -356,12 +356,12 @@
@@ -461,7 +461,7 @@
"fields": ["phone", "mobile", "email"]
}'/>
- Get the direction
+ Get the direction