summaryrefslogtreecommitdiff
path: root/addons/website_event_track/controllers
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2020-08-20 09:16:38 +0000
committerThibault Delavallée <tde@odoo.com>2020-08-21 17:30:13 +0000
commit1163013ed6bf191a9e1548866a4df699f72b5bf4 (patch)
tree8d54ebf3fe6a76ff69ad163541870eac938c0c7c /addons/website_event_track/controllers
parentb0845c0f2b48d6c7029a34ae50fc95876630e7ed (diff)
[REM] website_event_track_online: merge into website_event_track
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 remaining content of website event track online to website event track. Agenda notably is completely replaced by the new one developed within track_online module. Update dependencies accordingly. LINKS Task ID-2319779 COM odoo/odoo#56067 ENT odoo/enterprise#12520 UPG odoo/upgrade#1654
Diffstat (limited to 'addons/website_event_track/controllers')
-rw-r--r--addons/website_event_track/controllers/__init__.py3
-rw-r--r--addons/website_event_track/controllers/event_track.py332
-rw-r--r--addons/website_event_track/controllers/main.py185
-rw-r--r--addons/website_event_track/controllers/webmanifest.py58
4 files changed, 392 insertions, 186 deletions
diff --git a/addons/website_event_track/controllers/__init__.py b/addons/website_event_track/controllers/__init__.py
index 5d4b25db9c0..8779baf6109 100644
--- a/addons/website_event_track/controllers/__init__.py
+++ b/addons/website_event_track/controllers/__init__.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
-from . import main
+from . import event_track
+from . import webmanifest
diff --git a/addons/website_event_track/controllers/event_track.py b/addons/website_event_track/controllers/event_track.py
new file mode 100644
index 00000000000..e338f384580
--- /dev/null
+++ b/addons/website_event_track/controllers/event_track.py
@@ -0,0 +1,332 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from datetime import timedelta
+from werkzeug.exceptions import Forbidden, NotFound
+
+import babel
+import babel.dates
+import base64
+import pytz
+
+from odoo import exceptions, http, fields
+from odoo.http import request
+from odoo.tools import plaintext2html, html2plaintext
+
+
+class EventTrackController(http.Controller):
+
+ # ------------------------------------------------------------
+ # TRACK LIST VIEW
+ # ------------------------------------------------------------
+
+ @http.route([
+ '''/event/<model("event.event"):event>/track''',
+ '''/event/<model("event.event"):event>/track/tag/<model("event.track.tag"):tag>'''
+ ], type='http', auth="public", website=True, sitemap=False)
+ def event_tracks(self, event, tag=None, **post):
+ if not event.can_access_from_current_website() or (tag and tag.color == 0):
+ raise NotFound()
+
+ event = event.with_context(tz=event.date_tz or 'UTC')
+ searches = {}
+ if tag:
+ searches.update(tag=tag.id)
+ tracks = event.track_ids.filtered(lambda track: tag in track.tag_ids)
+ else:
+ tracks = event.track_ids
+
+ values = {
+ 'event': event,
+ 'main_object': event,
+ 'tracks': tracks,
+ 'tags': event.tracks_tag_ids,
+ 'searches': searches,
+ 'html2plaintext': html2plaintext
+ }
+ return request.render("website_event_track.tracks", values)
+
+ # ------------------------------------------------------------
+ # AGENDA VIEW
+ # ------------------------------------------------------------
+
+ @http.route(['''/event/<model("event.event"):event>/agenda'''], type='http', auth="public", website=True, sitemap=False)
+ def event_agenda(self, event, tag=None, **post):
+ if not event.can_access_from_current_website():
+ raise NotFound()
+
+ event = event.with_context(tz=event.date_tz or 'UTC')
+ vals = {
+ 'event': event,
+ 'main_object': event,
+ 'tag': tag,
+ 'user_event_manager': request.env.user.has_group('event.group_event_manager'),
+ }
+
+ vals.update(self._prepare_calendar_values(event))
+
+ return request.render("website_event_track.agenda_online", vals)
+
+ def _prepare_calendar_values(self, event):
+ """
+ Override that should completely replace original method in v14.
+
+ This methods slit the day (max end time - min start time) into 15 minutes time slots.
+ For each time slot, we assign the tracks that start at this specific time slot, and we add the number
+ of time slot that the track covers (track duration / 15 min)
+ The calendar will be divided into rows of 15 min, and the talks will cover the corresponding number of rows
+ (15 min slots).
+ """
+ event = event.with_context(tz=event.date_tz or 'UTC')
+ local_tz = pytz.timezone(event.date_tz or 'UTC')
+ lang_code = request.env.context.get('lang')
+ event_track_ids = self._event_agenda_get_tracks(event)
+
+ locations = list(set(track.location_id for track in event_track_ids))
+ locations.sort(key=lambda x: x.id)
+
+ # First split day by day (based on start time)
+ time_slots_by_tracks = {track: self._split_track_by_days(track, local_tz) for track in event_track_ids}
+
+ # extract all the tracks time slots
+ track_time_slots = set().union(*(time_slot.keys() for time_slot in [time_slots for time_slots in time_slots_by_tracks.values()]))
+
+ # extract unique days
+ days = list(set(time_slot.date() for time_slot in track_time_slots))
+ days.sort()
+
+ # Create the dict that contains the tracks at the correct time_slots / locations coordinates
+ tracks_by_days = dict.fromkeys(days, 0)
+ time_slots_by_day = dict((day, dict(start=set(), end=set())) for day in days)
+ tracks_by_rounded_times = dict((time_slot, dict((location, {}) for location in locations)) for time_slot in track_time_slots)
+ for track, time_slots in time_slots_by_tracks.items():
+ start_date = fields.Datetime.from_string(track.date).replace(tzinfo=pytz.utc).astimezone(local_tz)
+ end_date = start_date + timedelta(hours=(track.duration or 0.25))
+
+ for time_slot, duration in time_slots.items():
+ tracks_by_rounded_times[time_slot][track.location_id][track] = {
+ 'rowspan': duration, # rowspan
+ 'start_date': self._get_locale_time(start_date, lang_code),
+ 'end_date': self._get_locale_time(end_date, lang_code),
+ 'occupied_cells': self._get_occupied_cells(track, duration, locations, local_tz)
+ }
+
+ # get all the time slots by day to determine the max duration of a day.
+ day = time_slot.date()
+ time_slots_by_day[day]['start'].add(time_slot)
+ time_slots_by_day[day]['end'].add(time_slot+timedelta(minutes=15*duration))
+ tracks_by_days[day] += 1
+
+ # split days into 15 minutes time slots
+ global_time_slots_by_day = dict((day, {}) for day in days)
+ for day, time_slots in time_slots_by_day.items():
+ start_time_slot = min(time_slots['start'])
+ end_time_slot = max(time_slots['end'])
+
+ time_slots_count = int(((end_time_slot - start_time_slot).total_seconds() / 3600) * 4)
+ current_time_slot = start_time_slot
+ for i in range(0, time_slots_count + 1):
+ global_time_slots_by_day[day][current_time_slot] = tracks_by_rounded_times.get(current_time_slot, {})
+ global_time_slots_by_day[day][current_time_slot]['formatted_time'] = self._get_locale_time(current_time_slot, lang_code)
+ current_time_slot = current_time_slot + timedelta(minutes=15)
+
+ # count the number of tracks by days
+ tracks_by_days = dict.fromkeys(days, 0)
+ for track in event_track_ids:
+ track_day = fields.Datetime.from_string(track.date).replace(tzinfo=pytz.utc).astimezone(local_tz).date()
+ tracks_by_days[track_day] += 1
+
+ return {
+ 'days': days,
+ 'tracks_by_days': tracks_by_days,
+ 'time_slots': global_time_slots_by_day,
+ 'locations': locations
+ }
+
+ def _event_agenda_get_tracks(self, event):
+ tracks_sudo = event.sudo().track_ids.filtered(lambda track: track.date)
+ if not request.env.user.has_group('event.group_event_manager'):
+ tracks_sudo = tracks_sudo.filtered(lambda track: track.is_published or track.stage_id.is_accepted)
+ return tracks_sudo
+
+ def _get_locale_time(self, dt_time, lang_code):
+ """ Get locale time from datetime object
+
+ :param dt_time: datetime object
+ :param lang_code: language code (eg. en_US)
+ """
+ locale = babel.Locale.parse(lang_code)
+ return babel.dates.format_time(dt_time, format='short', locale=locale)
+
+ def time_slot_rounder(self, time, rounded_minutes):
+ """ Rounds to nearest hour by adding a timedelta hour if minute >= rounded_minutes
+ E.g. : If rounded_minutes = 15 -> 09:26:00 becomes 09:30:00
+ 09:17:00 becomes 09:15:00
+ """
+ return (time.replace(second=0, microsecond=0, minute=0, hour=time.hour)
+ + timedelta(minutes=rounded_minutes * (time.minute // rounded_minutes)))
+
+ def _split_track_by_days(self, track, local_tz):
+ """
+ Based on the track start_date and the duration,
+ split the track duration into :
+ start_time by day : number of time slot (15 minutes) that the track takes on that day.
+ E.g. : start date = 01-01-2000 10:00 PM and duration = 3 hours
+ return {
+ 01-01-2000 10:00:00 PM: 8 (2 * 4),
+ 01-02-2000 00:00:00 AM: 4 (1 * 4)
+ }
+ Also return a set of all the time slots
+ """
+ start_date = fields.Datetime.from_string(track.date).replace(tzinfo=pytz.utc).astimezone(local_tz)
+ start_datetime = self.time_slot_rounder(start_date, 15)
+ end_datetime = self.time_slot_rounder(start_datetime + timedelta(hours=(track.duration or 0.25)), 15)
+ time_slots_count = int(((end_datetime - start_datetime).total_seconds() / 3600) * 4)
+
+ time_slots_by_day_start_time = {start_datetime: 0}
+ for i in range(0, time_slots_count):
+ # If the new time slot is still on the current day
+ next_day = (start_datetime + timedelta(days=1)).date()
+ if (start_datetime + timedelta(minutes=15*i)).date() <= next_day:
+ time_slots_by_day_start_time[start_datetime] += 1
+ else:
+ start_datetime = next_day.datetime()
+ time_slots_by_day_start_time[start_datetime] = 0
+
+ return time_slots_by_day_start_time
+
+ def _get_occupied_cells(self, track, rowspan, locations, local_tz):
+ """
+ In order to use only once the cells that the tracks will occupy, we need to reserve those cells
+ (time_slot, location) coordinate. Those coordinated will be given to the template to avoid adding
+ blank cells where already occupied by a track.
+ """
+ occupied_cells = []
+
+ start_date = fields.Datetime.from_string(track.date).replace(tzinfo=pytz.utc).astimezone(local_tz)
+ start_date = self.time_slot_rounder(start_date, 15)
+ for i in range(0, rowspan):
+ time_slot = start_date + timedelta(minutes=15*i)
+ if track.location_id:
+ occupied_cells.append((time_slot, track.location_id))
+ # when no location, reserve all locations
+ else:
+ occupied_cells += [(time_slot, location) for location in locations if location]
+
+ return occupied_cells
+
+ # ------------------------------------------------------------
+ # TRACK PAGE VIEW
+ # ------------------------------------------------------------
+
+ @http.route(['''/event/<model("event.event"):event>/track/<model("event.track", "[('event_id','=',event.id)]"):track>'''], type='http', auth="public", website=True, sitemap=True)
+ def event_track_view(self, event, track, **post):
+ if not event.can_access_from_current_website():
+ raise NotFound()
+
+ track = track.sudo().with_context(tz=event.date_tz or 'UTC')
+ values = {'track': track, 'event': track.event_id, 'main_object': track}
+ return request.render("website_event_track.track_view", values)
+
+ @http.route("/event/track/toggle_reminder", type="json", auth="public", website=True)
+ def track_reminder_toggle(self, track_id, set_reminder_on):
+ """ Set a reminder a track for current visitor. Track visitor is created or updated
+ if it already exists. Exception made if un-wishlisting and no track_visitor
+ record found (should not happen unless manually done).
+
+ :param boolean set_reminder_on:
+ If True, set as a wishlist, otherwise un-wishlist track;
+ If the track is a Key Track (wishlisted_by_default):
+ if set_reminder_on = False, blacklist the track_partner
+ otherwise, un-blacklist the track_partner
+ """
+ track = self._fetch_track(track_id, allow_is_accepted=True)
+ force_create = set_reminder_on or track.wishlisted_by_default
+ event_track_partner = track._get_event_track_visitors(force_create=force_create)
+ visitor_sudo = event_track_partner.visitor_id
+
+ if not track.wishlisted_by_default:
+ if not event_track_partner or event_track_partner.is_wishlisted == set_reminder_on: # ignore if new state = old state
+ return {'error': 'ignored'}
+ event_track_partner.is_wishlisted = set_reminder_on
+ else:
+ if not event_track_partner or event_track_partner.is_blacklisted != set_reminder_on: # ignore if new state = old state
+ return {'error': 'ignored'}
+ event_track_partner.is_blacklisted = not set_reminder_on
+
+ result = {'reminderOn': set_reminder_on}
+ if request.httprequest.cookies.get('visitor_uuid', '') != visitor_sudo.access_token:
+ result['visitor_uuid'] = visitor_sudo.access_token
+
+ return result
+
+ # ------------------------------------------------------------
+ # TRACK PROPOSAL
+ # ------------------------------------------------------------
+
+ @http.route(['''/event/<model("event.event"):event>/track_proposal'''], type='http', auth="public", website=True, sitemap=False)
+ def event_track_proposal(self, event, **post):
+ if not event.can_access_from_current_website():
+ raise NotFound()
+
+ return request.render("website_event_track.event_track_proposal", {'event': event, 'main_object': event})
+
+ @http.route(['''/event/<model("event.event"):event>/track_proposal/post'''], type='http', auth="public", methods=['POST'], website=True)
+ def event_track_proposal_post(self, event, **post):
+ if not event.can_access_from_current_website():
+ raise NotFound()
+
+ tags = []
+ for tag in event.allowed_track_tag_ids:
+ if post.get('tag_' + str(tag.id)):
+ tags.append(tag.id)
+
+ track = request.env['event.track'].sudo().create({
+ 'name': post['track_name'],
+ 'partner_name': post['partner_name'],
+ 'partner_email': post['email_from'],
+ 'partner_phone': post['phone'],
+ 'partner_biography': plaintext2html(post['biography']),
+ 'event_id': event.id,
+ 'tag_ids': [(6, 0, tags)],
+ 'user_id': False,
+ 'description': plaintext2html(post['description']),
+ 'image': base64.b64encode(post['image'].read()) if post.get('image') else False
+ })
+ if request.env.user != request.website.user_id:
+ track.sudo().message_subscribe(partner_ids=request.env.user.partner_id.ids)
+ else:
+ partner = request.env['res.partner'].sudo().search([('email', '=', post['email_from'])])
+ if partner:
+ track.sudo().message_subscribe(partner_ids=partner.ids)
+ return request.render("website_event_track.event_track_proposal", {'track': track, 'event': event})
+
+ # ------------------------------------------------------------
+ # TOOLS
+ # ------------------------------------------------------------
+
+ def _fetch_track(self, track_id, allow_is_accepted=False):
+ track = request.env['event.track'].browse(track_id).exists()
+ if not track:
+ raise NotFound()
+ try:
+ track.check_access_rights('read')
+ track.check_access_rule('read')
+ except exceptions.AccessError:
+ track_sudo = track.sudo()
+ if allow_is_accepted and track_sudo.is_accepted:
+ track = track_sudo
+ else:
+ raise Forbidden()
+
+ event = track.event_id
+ # JSON RPC have no website in requests
+ if hasattr(request, 'website_id') and not event.can_access_from_current_website():
+ raise NotFound()
+ try:
+ event.check_access_rights('read')
+ event.check_access_rule('read')
+ except exceptions.AccessError:
+ raise Forbidden()
+
+ return track
diff --git a/addons/website_event_track/controllers/main.py b/addons/website_event_track/controllers/main.py
deleted file mode 100644
index 13477d422b4..00000000000
--- a/addons/website_event_track/controllers/main.py
+++ /dev/null
@@ -1,185 +0,0 @@
-# -*- coding: utf-8 -*-
-# Part of Odoo. See LICENSE file for full copyright and licensing details.
-
-import babel
-import babel.dates
-import collections
-import datetime
-import pytz
-import base64
-from werkzeug.exceptions import NotFound
-
-from odoo import fields, http
-from odoo.http import request
-from odoo.tools import plaintext2html, html2plaintext
-
-
-class WebsiteEventTrackController(http.Controller):
-
- # ------------------------------------------------------------
- # TRACK LIST VIEW
- # ------------------------------------------------------------
-
- @http.route([
- '''/event/<model("event.event"):event>/track''',
- '''/event/<model("event.event"):event>/track/tag/<model("event.track.tag"):tag>'''
- ], type='http', auth="public", website=True, sitemap=False)
- def event_tracks(self, event, tag=None, **post):
- if not event.can_access_from_current_website() or (tag and tag.color == 0):
- raise NotFound()
-
- event = event.with_context(tz=event.date_tz or 'UTC')
- searches = {}
- if tag:
- searches.update(tag=tag.id)
- tracks = event.track_ids.filtered(lambda track: tag in track.tag_ids)
- else:
- tracks = event.track_ids
-
- values = {
- 'event': event,
- 'main_object': event,
- 'tracks': tracks,
- 'tags': event.tracks_tag_ids,
- 'searches': searches,
- 'html2plaintext': html2plaintext
- }
- return request.render("website_event_track.tracks", values)
-
- # ------------------------------------------------------------
- # AGENDA VIEW
- # ------------------------------------------------------------
-
- def _get_locale_time(self, dt_time, lang_code):
- """ Get locale time from datetime object
-
- :param dt_time: datetime object
- :param lang_code: language code (eg. en_US)
- """
- locale = babel.Locale.parse(lang_code)
- return babel.dates.format_time(dt_time, format='short', locale=locale)
-
- def _prepare_calendar(self, event, event_track_ids):
- local_tz = pytz.timezone(event.date_tz or 'UTC')
- lang_code = request.env.context.get('lang')
- locations = {} # { location: [track, start_date, end_date, rowspan]}
- dates = [] # [ (date, {}) ]
- for track in event_track_ids:
- locations.setdefault(track.location_id or False, [])
-
- forcetr = True
- for track in event_track_ids:
- start_date = fields.Datetime.from_string(track.date).replace(tzinfo=pytz.utc).astimezone(local_tz)
- end_date = start_date + datetime.timedelta(hours=(track.duration or 0.5))
- location = track.location_id or False
- locations.setdefault(location, [])
-
- # New TR, align all events
- if forcetr or (start_date>dates[-1][0]) or not location:
- formatted_time = self._get_locale_time(start_date, lang_code)
- dates.append((start_date, {}, bool(location), formatted_time))
- for loc in list(locations):
- if locations[loc] and (locations[loc][-1][2] > start_date):
- locations[loc][-1][3] += 1
- elif not locations[loc] or locations[loc][-1][2] <= start_date:
- locations[loc].append([False, locations[loc] and locations[loc][-1][2] or dates[0][0], start_date, 1])
- dates[-1][1][loc] = locations[loc][-1]
- forcetr = not bool(location)
-
- # Add event
- if locations[location] and locations[location][-1][1] > start_date:
- locations[location][-1][3] -= 1
- locations[location].append([track, start_date, end_date, 1])
- dates[-1][1][location] = locations[location][-1]
- locations = collections.OrderedDict(sorted(locations.items(), key=lambda t: t[0].id if t[0] else 0))
- return {
- 'locations': locations,
- 'dates': dates
- }
-
- @http.route(['''/event/<model("event.event"):event>/agenda'''], type='http', auth="public", website=True, sitemap=False)
- def event_agenda(self, event, tag=None, **post):
- if not event.can_access_from_current_website():
- raise NotFound()
-
- event = event.with_context(tz=event.date_tz or 'UTC')
- local_tz = pytz.timezone(event.date_tz or 'UTC')
- days_tracks = collections.defaultdict(lambda: [])
- event_track_ids = self._event_agenda_get_tracks(event)
- for track in event_track_ids.sorted(lambda track: (bool(track.date), track.date, bool(track.location_id))):
- if not track.date:
- continue
- date = fields.Datetime.from_string(track.date).replace(tzinfo=pytz.utc).astimezone(local_tz)
- days_tracks[str(date)[:10]].append(track)
-
- days = {}
- tracks_by_days = {}
- for day, tracks in days_tracks.items():
- tracks_by_days[day] = tracks
- days[day] = self._prepare_calendar(event, tracks)
-
- return request.render("website_event_track.agenda", {
- 'event': event,
- 'main_object': event,
- 'days': days,
- 'tracks_by_days': tracks_by_days,
- 'tag': tag,
- 'user_event_manager': request.env.user.has_group('event.group_event_manager'),
- })
-
- def _event_agenda_get_tracks(self, event):
- return event.track_ids
-
- # ------------------------------------------------------------
- # TRACK PAGE VIEW
- # ------------------------------------------------------------
-
- @http.route(['''/event/<model("event.event"):event>/track/<model("event.track", "[('event_id','=',event.id)]"):track>'''], type='http', auth="public", website=True, sitemap=True)
- def event_track_view(self, event, track, **post):
- if not event.can_access_from_current_website():
- raise NotFound()
-
- track = track.sudo().with_context(tz=event.date_tz or 'UTC')
- values = {'track': track, 'event': track.event_id, 'main_object': track}
- return request.render("website_event_track.track_view", values)
-
- # ------------------------------------------------------------
- # TRACK PROPOSAL
- # ------------------------------------------------------------
-
- @http.route(['''/event/<model("event.event"):event>/track_proposal'''], type='http', auth="public", website=True, sitemap=False)
- def event_track_proposal(self, event, **post):
- if not event.can_access_from_current_website():
- raise NotFound()
-
- return request.render("website_event_track.event_track_proposal", {'event': event, 'main_object': event})
-
- @http.route(['''/event/<model("event.event"):event>/track_proposal/post'''], type='http', auth="public", methods=['POST'], website=True)
- def event_track_proposal_post(self, event, **post):
- if not event.can_access_from_current_website():
- raise NotFound()
-
- tags = []
- for tag in event.allowed_track_tag_ids:
- if post.get('tag_' + str(tag.id)):
- tags.append(tag.id)
-
- track = request.env['event.track'].sudo().create({
- 'name': post['track_name'],
- 'partner_name': post['partner_name'],
- 'partner_email': post['email_from'],
- 'partner_phone': post['phone'],
- 'partner_biography': plaintext2html(post['biography']),
- 'event_id': event.id,
- 'tag_ids': [(6, 0, tags)],
- 'user_id': False,
- 'description': plaintext2html(post['description']),
- 'image': base64.b64encode(post['image'].read()) if post.get('image') else False
- })
- if request.env.user != request.website.user_id:
- track.sudo().message_subscribe(partner_ids=request.env.user.partner_id.ids)
- else:
- partner = request.env['res.partner'].sudo().search([('email', '=', post['email_from'])])
- if partner:
- track.sudo().message_subscribe(partner_ids=partner.ids)
- return request.render("website_event_track.event_track_proposal", {'track': track, 'event': event})
diff --git a/addons/website_event_track/controllers/webmanifest.py b/addons/website_event_track/controllers/webmanifest.py
new file mode 100644
index 00000000000..a777ff10303
--- /dev/null
+++ b/addons/website_event_track/controllers/webmanifest.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import json
+import pytz
+
+from odoo import http
+from odoo.addons.http_routing.models.ir_http import url_for
+from odoo.http import request
+from odoo.modules.module import get_module_resource
+from odoo.tools import ustr
+from odoo.tools.translate import _
+
+
+class TrackManifest(http.Controller):
+
+ @http.route('/event/manifest.webmanifest', type='http', auth='public', methods=['GET'], website=True, sitemap=False)
+ def webmanifest(self):
+ """ Returns a WebManifest describing the metadata associated with a web application.
+ Using this metadata, user agents can provide developers with means to create user
+ experiences that are more comparable to that of a native application.
+ """
+ company = request.env.company
+ website = request.website
+ manifest = {
+ 'name': _('%s Online Events') % company.name,
+ 'short_name': company.name,
+ 'description': _('%s Online Events') % company.name,
+ 'scope': url_for('/event'),
+ 'start_url': url_for('/event'),
+ 'display': 'standalone',
+ 'background_color': '#ffffff',
+ 'theme_color': '#875A7B',
+ }
+ icon_sizes = ['192x192', '512x512']
+ manifest['icons'] = [{
+ 'src': website.image_url(website, 'app_icon', size=size),
+ 'sizes': size,
+ 'type': 'image/png',
+ } for size in icon_sizes]
+ body = json.dumps(manifest, default=ustr)
+ response = request.make_response(body, [
+ ('Content-Type', 'application/manifest+json'),
+ ])
+ return response
+
+ @http.route('/event/service-worker.js', type='http', auth='public', methods=['GET'], website=True, sitemap=False)
+ def service_worker(self):
+ """ Returns a ServiceWorker javascript file scoped for website_event
+ """
+ sw_file = get_module_resource('website_event_track', 'static/src/js/service_worker.js')
+ with open(sw_file, 'rb') as fp:
+ body = fp.read()
+ response = request.make_response(body, [
+ ('Content-Type', 'text/javascript'),
+ ('Service-Worker-Allowed', url_for('/event')),
+ ])
+ return response