Files
odoo_source/addons/website_event/controllers/main.py
T
RomainLibert a03faab03f [IMP] event, website_event: Make ics file generation available in event
Ics file generation should be possible even when only event is
installed as it is a basic feature of events.

Moreover we need to be able to generate such files in order to replace
the old outlook api used in the event templates, api which is not
supported anymore.

We decided to use ics files because it is supported by most calendar
schedulers hence working with outlook.

Linked to task #1853063

closes odoo/odoo#28477
2018-12-17 11:46:48 +00:00

286 lines
13 KiB
Python

# -*- coding: utf-8 -*-
import babel.dates
import re
import werkzeug
import json
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
from odoo import fields, http, _
from odoo.addons.http_routing.models.ir_http import slug
from odoo.http import request
class WebsiteEventController(http.Controller):
def sitemap_event(env, rule, qs):
if not qs or qs.lower() in '/events':
yield {'loc': '/events'}
@http.route(['/event', '/event/page/<int:page>', '/events', '/events/page/<int: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']
searches.setdefault('date', 'all')
searches.setdefault('type', 'all')
searches.setdefault('country', 'all')
def sdn(date):
return fields.Datetime.to_string(date.replace(hour=23, minute=59, second=59))
def sd(date):
return fields.Datetime.to_string(date)
today = datetime.today()
dates = [
['all', _('Next Events'), [("date_end", ">", sd(today))], 0],
['today', _('Today'), [
("date_end", ">", sd(today)),
("date_begin", "<", sdn(today))],
0],
['week', _('This Week'), [
("date_end", ">=", sd(today + relativedelta(days=-today.weekday()))),
("date_begin", "<", sdn(today + relativedelta(days=6-today.weekday())))],
0],
['nextweek', _('Next Week'), [
("date_end", ">=", sd(today + relativedelta(days=7-today.weekday()))),
("date_begin", "<", sdn(today + relativedelta(days=13-today.weekday())))],
0],
['month', _('This month'), [
("date_end", ">=", sd(today.replace(day=1))),
("date_begin", "<", (today.replace(day=1) + relativedelta(months=1)).strftime('%Y-%m-%d 00:00:00'))],
0],
['nextmonth', _('Next month'), [
("date_end", ">=", sd(today.replace(day=1) + relativedelta(months=1))),
("date_begin", "<", (today.replace(day=1) + relativedelta(months=2)).strftime('%Y-%m-%d 00:00:00'))],
0],
['old', _('Past Events'), [
("date_end", "<", today.strftime('%Y-%m-%d 00:00:00'))],
0],
]
# search domains
domain_search = {'website_specific': request.website.website_domain()}
current_date = None
current_type = None
current_country = None
for date in dates:
if searches["date"] == date[0]:
domain_search["date"] = date[2]
if date[0] != 'all':
current_date = date[1]
if searches["type"] != 'all':
current_type = EventType.browse(int(searches['type']))
domain_search["type"] = [("event_type_id", "=", int(searches["type"]))]
if searches["country"] != 'all' and searches["country"] != 'online':
current_country = request.env['res.country'].browse(int(searches['country']))
domain_search["country"] = ['|', ("country_id", "=", int(searches["country"])), ("country_id", "=", False)]
elif searches["country"] == 'online':
domain_search["country"] = [("country_id", "=", False)]
def dom_without(without):
domain = [('state', "in", ['draft', 'confirm', 'done'])]
for key, search in domain_search.items():
if key != without:
domain += search
return domain
# count by domains without self search
for date in dates:
if date[0] != 'old':
date[3] = Event.search_count(dom_without('date') + date[2])
domain = dom_without('type')
types = Event.read_group(domain, ["id", "event_type_id"], groupby=["event_type_id"], orderby="event_type_id")
types.insert(0, {
'event_type_id_count': sum([int(type['event_type_id_count']) for type in types]),
'event_type_id': ("all", _("All Categories"))
})
domain = dom_without('country')
countries = Event.read_group(domain, ["id", "country_id"], groupby="country_id", orderby="country_id")
countries.insert(0, {
'country_id_count': sum([int(country['country_id_count']) for country in countries]),
'country_id': ("all", _("All Countries"))
})
step = 10 # Number of events per page
event_count = Event.search_count(dom_without("none"))
pager = request.website.pager(
url="/event",
url_args={'date': searches.get('date'), 'type': searches.get('type'), 'country': searches.get('country')},
total=event_count,
page=page,
step=step,
scope=5)
order = 'date_begin'
if searches.get('date', 'all') == 'old':
order = 'date_begin desc'
if searches["country"] != 'all': # if we are looking for a specific country
order = 'is_online, ' + order # show physical events first
order = 'is_published desc, ' + order
events = Event.search(dom_without("none"), limit=step, offset=pager['offset'], order=order)
values = {
'current_date': current_date,
'current_country': current_country,
'current_type': current_type,
'event_ids': events, # event_ids used in website_event_track so we keep name as it is
'dates': dates,
'types': types,
'countries': countries,
'pager': pager,
'searches': searches,
'search_path': "?%s" % werkzeug.url_encode(searches),
}
return request.render("website_event.index", values)
@http.route(['''/event/<model("event.event", "[('website_id', 'in', (False, current_website_id))]"):event>/page/<path:page>'''], type='http', auth="public", website=True, sitemap=False)
def event_page(self, event, page, **post):
if not event.can_access_from_current_website():
raise werkzeug.exceptions.NotFound()
values = {
'event': event,
'main_object': event
}
if '.' not in page:
page = 'website_event.%s' % page
try:
request.website.get_template(page)
except ValueError:
# page not found
values['path'] = re.sub(r"^website_event\.", '', page)
values['from_template'] = 'website_event.default_page' # .strip('website_event.')
page = 'website.%s' % (request.website.is_publisher() and 'page_404' or '404')
return request.render(page, values)
@http.route(['''/event/<model("event.event", "[('website_id', 'in', (False, current_website_id))]"):event>'''], type='http', auth="public", website=True)
def event(self, event, **post):
if not event.can_access_from_current_website():
raise werkzeug.exceptions.NotFound()
if event.menu_id and event.menu_id.child_id:
target_url = event.menu_id.child_id[0].url
else:
target_url = '/event/%s/register' % str(event.id)
if post.get('enable_editor') == '1':
target_url += '?enable_editor=1'
return request.redirect(target_url)
@http.route(['''/event/<model("event.event", "[('website_id', 'in', (False, current_website_id))]"):event>/register'''], type='http', auth="public", website=True, sitemap=False)
def event_register(self, event, **post):
if not event.can_access_from_current_website():
raise werkzeug.exceptions.NotFound()
values = {
'event': event,
'main_object': event,
'range': range,
'registrable': event.sudo()._is_event_registrable()
}
return request.render("website_event.event_description_full", values)
@http.route('/event/add_event', type='json', auth="user", methods=['POST'], website=True)
def add_event(self, event_name="New Event", **kwargs):
event = self._add_event(event_name, request.context)
return "/event/%s/register?enable_editor=1" % slug(event)
def _add_event(self, event_name=None, context=None, **kwargs):
if not event_name:
event_name = _("New Event")
date_begin = datetime.today() + timedelta(days=(14))
vals = {
'name': event_name,
'date_begin': fields.Date.to_string(date_begin),
'date_end': fields.Date.to_string((date_begin + timedelta(days=(1)))),
'seats_available': 1000,
'website_id': request.website.id,
}
return request.env['event.event'].with_context(context or {}).create(vals)
def get_formated_date(self, event):
start_date = fields.Datetime.from_string(event.date_begin).date()
end_date = fields.Datetime.from_string(event.date_end).date()
month = babel.dates.get_month_names('abbreviated', locale=event.env.context.get('lang') or 'en_US')[start_date.month]
return ('%s %s%s') % (month, start_date.strftime("%e"), (end_date != start_date and ("-" + end_date.strftime("%e")) or ""))
@http.route('/event/get_country_event_list', type='json', auth='public', website=True)
def get_country_events(self, **post):
Event = request.env['event.event']
country_code = request.session['geoip'].get('country_code')
result = {'events': [], 'country': False}
events = None
domain = request.website.website_domain()
if country_code:
country = request.env['res.country'].search([('code', '=', country_code)], limit=1)
events = Event.search(domain + ['|', ('address_id', '=', None), ('country_id.code', '=', country_code), ('date_begin', '>=', '%s 00:00:00' % fields.Date.today()), ('state', '=', 'confirm')], order="date_begin")
if not events:
events = Event.search(domain + [('date_begin', '>=', '%s 00:00:00' % fields.Date.today()), ('state', '=', 'confirm')], order="date_begin")
for event in events:
if country_code and event.country_id.code == country_code:
result['country'] = country
result['events'].append({
"date": self.get_formated_date(event),
"event": event,
"url": event.website_url})
return request.env['ir.ui.view'].render_template("website_event.country_events_list", result)
def _process_tickets_details(self, data):
nb_register = int(data.get('nb_register-0', 0))
if nb_register:
return [{'id': 0, 'name': 'Registration', 'quantity': nb_register, 'price': 0}]
return []
@http.route(['/event/<model("event.event"):event>/registration/new'], type='json', auth="public", methods=['POST'], website=True)
def registration_new(self, event, **post):
tickets = self._process_tickets_details(post)
if not tickets:
return False
return request.env['ir.ui.view'].render_template("website_event.registration_attendee_details", {'tickets': tickets, 'event': event})
def _process_registration_details(self, details):
''' Process data posted from the attendee details form. '''
registrations = {}
global_values = {}
for key, value in details.items():
counter, field_name = key.split('-', 1)
if counter == '0':
global_values[field_name] = value
else:
registrations.setdefault(counter, dict())[field_name] = value
for key, value in global_values.items():
for registration in registrations.values():
registration[key] = value
return list(registrations.values())
@http.route(['''/event/<model("event.event", "[('website_id', 'in', (False, current_website_id))]"):event>/registration/confirm'''], type='http', auth="public", methods=['POST'], website=True)
def registration_confirm(self, event, **post):
if not event.can_access_from_current_website():
raise werkzeug.exceptions.NotFound()
Attendees = request.env['event.registration']
registrations = self._process_registration_details(post)
for registration in registrations:
registration['event_id'] = event
Attendees += Attendees.sudo().create(
Attendees._prepare_attendee_values(registration))
urls = event._get_event_resource_urls(Attendees.ids)
return request.render("website_event.registration_complete", {
'attendees': Attendees.sudo(),
'event': event,
'google_url': urls.get('google_url'),
'iCal_url': urls.get('iCal_url')
})