From dc91b69c0bff0818b6dae3c2af097bc2fdafbe69 Mon Sep 17 00:00:00 2001 From: gmariano Date: Sat, 4 Apr 2020 08:11:09 +0200 Subject: [PATCH 01/94] VC/Zoom: Initial Commit --- .gitignore | 84 + MANIFEST.in | 6 + README.md | 7 + indico_vc_zoom/__init__.py | 12 + indico_vc_zoom/api/__init__.py | 7 + indico_vc_zoom/api/client.py | 487 + indico_vc_zoom/blueprint.py | 16 + indico_vc_zoom/cli.py | 35 + indico_vc_zoom/client/index.js | 34 + indico_vc_zoom/controllers.py | 26 + indico_vc_zoom/forms.py | 67 + indico_vc_zoom/http_api.py | 51 + ...20200312_1030_b79318836818_crea_tabella.py | 52 + ...20200403_1957_d86e85a383c1_create_table.py | 66 + ...20200405_1539_d54585a383v1_create_table.py | 46 + indico_vc_zoom/models/__init__.py | 0 indico_vc_zoom/models/zoom_meetings.py | 75 + indico_vc_zoom/plugin.py | 260 + indico_vc_zoom/static/images/zoom_logo.png | Bin 0 -> 207444 bytes indico_vc_zoom/task.py | 70 + indico_vc_zoom/templates/buttons.html | 6 + indico_vc_zoom/templates/emails/created.html | 16 + indico_vc_zoom/templates/emails/deleted.html | 1 + .../templates/emails/notify_start_url.html | 18 + .../templates/emails/remote_deleted.html | 16 + indico_vc_zoom/templates/event_buttons.html | 6 + indico_vc_zoom/templates/info_box.html | 37 + .../templates/manage_event_info_box.html | 55 + .../templates/management_buttons.html | 6 + .../templates/vc_room_timetable_buttons.html | 7 + .../fr_FR/LC_MESSAGES/messages-js.po | 23 + .../fr_FR/LC_MESSAGES/messages.po | 289 + indico_vc_zoom/util.py | 90 + setup.py | 29 + tests/task_test.py | 24 + url_map.json | 30163 ++++++++++++++++ webpack-bundles.json | 5 + 37 files changed, 32192 insertions(+) create mode 100755 .gitignore create mode 100644 MANIFEST.in create mode 100644 README.md create mode 100644 indico_vc_zoom/__init__.py create mode 100644 indico_vc_zoom/api/__init__.py create mode 100644 indico_vc_zoom/api/client.py create mode 100644 indico_vc_zoom/blueprint.py create mode 100644 indico_vc_zoom/cli.py create mode 100644 indico_vc_zoom/client/index.js create mode 100644 indico_vc_zoom/controllers.py create mode 100644 indico_vc_zoom/forms.py create mode 100644 indico_vc_zoom/http_api.py create mode 100644 indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py create mode 100644 indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py create mode 100644 indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py create mode 100644 indico_vc_zoom/models/__init__.py create mode 100644 indico_vc_zoom/models/zoom_meetings.py create mode 100644 indico_vc_zoom/plugin.py create mode 100644 indico_vc_zoom/static/images/zoom_logo.png create mode 100644 indico_vc_zoom/task.py create mode 100644 indico_vc_zoom/templates/buttons.html create mode 100644 indico_vc_zoom/templates/emails/created.html create mode 100644 indico_vc_zoom/templates/emails/deleted.html create mode 100644 indico_vc_zoom/templates/emails/notify_start_url.html create mode 100644 indico_vc_zoom/templates/emails/remote_deleted.html create mode 100644 indico_vc_zoom/templates/event_buttons.html create mode 100644 indico_vc_zoom/templates/info_box.html create mode 100644 indico_vc_zoom/templates/manage_event_info_box.html create mode 100644 indico_vc_zoom/templates/management_buttons.html create mode 100644 indico_vc_zoom/templates/vc_room_timetable_buttons.html create mode 100644 indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po create mode 100644 indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po create mode 100644 indico_vc_zoom/util.py create mode 100644 setup.py create mode 100644 tests/task_test.py create mode 100644 url_map.json create mode 100644 webpack-bundles.json diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..fc6d642 --- /dev/null +++ b/.gitignore @@ -0,0 +1,84 @@ +.vscode/ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +venv/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/build/ +docs/source/generated/ + +# pytest +.pytest_cache/ + +# PyBuilder +target/ + +# Editor files +#mac +.DS_Store +*~ + +#vim +*.swp +*.swo + +#pycharm +.idea/* + + +#Ipython Notebook +.ipynb_checkpoints + + +webpack-build-config.json \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..facfb9e --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,6 @@ +graft indico_vc_zoom/static +graft indico_vc_zoom/migrations +graft indico_vc_zoom/templates +graft indico_vc_zoom/translations + +global-exclude *.pyc __pycache__ .keep diff --git a/README.md b/README.md new file mode 100644 index 0000000..4b220a0 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +Indico Plugin for Zoom based on Vidyo plugin. + +To obtain Api key and api secret, please visit [https://marketplace.zoom.us/docs/guides/auth/jwt](https://marketplace.zoom.us/docs/guides/auth/jwt) + +Not ready for production. + +Developed by Giovanni Mariano @ ENEA Frascati diff --git a/indico_vc_zoom/__init__.py b/indico_vc_zoom/__init__.py new file mode 100644 index 0000000..22dd971 --- /dev/null +++ b/indico_vc_zoom/__init__.py @@ -0,0 +1,12 @@ +from __future__ import unicode_literals + +from indico.core import signals +from indico.util.i18n import make_bound_gettext + + +_ = make_bound_gettext('vc_zoom') + + +@signals.import_tasks.connect +def _import_tasks(sender, **kwargs): + import indico_vc_zoom.task diff --git a/indico_vc_zoom/api/__init__.py b/indico_vc_zoom/api/__init__.py new file mode 100644 index 0000000..bba1dbe --- /dev/null +++ b/indico_vc_zoom/api/__init__.py @@ -0,0 +1,7 @@ + + + +from .client import ZoomIndicoClient, APIException, RoomNotFoundAPIException, ZoomClient + + +__all__ = ['ZoomIndicoClient', 'APIException', 'RoomNotFoundAPIException', 'ZoomClient'] diff --git a/indico_vc_zoom/api/client.py b/indico_vc_zoom/api/client.py new file mode 100644 index 0000000..b9ad131 --- /dev/null +++ b/indico_vc_zoom/api/client.py @@ -0,0 +1,487 @@ +from __future__ import absolute_import, unicode_literals +from requests import Session +from requests.auth import HTTPBasicAuth + +import contextlib +import json +import requests +import time +import jwt + + +class ApiClient(object): + """Simple wrapper for REST API requests""" + + def __init__(self, base_uri=None, timeout=15, **kwargs): + """Setup a new API Client + + :param base_uri: The base URI to the API + :param timeout: The timeout to use for requests + :param kwargs: Any other attributes. These will be added as + attributes to the ApiClient object. + """ + self.base_uri = base_uri + self.timeout = timeout + for k, v in kwargs.items(): + setattr(self, k, v) + + @property + def timeout(self): + """The timeout""" + return self._timeout + + @timeout.setter + def timeout(self, value): + """The default timeout""" + if value is not None: + try: + value = int(value) + except ValueError: + raise ValueError("timeout value must be an integer") + self._timeout = value + + @property + def base_uri(self): + """The base_uri""" + return self._base_uri + + @base_uri.setter + def base_uri(self, value): + """The default base_uri""" + if value and value.endswith("/"): + value = value[:-1] + self._base_uri = value + + def url_for(self, endpoint): + """Get the URL for the given endpoint + + :param endpoint: The endpoint + :return: The full URL for the endpoint + """ + if not endpoint.startswith("/"): + endpoint = "/{}".format(endpoint) + if endpoint.endswith("/"): + endpoint = endpoint[:-1] + return self.base_uri + endpoint + + def get_request(self, endpoint, params=None, headers=None): + """Helper function for GET requests + + :param endpoint: The endpoint + :param params: The URL parameters + :param headers: request headers + :return: The :class:``requests.Response`` object for this request + """ + if headers is None: + headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} + return requests.get( + self.url_for(endpoint), params=params, headers=headers, timeout=self.timeout + ) + + def post_request( + self, endpoint, params=None, data=None, headers=None, cookies=None + ): + """Helper function for POST requests + + :param endpoint: The endpoint + :param params: The URL parameters + :param data: The data (either as a dict or dumped JSON string) to + include with the POST + :param headers: request headers + :param cookies: request cookies + :return: The :class:``requests.Response`` object for this request + """ + if data and not is_str_type(data): + data = json.dumps(data) + if headers is None: + headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} + return requests.post( + self.url_for(endpoint), + params=params, + data=data, + headers=headers, + cookies=cookies, + timeout=self.timeout, + ) + + def patch_request( + self, endpoint, params=None, data=None, headers=None, cookies=None + ): + """Helper function for PATCH requests + + :param endpoint: The endpoint + :param params: The URL parameters + :param data: The data (either as a dict or dumped JSON string) to + include with the PATCH + :param headers: request headers + :param cookies: request cookies + :return: The :class:``requests.Response`` object for this request + """ + if data and not is_str_type(data): + data = json.dumps(data) + if headers is None: + headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} + return requests.patch( + self.url_for(endpoint), + params=params, + data=data, + headers=headers, + cookies=cookies, + timeout=self.timeout, + ) + + def delete_request( + self, endpoint, params=None, data=None, headers=None, cookies=None + ): + """Helper function for DELETE requests + + :param endpoint: The endpoint + :param params: The URL parameters + :param data: The data (either as a dict or dumped JSON string) to + include with the DELETE + :param headers: request headers + :param cookies: request cookies + :return: The :class:``requests.Response`` object for this request + """ + if data and not is_str_type(data): + data = json.dumps(data) + if headers is None: + headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} + return requests.delete( + self.url_for(endpoint), + params=params, + data=data, + headers=headers, + cookies=cookies, + timeout=self.timeout, + ) + + def put_request(self, endpoint, params=None, data=None, headers=None, cookies=None): + """Helper function for PUT requests + + :param endpoint: The endpoint + :param params: The URL paramaters + :param data: The data (either as a dict or dumped JSON string) to + include with the PUT + :param headers: request headers + :param cookies: request cookies + :return: The :class:``requests.Response`` object for this request + """ + if data and not is_str_type(data): + data = json.dumps(data) + if headers is None: + headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} + return requests.put( + self.url_for(endpoint), + params=params, + data=data, + headers=headers, + cookies=cookies, + timeout=self.timeout, + ) + + +@contextlib.contextmanager +def ignored(*exceptions): + """Simple context manager to ignore expected Exceptions + + :param \*exceptions: The exceptions to safely ignore + """ + try: + yield + except exceptions: + pass + + +def is_str_type(val): + """Check whether the input is of a string type. + + We use this method to ensure python 2-3 capatibility. + + :param val: The value to check wither it is a string + :return: In python2 it will return ``True`` if :attr:`val` is either an + instance of str or unicode. In python3 it will return ``True`` if + it is an instance of str + """ + with ignored(NameError): + return isinstance(val, basestring) + return isinstance(val, str) + + +def require_keys(d, keys, allow_none=True): + """Require that the object have the given keys + + :param d: The dict the check + :param keys: The keys to check :attr:`obj` for. This can either be a single + string, or an iterable of strings + + :param allow_none: Whether ``None`` values are allowed + :raises: + :ValueError: If any of the keys are missing from the obj + """ + if is_str_type(keys): + keys = [keys] + for k in keys: + if k not in d: + raise ValueError("'{}' must be set".format(k)) + if not allow_none and d[k] is None: + raise ValueError("'{}' cannot be None".format(k)) + return True + + +def date_to_str_gmt(d): + """Convert date and datetime objects to a string + + Note, this does not do any timezone conversion. + + :param d: The :class:`datetime.date` or :class:`datetime.datetime` to + convert to a string + :returns: The string representation of the date + """ + return d.strftime("%Y-%m-%dT%H:%M:%SZ") + +def date_to_str_local(d): + """Convert date and datetime objects to a string + + Note, this does not do any timezone conversion. + + :param d: The :class:`datetime.date` or :class:`datetime.datetime` to + convert to a string + :returns: The string representation of the date + """ + return d.strftime("%Y-%m-%dT%H:%M:%S") + + +def generate_jwt(key, secret): + header = {"alg": "HS256", "typ": "JWT"} + + payload = {"iss": key, "exp": int(time.time() + 3600)} + + token = jwt.encode(payload, secret, algorithm="HS256", headers=header) + return token.decode("utf-8") + + + + + +class APIException(Exception): + pass + + +class RoomNotFoundAPIException(APIException): + pass + + + + + +class BaseComponent(ApiClient): + """A base component""" + + def __init__(self, base_uri=None, config=None, timeout=15, **kwargs): + """Setup a base component + + :param base_uri: The base URI to the API + :param config: The config details + :param timeout: The timeout to use for requests + :param kwargs: Any other attributes. These will be added as + attributes to the ApiClient object. + """ + super(BaseComponent, self).__init__( + base_uri=base_uri, timeout=timeout, config=config, **kwargs + ) + + def post_request( + self, endpoint, params=None, data=None, headers=None, cookies=None + ): + """Helper function for POST requests + + Since the Zoom.us API only uses POST requests and each post request + must include all of the config data, this method ensures that all + of that data is there + + :param endpoint: The endpoint + :param params: The URL parameters + :param data: The data (either as a dict or dumped JSON string) to + include with the POST + :param headers: request headers + :param cookies: request cookies + :return: The :class:``requests.Response`` object for this request + """ + params = params or {} + if headers is None: + headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} + return super(BaseComponent, self).post_request( + endpoint, params=params, data=data, headers=headers, cookies=cookies + ) + +class MeetingComponent(BaseComponent): + def list(self, **kwargs): + require_keys(kwargs, "user_id") + return self.get_request( + "/users/{}/meetings".format(kwargs.get("user_id")), params=kwargs + ) + + def create(self, **kwargs): + require_keys(kwargs, "user_id") + if kwargs.get("start_time"): + if kwargs.get("timezone"): + kwargs["start_time"] = date_to_str_local(kwargs["start_time"]) + else: + kwargs["start_time"] = date_to_str_gmt(kwargs["start_time"]) + return self.post_request( + "/users/{}/meetings".format(kwargs.get("user_id")), params=kwargs['user_id'], data={x: kwargs[x] for x in kwargs.keys() if x not in ['user_id']} + ) + + def get(self, **kwargs): + require_keys(kwargs, "id") + return self.get_request("/meetings/{}".format(kwargs.get("id")), params=kwargs) + + def update(self, **kwargs): + require_keys(kwargs, "id") + if kwargs.get("start_time"): + if kwargs.get("timezone"): + kwargs["start_time"] = date_to_str_local(kwargs["start_time"]) + else: + kwargs["start_time"] = date_to_str_gmt(kwargs["start_time"]) + return self.patch_request( + "/meetings/{}".format(kwargs.get("id")), params=kwargs + ) + + def delete(self, **kwargs): + require_keys(kwargs, "id") + return self.delete_request( + "/meetings/{}".format(kwargs.get("id")), params=kwargs + ) + + def get_invitation(self, **kwargs): + require_keys(kwargs, "id") + return self.get_request("/meetings/{}/invitation".format(kwargs.get("id")), params=kwargs) + + +class UserComponent(BaseComponent): + def list(self, **kwargs): + return self.get_request("/users", params=kwargs) + + def create(self, **kwargs): + return self.post_request("/users", params=kwargs) + + def update(self, **kwargs): + require_keys(kwargs, "id") + return self.patch_request("/users/{}".format(kwargs.get("id")), params=kwargs) + + def delete(self, **kwargs): + require_keys(kwargs, "id") + return self.delete_request("/users/{}".format(kwargs.get("id")), params=kwargs) + + def get(self, **kwargs): + require_keys(kwargs, "id") + return self.get_request("/users/{}".format(kwargs.get("id")), params=kwargs) + + + +class ZoomClient(ApiClient): + """Zoom.us REST API Python Client""" + + """Base URL for Zoom API""" + + def __init__( + self, api_key, api_secret, data_type="json", timeout=15 + ): + """Create a new Zoom client + + :param api_key: The Zooom.us API key + :param api_secret: The Zoom.us API secret + :param data_type: The expected return data type. Either 'json' or 'xml' + :param timeout: The time out to use for API requests + """ + + BASE_URI = "https://api.zoom.us/v2" + self.components = {"user": UserComponent, + "meeting": MeetingComponent} + + super(ZoomClient, self).__init__(base_uri=BASE_URI, timeout=timeout) + + # Setup the config details + self.config = { + "api_key": api_key, + "api_secret": api_secret, + "data_type": data_type, + "token": generate_jwt(api_key, api_secret), + } + + # Instantiate the components + for key in self.components.keys(): + self.components[key] = self.components[key]( + base_uri=BASE_URI, config=self.config + ) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + return + + def refresh_token(self): + self.config["token"] = ( + generate_jwt(self.config["api_key"], self.config["api_secret"]), + ) + + @property + def api_key(self): + """The Zoom.us api_key""" + return self.config.get("api_key") + + @api_key.setter + def api_key(self, value): + """Set the api_key""" + self.config["api_key"] = value + self.refresh_token() + + @property + def api_secret(self): + """The Zoom.us api_secret""" + return self.config.get("api_secret") + + @api_secret.setter + def api_secret(self, value): + """Set the api_secret""" + self.config["api_secret"] = value + self.refresh_token() + + @property + def meeting(self): + """Get the meeting component""" + return self.components.get("meeting") + + @property + def user(self): + """Get the user component""" + return self.components.get("user") + + + +class ZoomIndicoClient(object): + def __init__(self, settings): + api_key=settings.get('api_key') + api_secret=settings.get('api_secret') + self.client=ZoomClient(api_key, api_secret) + + def create_meeting(self, **kwargs): + return json.loads(self.client.meeting.create(**kwargs).content) + + + def get_meeting(self, zoom_id): + return json.loads(self.client.meeting.get(id=zoom_id).content) + + + def get_meeting_invitation(self, zoom_id): + return json.loads(self.client.meeting.get_invitation(id=zoom_id).content) + + def delete_meeting(self, zoom_id): + self.client.meeting.delete(id=zoom_id) + + def check_user_meeting_time(self, userID, start_dt, end_dt): + pass + + diff --git a/indico_vc_zoom/blueprint.py b/indico_vc_zoom/blueprint.py new file mode 100644 index 0000000..e29b2d6 --- /dev/null +++ b/indico_vc_zoom/blueprint.py @@ -0,0 +1,16 @@ + + +from __future__ import unicode_literals + +from indico.core.plugins import IndicoPluginBlueprint + +from indico_vc_zoom.controllers import RHZoomRoomOwner + + +blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') + +# Room management +# using any(zoom) instead of defaults since the event vc room locator +# includes the service and normalization skips values provided in 'defaults' +blueprint.add_url_rule('/event//manage/videoconference///room-owner', + 'set_room_owner', RHZoomRoomOwner, methods=('POST',)) diff --git a/indico_vc_zoom/cli.py b/indico_vc_zoom/cli.py new file mode 100644 index 0000000..c5f57c2 --- /dev/null +++ b/indico_vc_zoom/cli.py @@ -0,0 +1,35 @@ + + +from __future__ import unicode_literals + +import click +from terminaltables import AsciiTable + +from indico.cli.core import cli_group +from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomStatus + + +@cli_group(name='zoom') +def cli(): + """Manage the Zoom plugin.""" + + +@cli.command() +@click.option('--status', type=click.Choice(['deleted', 'created'])) +def rooms(status=None): + """Lists all Zoom rooms""" + + room_query = VCRoom.find(type='zoom') + table_data = [['ID', 'Name', 'Status', 'Zoom ID', 'Meeting']] + + if status: + room_query = room_query.filter(VCRoom.status == VCRoomStatus.get(status)) + + for room in room_query: + table_data.append([unicode(room.id), room.name, room.status.name, + unicode(room.data['zoom_id']), unicode(room.zoom_meeting.meeting)]) + + table = AsciiTable(table_data) + for col in (0, 3, 4): + table.justify_columns[col] = 'right' + print table.table diff --git a/indico_vc_zoom/client/index.js b/indico_vc_zoom/client/index.js new file mode 100644 index 0000000..361049b --- /dev/null +++ b/indico_vc_zoom/client/index.js @@ -0,0 +1,34 @@ +// This file is part of the Indico plugins. +// Copyright (C) 2002 - 2019 CERN +// +// The Indico plugins are free software; you can redistribute +// them and/or modify them under the terms of the MIT License; +// see the LICENSE file for more details. + +$(function() { + $('.vc-toolbar').dropdown({ + positioning: { + level1: {my: 'right top', at: 'right bottom', offset: '0px 0px'}, + }, + }); + + $('.vc-toolbar .action-make-owner').click(function() { + const $this = $(this); + + $.ajax({ + url: $this.data('href'), + method: 'POST', + complete: IndicoUI.Dialogs.Util.progress(), + }) + .done(function(result) { + if (handleAjaxError(result)) { + return; + } else { + location.reload(); + } + }) + .fail(function(error) { + handleAjaxError(error); + }); + }); +}); diff --git a/indico_vc_zoom/controllers.py b/indico_vc_zoom/controllers.py new file mode 100644 index 0000000..5b46443 --- /dev/null +++ b/indico_vc_zoom/controllers.py @@ -0,0 +1,26 @@ + + +from __future__ import unicode_literals + +from flask import flash, jsonify, session + +from indico.core.db import db +from indico.modules.vc.controllers import RHVCSystemEventBase +from indico.modules.vc.exceptions import VCRoomError +from indico.util.i18n import _ + + +class RHZoomRoomOwner(RHVCSystemEventBase): + def _process(self): + result = {} + self.vc_room.zoom_meeting.owned_by_user = session.user + try: + self.plugin.update_room(self.vc_room, self.event) + except VCRoomError as err: + result['error'] = {'message': err.message} + result['success'] = False + db.session.rollback() + else: + flash(_("You are now the owner of the room '{room.name}'".format(room=self.vc_room)), 'success') + result['success'] = True + return jsonify(result) diff --git a/indico_vc_zoom/forms.py b/indico_vc_zoom/forms.py new file mode 100644 index 0000000..0b6e195 --- /dev/null +++ b/indico_vc_zoom/forms.py @@ -0,0 +1,67 @@ + + +from __future__ import unicode_literals +from flask import session + +from wtforms.fields.core import BooleanField +from wtforms.fields.simple import TextAreaField, HiddenField +from wtforms.validators import DataRequired, Length, Optional, Regexp, ValidationError + +from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase +from indico.web.forms.base import generated_data +from indico.web.forms.fields import IndicoPasswordField, PrincipalField +from indico.web.forms.widgets import SwitchWidget + +from indico_vc_zoom import _ +from indico_vc_zoom.util import iter_user_identities, retrieve_principal + + +PIN_VALIDATORS = [Optional(), Length(min=3, max=10), Regexp(r'^\d+$', message=_("The PIN must be a number"))] + + +class ZoomAdvancedFormMixin(object): + # Advanced options (per event) + + show_autojoin = BooleanField(_('Show Auto-join URL'), + widget=SwitchWidget(), + description=_("Show the auto-join URL on the event page")) + show_phone_numbers = BooleanField(_('Show Phone Access numbers'), + widget=SwitchWidget(), + description=_("Show a link to the list of phone access numbers")) + + +class VCRoomAttachForm(VCRoomAttachFormBase, ZoomAdvancedFormMixin): + pass + + +class VCRoomForm(VCRoomFormBase, ZoomAdvancedFormMixin): + """Contains all information concerning a Zoom booking""" + + advanced_fields = {'show_autojoin', 'show_phone_numbers'} | VCRoomFormBase.advanced_fields + skip_fields = advanced_fields | VCRoomFormBase.conditional_fields + + description = TextAreaField(_('Description'), [DataRequired()], description=_('The description of the room')) + #owner_user = PrincipalField(_('Owner'), [DataRequired()], description=_('The owner of the room')) + #owner_user = HiddenField(default=session.user) + #moderation_pin = IndicoPasswordField(_('Moderation PIN'), PIN_VALIDATORS, toggle=True, + # description=_('Used to moderate the VC Room. Only digits allowed.')) + #room_pin = IndicoPasswordField(_('Room PIN'), PIN_VALIDATORS, toggle=True, + # description=_('Used to protect the access to the VC Room (leave blank for open ' + # 'access). Only digits allowed.')) + + + def __init__(self, *args, **kwargs): + defaults = kwargs['obj'] + if defaults.owner_user is None and defaults.owner is not None: + defaults.owner_user = retrieve_principal(defaults.owner) + super(VCRoomForm, self).__init__(*args, **kwargs) + + #@generated_data + #def owner(self): + # return self.owner_user.data.default + + def validate_owner_user(self, field): + if not field.data: + raise ValidationError(_("Unable to find this user in Indico.")) + #if not next(iter_user_identities(field.data), None): + # raise ValidationError(_("This user does not have a suitable account to use Zoom.")) diff --git a/indico_vc_zoom/http_api.py b/indico_vc_zoom/http_api.py new file mode 100644 index 0000000..7c53d69 --- /dev/null +++ b/indico_vc_zoom/http_api.py @@ -0,0 +1,51 @@ + + +from flask import request + +from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomStatus +from indico.web.http_api.hooks.base import HTTPAPIHook + + +class DeleteVCRoomAPI(HTTPAPIHook): + PREFIX = 'api' + TYPES = ('deletevcroom',) + RE = r'zoom' + GUEST_ALLOWED = False + VALID_FORMATS = ('json',) + COMMIT = True + HTTP_POST = True + + def _has_access(self, user): + from indico_vc_zoom.plugin import ZoomPlugin + return user in ZoomPlugin.settings.acls.get('managers') + + def _getParams(self): + super(DeleteVCRoomAPI, self)._getParams() + self._room_ids = map(int, request.form.getlist('rid')) + + def api_deletevcroom(self, user): + from indico_vc_zoom.plugin import ZoomPlugin + from indico_vc_zoom.api import APIException + + success = [] + failed = [] + not_in_db = [] + + for rid in self._room_ids: + room = VCRoom.query.filter(VCRoom.type == 'zoom', + VCRoom.status == VCRoomStatus.created, + VCRoom.data.contains({'zoom_id': str(rid)})).first() + if not room: + not_in_db.append(rid) + continue + try: + room.plugin.delete_meeting(room, None) + except APIException: + failed.append(rid) + ZoomPlugin.logger.exception('Could not delete VC room %s', room) + else: + room.status = VCRoomStatus.deleted + success.append(rid) + ZoomPlugin.logger.info('%s deleted', room) + + return {'success': success, 'failed': failed, 'missing': not_in_db} diff --git a/indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py b/indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py new file mode 100644 index 0000000..c865a47 --- /dev/null +++ b/indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py @@ -0,0 +1,52 @@ +"""crea tabella + +Revision ID: b79318836818 +Revises: +Create Date: 2020-03-12 10:30:09.256157 +""" + +import sqlalchemy as sa +from alembic import op + +from sqlalchemy.sql.ddl import CreateSchema, DropSchema + + +# revision identifiers, used by Alembic. +revision = 'b79318836818' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute(CreateSchema('plugin_vc_zoom')) + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('zoom_extensions', + sa.Column('vc_room_id', sa.Integer(), nullable=False), + sa.Column('url_zoom', sa.Text(), nullable=False), + sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=op.f('fk_zoom_extensions_vc_room_id_vc_rooms')), + sa.PrimaryKeyConstraint('vc_room_id', name=op.f('pk_zoom_extensions')), + schema='plugin_vc_zoom' + ) + op.create_index(op.f('ix_zoom_extensions_url_zoom'), 'zoom_extensions', ['url_zoom'], unique=False, schema='plugin_vc_zoom') + op.create_table('zoom_licenses', + sa.Column('id', sa.Integer(), nullable=False), + sa.Column('license_id', sa.Text(), nullable=False), + sa.Column('license_name', sa.Text(), nullable=False), + sa.PrimaryKeyConstraint('id', name=op.f('pk_zoom_licenses')), + schema='plugin_vc_zoom' + ) + op.create_index(op.f('ix_uq_zoom_licenses_license_id'), 'zoom_licenses', ['license_id'], unique=True, schema='plugin_vc_zoom') + op.create_index(op.f('ix_zoom_licenses_license_name'), 'zoom_licenses', ['license_name'], unique=False, schema='plugin_vc_zoom') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_zoom_licenses_license_name'), table_name='zoom_licenses', schema='plugin_vc_zoom') + op.drop_index(op.f('ix_uq_zoom_licenses_license_id'), table_name='zoom_licenses', schema='plugin_vc_zoom') + op.drop_table('zoom_licenses', schema='plugin_vc_zoom') + op.drop_index(op.f('ix_zoom_extensions_url_zoom'), table_name='zoom_extensions', schema='plugin_vc_zoom') + op.drop_table('zoom_extensions', schema='plugin_vc_zoom') + # ### end Alembic commands ### + op.execute(DropSchema('plugin_vc_zoom')) diff --git a/indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py b/indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py new file mode 100644 index 0000000..399511d --- /dev/null +++ b/indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py @@ -0,0 +1,66 @@ +"""create table + +Revision ID: d86e85a383c1 +Revises: b79318836818 +Create Date: 2020-04-03 19:57:35.771416 +""" + +import sqlalchemy as sa +from alembic import op + + + +# revision identifiers, used by Alembic. +revision = 'd86e85a383c1' +down_revision = 'b79318836818' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('zoom_meetings', + sa.Column('vc_room_id', sa.Integer(), nullable=False), + sa.Column('meeting', sa.BigInteger(), nullable=True), + sa.Column('url_zoom', sa.Text(), nullable=False), + sa.Column('owned_by_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['owned_by_id'], [u'users.users.id'], name=op.f('fk_zoom_meetings_owned_by_id_users')), + sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=op.f('fk_zoom_meetings_vc_room_id_vc_rooms')), + sa.PrimaryKeyConstraint('vc_room_id', name=op.f('pk_zoom_meetings')), + schema='plugin_vc_zoom' + ) + op.create_index(op.f('ix_zoom_meetings_meeting'), 'zoom_meetings', ['meeting'], unique=False, schema='plugin_vc_zoom') + op.create_index(op.f('ix_zoom_meetings_owned_by_id'), 'zoom_meetings', ['owned_by_id'], unique=False, schema='plugin_vc_zoom') + op.create_index(op.f('ix_zoom_meetings_url_zoom'), 'zoom_meetings', ['url_zoom'], unique=False, schema='plugin_vc_zoom') + op.drop_index('ix_zoom_extensions_url_zoom', table_name='zoom_extensions', schema='plugin_vc_zoom') + op.drop_table('zoom_extensions', schema='plugin_vc_zoom') + op.drop_index('ix_uq_zoom_licenses_license_id', table_name='zoom_licenses', schema='plugin_vc_zoom') + op.drop_index('ix_zoom_licenses_license_name', table_name='zoom_licenses', schema='plugin_vc_zoom') + op.drop_table('zoom_licenses', schema='plugin_vc_zoom') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('zoom_licenses', + sa.Column('id', sa.INTEGER(), server_default=sa.text(u"nextval('plugin_vc_zoom.zoom_licenses_id_seq'::regclass)"), autoincrement=True, nullable=False), + sa.Column('license_id', sa.TEXT(), autoincrement=False, nullable=False), + sa.Column('license_name', sa.TEXT(), autoincrement=False, nullable=False), + sa.PrimaryKeyConstraint('id', name=u'pk_zoom_licenses'), + schema='plugin_vc_zoom' + ) + op.create_index('ix_zoom_licenses_license_name', 'zoom_licenses', ['license_name'], unique=False, schema='plugin_vc_zoom') + op.create_index('ix_uq_zoom_licenses_license_id', 'zoom_licenses', ['license_id'], unique=True, schema='plugin_vc_zoom') + op.create_table('zoom_extensions', + sa.Column('vc_room_id', sa.INTEGER(), autoincrement=False, nullable=False), + sa.Column('url_zoom', sa.TEXT(), autoincrement=False, nullable=False), + sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=u'fk_zoom_extensions_vc_room_id_vc_rooms'), + sa.PrimaryKeyConstraint('vc_room_id', name=u'pk_zoom_extensions'), + schema='plugin_vc_zoom' + ) + op.create_index('ix_zoom_extensions_url_zoom', 'zoom_extensions', ['url_zoom'], unique=False, schema='plugin_vc_zoom') + op.drop_index(op.f('ix_zoom_meetings_url_zoom'), table_name='zoom_meetings', schema='plugin_vc_zoom') + op.drop_index(op.f('ix_zoom_meetings_owned_by_id'), table_name='zoom_meetings', schema='plugin_vc_zoom') + op.drop_index(op.f('ix_zoom_meetings_meeting'), table_name='zoom_meetings', schema='plugin_vc_zoom') + op.drop_table('zoom_meetings', schema='plugin_vc_zoom') + # ### end Alembic commands ### diff --git a/indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py b/indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py new file mode 100644 index 0000000..15afd8f --- /dev/null +++ b/indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py @@ -0,0 +1,46 @@ +"""create table + +Revision ID: d54585a383v1 +Revises: b79318836818 +Create Date: 2020-04-05 15:39:35.771416 +""" + +import sqlalchemy as sa +from alembic import op + +from sqlalchemy.sql.ddl import CreateSchema, DropSchema + +# revision identifiers, used by Alembic. +revision = 'd54585a383v1' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.execute(CreateSchema('plugin_vc_zoom')) + op.create_table('zoom_meetings', + sa.Column('vc_room_id', sa.Integer(), nullable=False), + sa.Column('meeting', sa.BigInteger(), nullable=True), + sa.Column('url_zoom', sa.Text(), nullable=False), + sa.Column('owned_by_id', sa.Integer(), nullable=False), + sa.ForeignKeyConstraint(['owned_by_id'], [u'users.users.id'], name=op.f('fk_zoom_meetings_owned_by_id_users')), + sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=op.f('fk_zoom_meetings_vc_room_id_vc_rooms')), + sa.PrimaryKeyConstraint('vc_room_id', name=op.f('pk_zoom_meetings')), + schema='plugin_vc_zoom' + ) + op.create_index(op.f('ix_zoom_meetings_meeting'), 'zoom_meetings', ['meeting'], unique=False, schema='plugin_vc_zoom') + op.create_index(op.f('ix_zoom_meetings_owned_by_id'), 'zoom_meetings', ['owned_by_id'], unique=False, schema='plugin_vc_zoom') + op.create_index(op.f('ix_zoom_meetings_url_zoom'), 'zoom_meetings', ['url_zoom'], unique=False, schema='plugin_vc_zoom') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index(op.f('ix_zoom_meetings_url_zoom'), table_name='zoom_meetings', schema='plugin_vc_zoom') + op.drop_index(op.f('ix_zoom_meetings_owned_by_id'), table_name='zoom_meetings', schema='plugin_vc_zoom') + op.drop_index(op.f('ix_zoom_meetings_meeting'), table_name='zoom_meetings', schema='plugin_vc_zoom') + op.drop_table('zoom_meetings', schema='plugin_vc_zoom') + op.execute(DropSchema('plugin_vc_zoom')) + # ### end Alembic commands ### diff --git a/indico_vc_zoom/models/__init__.py b/indico_vc_zoom/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/indico_vc_zoom/models/zoom_meetings.py b/indico_vc_zoom/models/zoom_meetings.py new file mode 100644 index 0000000..040d0e0 --- /dev/null +++ b/indico_vc_zoom/models/zoom_meetings.py @@ -0,0 +1,75 @@ + + +from __future__ import unicode_literals + +import urllib + +from sqlalchemy.event import listens_for +from sqlalchemy.orm.attributes import flag_modified + +from indico.core.db.sqlalchemy import db +from indico.util.string import return_ascii + + +class ZoomMeeting(db.Model): + __tablename__ = 'zoom_meetings' + __table_args__ = {'schema': 'plugin_vc_zoom'} + + #: ID of the videoconference room + vc_room_id = db.Column( + db.Integer, + db.ForeignKey('events.vc_rooms.id'), + primary_key=True + ) + meeting = db.Column( + db.BigInteger, + index=True + ) + url_zoom = db.Column( + db.Text, + index=True, + nullable=False + ) + owned_by_id = db.Column( + db.Integer, + db.ForeignKey('users.users.id'), + index=True, + nullable=False + ) + vc_room = db.relationship( + 'VCRoom', + lazy=False, + backref=db.backref( + 'zoom_meeting', + cascade='all, delete-orphan', + uselist=False, + lazy=False + ) + ) + + #: The user who owns the Zoom room + owned_by_user = db.relationship( + 'User', + lazy=True, + backref=db.backref( + 'vc_rooms_zoom', + lazy='dynamic' + ) + ) + + @property + def join_url(self): + from indico_vc_zoom.plugin import ZoomPlugin + url = self.vc_room.data['url'] + return url + + @return_ascii + def __repr__(self): + return ''.format(self.vc_room, self.meeting, self.owned_by_user) + + +@listens_for(ZoomMeeting.owned_by_user, 'set') +def _owned_by_user_set(target, user, *unused): + if target.vc_room and user.as_principal != tuple(target.vc_room.data['owner']): + target.vc_room.data['owner'] = user.as_principal + flag_modified(target.vc_room, 'data') diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py new file mode 100644 index 0000000..0b30f4e --- /dev/null +++ b/indico_vc_zoom/plugin.py @@ -0,0 +1,260 @@ + + +from __future__ import unicode_literals + +from flask import session +from flask_pluginengine import current_plugin +from sqlalchemy.orm.attributes import flag_modified +from wtforms.fields.core import BooleanField +from wtforms.fields import IntegerField, TextAreaField +from wtforms.fields.html5 import EmailField, URLField +from wtforms.fields.simple import StringField, BooleanField + +from indico.web.forms.widgets import SwitchWidget + +from indico.web.flask.templating import get_template_module +from wtforms.validators import DataRequired, NumberRange +from indico.core.notifications import make_email, send_email +from indico.core.plugins import get_plugin_template_module +from indico.core import signals +from indico.core.auth import multipass +from indico.core.config import config +from indico.core.plugins import IndicoPlugin, url_for_plugin +from indico.modules.events.views import WPSimpleEventDisplay +from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase +from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError +from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent +from indico.web.forms.fields import IndicoPasswordField +from indico.web.forms.widgets import CKEditorWidget +from indico.web.http_api.hooks.base import HTTPAPIHook +from indico.modules.vc.notifications import _send + +from indico_vc_zoom import _ +from indico_vc_zoom.api import ZoomIndicoClient, APIException, RoomNotFoundAPIException +from indico_vc_zoom.blueprint import blueprint +from indico_vc_zoom.cli import cli +from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm +from indico_vc_zoom.http_api import DeleteVCRoomAPI +from indico_vc_zoom.models.zoom_meetings import ZoomMeeting +from indico_vc_zoom.util import iter_extensions, iter_user_identities, retrieve_principal, update_room_from_obj + + +class PluginSettingsForm(VCPluginSettingsFormBase): + support_email = EmailField(_('Zoom email support')) + + api_key = StringField(_('API KEY'), [DataRequired()]) + + api_secret = StringField(_('API SECRET'), [DataRequired()]) + + auto_mute = BooleanField(_('Auto mute'), + widget=SwitchWidget(_('On'), _('Off')), + description=_('The Zoom clients will join the VC room muted by default ')) + + host_video = BooleanField(_('Host Video'), + widget=SwitchWidget(_('On'), _('Off')), + description=_('Start video when the host joins the meeting.')) + + participant_video = BooleanField(_('Participant Video'), + widget=SwitchWidget(_('On'), _('Off')), + description=_('Start video when participants join the meeting. ')) + + join_before_host = BooleanField(_('Join Before Host'), + widget=SwitchWidget(_('On'), _('Off')), + description=_('Allow participants to join the meeting before the host starts the meeting. Only used for scheduled or recurring meetings.')) + + #indico_room_prefix = IntegerField(_('Indico tenant prefix'), [NumberRange(min=0)], + # description=_('The tenant prefix for Indico rooms created on this server')) + #room_group_name = StringField(_("Public rooms' group name"), [DataRequired()], + # description=_('Group name for public videoconference rooms created by Indico')) + num_days_old = IntegerField(_('VC room age threshold'), [NumberRange(min=1), DataRequired()], + description=_('Number of days after an Indico event when a videoconference room is ' + 'considered old')) + max_rooms_warning = IntegerField(_('Max. num. VC rooms before warning'), [NumberRange(min=1), DataRequired()], + description=_('Maximum number of rooms until a warning is sent to the managers')) + zoom_phone_link = URLField(_('ZoomVoice phone number'), + description=_('Link to the list of ZoomVoice phone numbers')) + + creation_email_footer = TextAreaField(_('Creation email footer'), widget=CKEditorWidget(), + description=_('Footer to append to emails sent upon creation of a VC room')) + + +class ZoomPlugin(VCPluginMixin, IndicoPlugin): + """Zoom + + Videoconferencing with Zoom + """ + configurable = True + settings_form = PluginSettingsForm + vc_room_form = VCRoomForm + vc_room_attach_form = VCRoomAttachForm + friendly_name = 'Zoom' + + def init(self): + super(ZoomPlugin, self).init() + self.connect(signals.plugin.cli, self._extend_indico_cli) + self.inject_bundle('main.js', WPSimpleEventDisplay) + self.inject_bundle('main.js', WPVCEventPage) + self.inject_bundle('main.js', WPVCManageEvent) + HTTPAPIHook.register(DeleteVCRoomAPI) + + @property + def default_settings(self): + return dict(VCPluginMixin.default_settings, **{ + 'support_email': config.SUPPORT_EMAIL, + 'api_key': '', + 'api_secret': '', + #'indico_room_prefix': 10, + 'auto_mute':True, + 'host_video':False, + 'participant_video':True, + 'join_before_host':True, + #'room_group_name': 'Indico', + # we skip identity providers in the default list if they don't support get_identity. + # these providers (local accounts, oauth) are unlikely be the correct ones to integrate + # with the zoom infrastructure. + 'num_days_old': 5, + 'max_rooms_warning': 5000, + 'zoom_phone_link': None, + 'creation_email_footer': None + }) + + @property + def logo_url(self): + return url_for_plugin(self.name + '.static', filename='images/zoom_logo.png') + + @property + def icon_url(self): + return url_for_plugin(self.name + '.static', filename='images/zoom_logo.png') + + def _extend_indico_cli(self, sender, **kwargs): + return cli + + def update_data_association(self, event, vc_room, event_vc_room, data): + super(ZoomPlugin, self).update_data_association(event, vc_room, event_vc_room, data) + + event_vc_room.data.update({key: data.pop(key) for key in [ + 'show_autojoin', + 'show_phone_numbers' + ]}) + + flag_modified(event_vc_room, 'data') + + def update_data_vc_room(self, vc_room, data): + super(ZoomPlugin, self).update_data_vc_room(vc_room, data) + + for key in ['description', 'owner', 'auto_mute', 'host_video', 'participant_video', 'join_before_host']: + if key in data: + vc_room.data[key] = data.pop(key) + + flag_modified(vc_room, 'data') + + def create_room(self, vc_room, event): + """Create a new Zoom room for an event, given a VC room. + + In order to create the Zoom room, the function will try to do so with + all the available identities of the user based on the authenticators + defined in Zoom plugin's settings, in that order. + + :param vc_room: VCRoom -- The VC room from which to create the Zoom + room + :param event: Event -- The event to the Zoom room will be attached + """ + client = ZoomIndicoClient(self.settings) + #owner = retrieve_principal(vc_room.data['owner']) + owner= session.user + user_id=owner.email + topic=vc_room.name + time_zone=event.timezone + start=event.start_dt_local + end=event.end_dt + topic=vc_room.data['description'] + type_meeting=2 + host_video=self.settings.get('host_video') + participant_video=self.settings.get('participant_video') + join_before_host=self.settings.get('join_before_host') + mute_upon_entry=self.settings.get('auto_mute') + + + meeting_obj = client.create_meeting(user_id=user_id, + type=type_meeting, + start_time=start, + topic=topic, + timezone=time_zone, + host_video=host_video, + participant_video=participant_video, + join_before_host=join_before_host, + mute_upon_entry=mute_upon_entry) + + if not meeting_obj: + raise VCRoomNotFoundError(_("Could not find newly created room in Zoom")) + vc_room.data.update({ + 'zoom_id': unicode(meeting_obj['id']), + 'url': meeting_obj['join_url'], + 'start_url':meeting_obj['start_url'] + }) + + flag_modified(vc_room, 'data') + vc_room.zoom_meeting = ZoomMeeting(vc_room_id=vc_room.id, meeting=meeting_obj['id'], + owned_by_user=owner, url_zoom=meeting_obj['join_url']) + self.notify_owner_start_url(vc_room) + + + def update_room(self, vc_room, event): + pass + + def refresh_room(self, vc_room, event): + pass + + def delete_room(self, vc_room, event): + client = ZoomIndicoClient(self.settings) + zoom_id = vc_room.data['zoom_id'] + client.delete_meeting(zoom_id) + + + def get_meeting(self, vc_room): + client = ZoomIndicoClient(self.settings) + return client.get_meeting(vc_room.data['zoom_id']) + + def get_blueprints(self): + return blueprint + + def get_vc_room_form_defaults(self, event): + defaults = super(ZoomPlugin, self).get_vc_room_form_defaults(event) + defaults.update({ + 'show_autojoin': True, + 'show_phone_numbers': True, + 'owner_user': session.user + }) + + return defaults + + def get_vc_room_attach_form_defaults(self, event): + defaults = super(ZoomPlugin, self).get_vc_room_attach_form_defaults(event) + defaults.update({ + 'show_autojoin': True, + 'show_phone_numbers': True + }) + return defaults + + def can_manage_vc_room(self, user, room): + return user == room.zoom_meeting.owned_by_user or super(ZoomPlugin, self).can_manage_vc_room(user, room) + + def _merge_users(self, target, source, **kwargs): + super(ZoomPlugin, self)._merge_users(target, source, **kwargs) + for ext in ZoomMeeting.find(owned_by_user=source): + ext.owned_by_user = target + flag_modified(ext.vc_room, 'data') + + def get_notification_cc_list(self, action, vc_room, event): + return {vc_room.zoom_meeting.owned_by_user.email} + + + def notify_owner_start_url(self, vc_room): + user = vc_room.zoom_meeting.owned_by_user + to_list = {user.email} + + template_module = get_template_module('vc_zoom:emails/notify_start_url.html', plugin=ZoomPlugin.instance, vc_room=vc_room, event=None, + vc_room_event=None, user=user) + + email = make_email(to_list, template=template_module, html=True) + send_email(email, None, 'Zoom') diff --git a/indico_vc_zoom/static/images/zoom_logo.png b/indico_vc_zoom/static/images/zoom_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c8347b4379d51d09983e2124661a33acfd00e7be GIT binary patch literal 207444 zcmZ6SWlUXPu=e-C-L({VD{_$H4yCvkcPQ>|2X`qHcPMVf-QC?OQlz-MzWm?hez-ST zU-nK`b|zVC_A}4?CR|Zo3Ki)C5&!_G(qF`t0RUPI0HA6R;NIWhd%*q!05U*YTtwA9 zF8Ww~!IY3lVT|0Cf%oj+83T#{R-R;S&&!hJZ&mW)g)M{Am-~W4^yFy=> zaT_2v{GYWs4(WNVzEVMdse+MRD9ZLjn{R?5AY0i{gPVHJ2-M&yp=od6CWOI&mL;2U zIV#8XA8Lb-omnu(*52Ca$lCiS-tv&~v%VdQzyu?>ednqvb~7vZd3o=wBkjo{ed5K< zOLu(RVsuAgn@`6EWuB2XDYulo;(6WyQd$s7%Kt;H3D%Bo?5xuZ6L5cWX%*=iZcS-1 zi!oUq)%%WrGytU&D`mNRAKyAzzQ1dp1q&$%74ka{a5h42*re!wer+uRWUu;SES!tX z{y>lJW%|;?^X;9WdbP@F54hFaC>?F+?oA)EdI{Hf6(aQXZl^6Hv5XjV*fH z*I>0*yuWwb3d`O(y<+q4OId{8>jWmN;lU61jU?ArgxAwlKWc=(A4xE|yh!9-FCTv5 zGv48+8X8@KNx)9iXJEQi-DSk+vg|;1k*g2ctGrMdV<<=~*zMaR+~a+8rOD$NF$PaP z%VW_qowK}?*vX88plFJZ=i=;lsR(`Lev}_Qh@9WBd4sN9&OiVThY&7+Xl+W&g8RG1 zdSE~VagRNMgSFTw{3R`6(!KKtA=K+6tzar5E4V}2-vggT7712Iwu3L zj$amg&aF6X_289iNs|Q^6=Bd?_F|oyU+fIYTFt*-BzIo%0D;|eJtyKdu^-%#8AIOp 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%0AS)BnGD6Aq4uw7*T`JG+v=m<2(s%3 zDVoK+h@d9ZdVx#Hy+>11mL8b3~d+nD7gmD&<05=+!$I) zKgQ$PI&Uq~J?I%a_K{1sfbo_=mVHN-rp_Z&WsVRFF8~mGi>|yGO(A6xuR}ETXKX$4 z&V#JtVU4cx#=<)vmj|k6>bu5T2EWe084x}D>a^VMKsj0+0eA&mjDmdxSS&e2Zp}~F zXVoN%JZoINUwtnC0{Soo*__CifqYd5uTBc?6&$+%p&^*l;g5dg2&MhoDa{UWF0>WV ziTiD$HQ4h2>eq~T6ou4$8e?XZWqH0R%N1sG8q6yont3xx9Ner3&}$N4Q9Ci9vZ=^?=kFzh>ms9R(=U|(6#xgJs~u(mzw(Wjm|<|;@`xw{P#?d8 zK9EhbVXPbrXtYIl@DY2Cx(Jc&!_Tl>d1&pKpnu}=NN%)-JUO4#`^NTrJbrN{s}QaY z-qn+#V;@<)g@N09z4YxSr9(-QEV86Xt}P9MG*ac$hAPxx>-KEi5jTd0ow&U@8ejk- zMvtw^G^L1jRF|IE&Mc>EpF~lv0yqyWY_S!t0px2V239%6r0BtJdRCxX|KQejz!?|X zx~4VULHdkP-P) zj@S6|%2@zwJHh`U{rZB?zYr>d3RBv>QtW1{p0TI7cnCELE#7#e>CF#d)7Ny^126}U z832bUNqcVmidKU;#YWf8d2|Dy&O=1aVVQopXi(d6tuxZUu ztjtAY@rE=IjbEWLCA@i8Plf<`2Z4VgNzLKGe0B#HkcIMI19}r8f3_L4BB3!Ib|W

Y{`Z%@^w_fiPU0Utw%N*GGbmS2uK_q) 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ʘh@mdVp z60H%x*37*!Od**l(N5C@w^sGqDzC|CEd$1SA!%ydzL=JTYsjxT5g0bo?$7Qmdb-ek-#asN^#$!ez^Lgp>Y`sAd7cx zvVYc%JDH#sRb2{HC_ZnXjf~q(@Y*q1S4BE&s`OZ1PGhGwY?x2yg$Mnt*t|@dV@azy zR%o0YhjwLJ)y>e!&+MN8Ff+dA&JKX**WUG!H=s2H5Ktt5%7Lo+2AAJ^jUjnFiz^J? zdEv&5Wvn?d?2#|{zUi5Kp@?J@LWS@6QWw-?ai z>9P5)|Le;DrHyU7euk2y&3Of>6f~rg5meBU@;r;*B1l>)Bc_?Kn<1mnDOslCwv^U$ zL^owS9j%A^PyaBYUPZK1gO6}Xm9)5OExYya=(n^kMU9M`9hB*qPPk4;yO3Jm%Zy^- znXi1+wD+kOKkYo|0Xt#G1&E{BQ{Jx#wE=fQga>nh55w}L@cY`FYGZE7X z{^a<3*lGQzPULC7C3F$}aza(?eh_YC>JAClO`@*R*17lrvzo%oC6m zXHNYM=h+^RsIg|P_b zXI}nXHv96S;_TTk6L6S;xoj?=IJFy!5UdEl#?#PFZ?1} zcKJY=mUw=y@7Y2@NX`IYp3SCT{6l~XfWM^E(q(sWysUsL^A`Y)vQ>u5uFfJ9h2cC~ z>vP`APi1rYDeg6%0q_jKm#0PT5&$PVWzgrq6M)oWLUWAg73(JjV%f^SF`ghm-zv09 zz-Lbv44hJpbO?xefis5G$goy%YUx!;-mh7tHLrnXY=$NdJ}?ge+wVE@0zl8xKywsH zbBtJ=FN7x^r3$O%!16c2n*xFr@BEa1?=3@uxpLKaTeg?{m_<|(A#|6T9Sfv#=P968 z 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 z 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 (now_utc() - timedelta(days=max_room_event_age))) + .join(VCRoom.events) + .join(VCRoomEventAssociation.event) + .group_by(VCRoom.id)) + + # non-deleted rooms with no recent associations + return VCRoom.find_all(VCRoom.status != VCRoomStatus.deleted, ~VCRoom.id.in_(recently_used)) + + +def notify_owner(plugin, vc_room): + """Notifies about the deletion of a Zoom room from the Zoom server.""" + user = vc_room.zoom_meeting.owned_by_user + tpl = get_plugin_template_module('emails/remote_deleted.html', plugin=plugin, vc_room=vc_room, event=None, + vc_room_event=None, user=user) + _send('delete', user, plugin, None, vc_room, tpl) + + +@celery.periodic_task(run_every=crontab(minute='0', hour='3', day_of_week='monday'), plugin='vc_zoom') +def zoom_cleanup(dry_run=False): + from indico_vc_zoom.plugin import ZoomPlugin + max_room_event_age = ZoomPlugin.settings.get('num_days_old') + + ZoomPlugin.logger.info('Deleting Zoom rooms that are not used or linked to events all older than %d days', + max_room_event_age) + candidate_rooms = find_old_zoom_rooms(max_room_event_age) + ZoomPlugin.logger.info('%d rooms found', len(candidate_rooms)) + + if dry_run: + for vc_room in candidate_rooms: + ZoomPlugin.logger.info('Would delete Zoom room %s from server', vc_room) + return + + for vc_room in committing_iterator(candidate_rooms, n=20): + try: + ZoomPlugin.instance.delete_room(vc_room, None) + ZoomPlugin.logger.info('Room %s deleted from Zoom server', vc_room) + notify_owner(ZoomPlugin.instance, vc_room) + vc_room.status = VCRoomStatus.deleted + except RoomNotFoundAPIException: + ZoomPlugin.logger.warning('Room %s had been already deleted from the Zoom server', vc_room) + vc_room.status = VCRoomStatus.deleted + except APIException: + ZoomPlugin.logger.exception('Impossible to delete Zoom room %s', vc_room) diff --git a/indico_vc_zoom/templates/buttons.html b/indico_vc_zoom/templates/buttons.html new file mode 100644 index 0000000..3f0c1d9 --- /dev/null +++ b/indico_vc_zoom/templates/buttons.html @@ -0,0 +1,6 @@ +{% macro render_join_button(vc_room, extra_classes="") %} + + {% trans %}Join{% endtrans %} + +{% endmacro %} diff --git a/indico_vc_zoom/templates/emails/created.html b/indico_vc_zoom/templates/emails/created.html new file mode 100644 index 0000000..6d4118d --- /dev/null +++ b/indico_vc_zoom/templates/emails/created.html @@ -0,0 +1,16 @@ +{% extends 'vc/emails/created.html' %} + +{% block plugin_specific_info %} +

  • + Zoom URL: + {{ vc_room.zoom_meeting.join_url }} +
  • + +{% endblock %} + +{% block custom_footer %} + {% if plugin.settings.get('creation_email_footer') %} +
    + {{ plugin.settings.get('creation_email_footer') | sanitize_html }} + {% endif %} +{% endblock %} diff --git a/indico_vc_zoom/templates/emails/deleted.html b/indico_vc_zoom/templates/emails/deleted.html new file mode 100644 index 0000000..a67c1f1 --- /dev/null +++ b/indico_vc_zoom/templates/emails/deleted.html @@ -0,0 +1 @@ +{% extends 'vc/emails/deleted.html' %} diff --git a/indico_vc_zoom/templates/emails/notify_start_url.html b/indico_vc_zoom/templates/emails/notify_start_url.html new file mode 100644 index 0000000..ee45670 --- /dev/null +++ b/indico_vc_zoom/templates/emails/notify_start_url.html @@ -0,0 +1,18 @@ +{% extends 'emails/base.html' %} + +{% block subject -%} + [DON'T SHARE] Zoom Host URL - {{ vc_room.name }} +{%- endblock %} + +{% block header -%} + +
  • + HOST Zoom URL: + {{ vc_room.data.start_url }} +
  • + +Please don't share this link. + +{% block custom_footer %}{% endblock %} + +{%- endblock %} diff --git a/indico_vc_zoom/templates/emails/remote_deleted.html b/indico_vc_zoom/templates/emails/remote_deleted.html new file mode 100644 index 0000000..1c0c580 --- /dev/null +++ b/indico_vc_zoom/templates/emails/remote_deleted.html @@ -0,0 +1,16 @@ +{% extends 'emails/base.html' %} + +{% block subject -%} + [{{ plugin.friendly_name }}] Room deleted from server: {{ vc_room.name }} +{%- endblock %} + +{% block header -%} +

    + The Zoom room "{{ vc_room.name }}" has been deleted from the Zoom server since it has not been used by any recent event. +

    +

    + You won't be able to attach it to any future events. If you need to do so, please create a new room. +

    +{% block custom_footer %}{% endblock %} + +{%- endblock %} diff --git a/indico_vc_zoom/templates/event_buttons.html b/indico_vc_zoom/templates/event_buttons.html new file mode 100644 index 0000000..c30f4cc --- /dev/null +++ b/indico_vc_zoom/templates/event_buttons.html @@ -0,0 +1,6 @@ +{% extends 'vc/event_buttons.html' %} +{% from 'vc_zoom:buttons.html' import render_join_button %} + +{% block buttons %} + {{ render_join_button(vc_room, "i-button-small event-service-right-button join-button") }} +{% endblock %} diff --git a/indico_vc_zoom/templates/info_box.html b/indico_vc_zoom/templates/info_box.html new file mode 100644 index 0000000..4dbf5d3 --- /dev/null +++ b/indico_vc_zoom/templates/info_box.html @@ -0,0 +1,37 @@ +{% from '_clipboard_input.html' import clipboard_input %} +{% set owner = vc_room.zoom_meeting.owned_by_user %} +{% set phone_link = settings.get('zoom_phone_link') %} +
    +
    {% trans %}Name{% endtrans %}
    +
    {{ vc_room.name }}
    +
    {% trans %}Meeting Topic{% endtrans %}
    +
    {{ vc_room.data.description }}
    + {% if vc_room.zoom_meeting %} +
    {% trans %}Meeting ID{% endtrans %}
    +
    {{ vc_room.zoom_meeting.meeting }}
    + {% endif %} + {% if owner %} +
    {% trans %}Owner{% endtrans %}
    +
    {{ owner.full_name }}
    + {% endif %} + {% if event_vc_room.data.show_pin and vc_room.data.room_pin %} +
    {% trans %}Room PIN{% endtrans %}
    +
    {{ vc_room.data.room_pin }}
    + {% endif %} + {% if event_vc_room.data.show_autojoin %} +
    {% trans %}Zoom URL{% endtrans %}
    +
    + {{ clipboard_input(vc_room.zoom_meeting.join_url, name="vc-room-url-%s"|format(event_vc_room.id)) }} +
    + {% endif %} + {% if event_vc_room.data.show_phone_numbers and phone_link %} +
    + {% trans %}Useful links{% endtrans %} +
    +
    + + {% trans %}Phone numbers{% endtrans %} + +
    + {% endif %} +
    diff --git a/indico_vc_zoom/templates/manage_event_info_box.html b/indico_vc_zoom/templates/manage_event_info_box.html new file mode 100644 index 0000000..5068f4c --- /dev/null +++ b/indico_vc_zoom/templates/manage_event_info_box.html @@ -0,0 +1,55 @@ +{% from '_password.html' import password %} +{% from '_clipboard_input.html' import clipboard_input %} +{% set owner = vc_room.zoom_meeting.owned_by_user %} +{% set phone_link = settings.get('zoom_phone_link') %} +
    +
    {% trans %}Meeting Topic{% endtrans %}
    +
    {{ vc_room.data.description }}
    +
    {% trans %}Meeting ID{% endtrans %}
    +
    {{ vc_room.zoom_meeting.meeting }}
    +
    {% trans %}Owner{% endtrans %}
    +
    + {% if owner %} + {{ owner.full_name }} + {% else %} + {{ vc_room.data.owner_account }} (deleted) + {% endif %} +
    +
    {% trans %}Linked to{% endtrans %}
    +
    + {% set obj = event_vc_room.link_object %} + {% if obj is none %} + (missing {{ event_vc_room.link_type.name }}) + {% elif event_vc_room.link_type.name == 'event' %} + {% trans %}the whole event{% endtrans %} + {% elif event_vc_room.link_type.name == 'contribution' %} + {% trans %}Contribution{% endtrans %}: {{ obj.title }} + {% elif event_vc_room.link_type.name == 'block' %} + {% trans %}Session{% endtrans %}: {{ obj.full_title }} + {% endif %} +
    + {% if vc_room.data.room_pin %} +
    {% trans %}Room PIN{% endtrans %}
    +
    + {{ password('vc-room-pin-%s'|format(event_vc_room.id), value=vc_room.data.room_pin, toggle=True, + readonly=true) }} +
    + {% endif %} + {% if vc_room.data.moderation_pin %} +
    {% trans %}Moderation PIN{% endtrans %}
    +
    + {{ password('vc-moderation-pin-%s'|format(event_vc_room.id), value=vc_room.data.moderation_pin, + toggle=True, readonly=true) }} +
    + {% endif %} +
    {% trans %}Zoom URL{% endtrans %}
    +
    + {{ clipboard_input(vc_room.zoom_meeting.join_url, name="vc-room-url") }} +
    +
    {% trans %}Created on{% endtrans %}
    +
    {{ vc_room.created_dt | format_datetime(timezone=event.tzinfo) }}
    + {% if vc_room.modified_dt %} +
    {% trans %}Modified on{% endtrans %}
    +
    {{ vc_room.modified_dt | format_datetime(timezone=event.tzinfo) }}
    + {% endif %} +
    diff --git a/indico_vc_zoom/templates/management_buttons.html b/indico_vc_zoom/templates/management_buttons.html new file mode 100644 index 0000000..93b9f5c --- /dev/null +++ b/indico_vc_zoom/templates/management_buttons.html @@ -0,0 +1,6 @@ +{% extends 'vc/management_buttons.html' %} +{% from 'vc_zoom:buttons.html' import render_join_button %} + +{% block buttons %} + {{ render_join_button(vc_room, extra_classes="icon-play") }} +{% endblock %} diff --git a/indico_vc_zoom/templates/vc_room_timetable_buttons.html b/indico_vc_zoom/templates/vc_room_timetable_buttons.html new file mode 100644 index 0000000..8b70551 --- /dev/null +++ b/indico_vc_zoom/templates/vc_room_timetable_buttons.html @@ -0,0 +1,7 @@ +{% extends 'vc/vc_room_timetable_buttons.html' %} +{% from 'vc_zoom:buttons.html' import render_join_button %} +{% set vc_room = event_vc_room.vc_room %} + +{% block buttons %} + {{ render_join_button(vc_room, "i-button-small event-service-right-button join-button") }} +{% endblock %} diff --git a/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po b/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po new file mode 100644 index 0000000..fe16c6c --- /dev/null +++ b/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po @@ -0,0 +1,23 @@ +# Translations template for PROJECT. +# Copyright (C) 2015 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Translators: +# Thomas Baron , 2015 +msgid "" +msgstr "" +"Project-Id-Version: Indico\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2015-03-11 16:21+0100\n" +"PO-Revision-Date: 2015-03-12 12:52+0000\n" +"Last-Translator: Thomas Baron \n" +"Language-Team: French (France) (http://www.transifex.com/projects/p/indico/language/fr_FR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 1.3\n" +"Language: fr_FR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +msgid "Indico" +msgstr "Indico" diff --git a/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po b/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po new file mode 100644 index 0000000..652e3e6 --- /dev/null +++ b/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po @@ -0,0 +1,289 @@ +# Translations template for PROJECT. +# Copyright (C) 2017 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# +# Translators: +# Thomas Baron , 2015,2017 +msgid "" +msgstr "" +"Project-Id-Version: Indico\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2017-10-18 11:55+0200\n" +"PO-Revision-Date: 2017-10-30 11:04+0000\n" +"Last-Translator: Thomas Baron \n" +"Language-Team: French (France) (http://www.transifex.com/indico/indico/language/fr_FR/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.5.1\n" +"Language: fr_FR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: indico_vc_zoom/controllers.py:38 +msgid "You are now the owner of the room '{room.name}'" +msgstr "Vous êtes maintenant responsable de la salle '{room.name}'" + +#: indico_vc_zoom/forms.py:32 +msgid "The PIN must be a number" +msgstr "Le code confidentiel doit être un nombre entier" + +#: indico_vc_zoom/forms.py:37 +msgid "Show PIN" +msgstr "Afficher le code confidentiel" + +#: indico_vc_zoom/forms.py:39 +msgid "Show the VC Room PIN on the event page (insecure!)" +msgstr "Afficher le code confidentiel de la salle Vidyo sur la page de l'événement (peu sûr!)" + +#: indico_vc_zoom/forms.py:40 +msgid "Show Auto-join URL" +msgstr "Afficher l'URL de connexion" + +#: indico_vc_zoom/forms.py:42 +msgid "Show the auto-join URL on the event page" +msgstr "Afficher l'URL de connexion sur la page de l'événement" + +#: indico_vc_zoom/forms.py:43 +msgid "Show Phone Access numbers" +msgstr "Afficher les numéros d'accès téléphonique" + +#: indico_vc_zoom/forms.py:45 +msgid "Show a link to the list of phone access numbers" +msgstr "Afficher un lien vers la liste des numéros d'accès téléphonique" + +#: indico_vc_zoom/forms.py:58 indico_vc_zoom/templates/info_box.html:7 +#: indico_vc_zoom/templates/manage_event_info_box.html:6 +msgid "Description" +msgstr "Description" + +#: indico_vc_zoom/forms.py:58 +msgid "The description of the room" +msgstr "La description de la salle" + +#: indico_vc_zoom/forms.py:59 indico_vc_zoom/templates/info_box.html:14 +#: indico_vc_zoom/templates/manage_event_info_box.html:10 +msgid "Owner" +msgstr "Responsable" + +#: indico_vc_zoom/forms.py:59 +msgid "The owner of the room" +msgstr "Le responsable de la salle" + +#: indico_vc_zoom/forms.py:60 +#: indico_vc_zoom/templates/manage_event_info_box.html:39 +msgid "Moderation PIN" +msgstr "Code confidentiel de modération" + +#: indico_vc_zoom/forms.py:61 +msgid "Used to moderate the VC Room. Only digits allowed." +msgstr "Utilisé pour modérer la salle de VC. Seuls les chiffres sont autorisés." + +#: indico_vc_zoom/forms.py:62 indico_vc_zoom/templates/info_box.html:18 +#: indico_vc_zoom/templates/manage_event_info_box.html:32 +msgid "Room PIN" +msgstr "Code confidentiel de la salle" + +#: indico_vc_zoom/forms.py:63 +msgid "" +"Used to protect the access to the VC Room (leave blank for open access). " +"Only digits allowed." +msgstr "Utilisé pour protéger l'accès à la salle de VC (laisser vide pour un accès ouvert). Seuls les chiffres sont autorisés." + +#: indico_vc_zoom/forms.py:65 +msgid "Auto mute" +msgstr "Coupure automatique des périphériques d'entrée" + +#: indico_vc_zoom/forms.py:66 +msgid "On" +msgstr "Activé" + +#: indico_vc_zoom/forms.py:66 +msgid "Off" +msgstr "Désactivé" + +#: indico_vc_zoom/forms.py:67 +msgid "" +"The VidyoDesktop clients will join the VC room muted by default (audio and " +"video)" +msgstr "Les clients VidyoDesktop rejoindront la salle Vidyo avec le micro et la caméra coupés par défaut" + +#: indico_vc_zoom/forms.py:82 +msgid "Unable to find this user in Indico." +msgstr "Impossible de trouver cet utilisateur dans Indico." + +#: indico_vc_zoom/forms.py:84 +msgid "This user does not have a suitable account to use Vidyo." +msgstr "Cet utilisateur n'a pas de compte qui lui permet d'utiliser Vidyo." + +#: indico_vc_zoom/plugin.py:49 +msgid "Vidyo email support" +msgstr "Adresse électronique de l'assistance Vidyo" + +#: indico_vc_zoom/plugin.py:50 +msgid "Username" +msgstr "Identifiant" + +#: indico_vc_zoom/plugin.py:50 +msgid "Indico username for Vidyo" +msgstr "Identifiant Indico pour Vidyo" + +#: indico_vc_zoom/plugin.py:51 +msgid "Password" +msgstr "Mot de passe" + +#: indico_vc_zoom/plugin.py:52 +msgid "Indico password for Vidyo" +msgstr "Mot de passe utilisateur pour Vidyo" + +#: indico_vc_zoom/plugin.py:53 +msgid "Admin API WSDL URL" +msgstr "URL WSDL pour l'API admin" + +#: indico_vc_zoom/plugin.py:54 +msgid "User API WSDL URL" +msgstr "URL WSDL pour l'API utilisateur" + +#: indico_vc_zoom/plugin.py:55 +msgid "Indico tenant prefix" +msgstr "Préfixe de tenant pour Indico" + +#: indico_vc_zoom/plugin.py:56 +msgid "The tenant prefix for Indico rooms created on this server" +msgstr "Le préfixe de tenant pour les salles Vidyo créées sur ce serveur Indico" + +#: indico_vc_zoom/plugin.py:57 +msgid "Public rooms' group name" +msgstr "Nom du groupe Vidyo pour les salles Vidyo" + +#: indico_vc_zoom/plugin.py:58 +msgid "Group name for public videoconference rooms created by Indico" +msgstr "Nom du groupe pour les salles publiques de visioconférence créées par Indico" + +#: indico_vc_zoom/plugin.py:59 +msgid "Authenticators" +msgstr "Services d'authentification" + +#: indico_vc_zoom/plugin.py:60 +msgid "Identity providers to convert Indico users to Vidyo accounts" +msgstr "Fournisseurs d'identité pour convertir des utilisateurs Indico en comptes Vidyo" + +#: indico_vc_zoom/plugin.py:61 +msgid "VC room age threshold" +msgstr "Limite d'âge pour les salles Vidyo" + +#: indico_vc_zoom/plugin.py:62 +msgid "" +"Number of days after an Indico event when a videoconference room is " +"considered old" +msgstr "Nombre de jours à partir de la fin d'un événement dans Indico après lesquels une salle de visioconférence est considérée comme agée" + +#: indico_vc_zoom/plugin.py:64 +msgid "Max. num. VC rooms before warning" +msgstr "Nombre maximum de salles Vidyo avant un message d'alerte" + +#: indico_vc_zoom/plugin.py:65 +msgid "Maximum number of rooms until a warning is sent to the managers" +msgstr "Nombre maximum de salles Vidyo créées sur ce serveur avant qu'un message d'alerte soit envoyé aux administrateurs" + +#: indico_vc_zoom/plugin.py:66 +msgid "VidyoVoice phone number" +msgstr "Numéros de téléphone VidyoVoice" + +#: indico_vc_zoom/plugin.py:67 +msgid "Link to the list of VidyoVoice phone numbers" +msgstr "Lien vers la liste des numéros de téléphones VidyoVoice" + +#: indico_vc_zoom/plugin.py:68 +msgid "Client Chooser URL" +msgstr "URL de sélection du client" + +#: indico_vc_zoom/plugin.py:69 +msgid "" +"URL for client chooser interface. The room key will be passed as a 'url' GET" +" query argument" +msgstr "L'URL pour l'interface de sélection du client. Le code de la salle sera passé comme argument de requête GET." + +#: indico_vc_zoom/plugin.py:71 +msgid "Creation email footer" +msgstr "Pied de page du courriel de création" + +#: indico_vc_zoom/plugin.py:72 +msgid "Footer to append to emails sent upon creation of a VC room" +msgstr "Pied de page ajouté au courriel envoyé à la création d'une nouvelle salle Vidyo" + +#: indico_vc_zoom/plugin.py:162 indico_vc_zoom/plugin.py:202 +#: indico_vc_zoom/plugin.py:240 indico_vc_zoom/plugin.py:269 +msgid "No valid Vidyo account found for this user" +msgstr "Pas de compte Vidyo valide pour cet utilisateur" + +#: indico_vc_zoom/plugin.py:198 indico_vc_zoom/plugin.py:263 +msgid "Room name already in use" +msgstr "Ce nom de salle est déjà utilisé" + +#: indico_vc_zoom/plugin.py:213 +msgid "Could not find newly created room in Vidyo" +msgstr "Impossible de trouver la nouvelle salle dans Vidyo" + +#: indico_vc_zoom/plugin.py:232 indico_vc_zoom/plugin.py:259 +#: indico_vc_zoom/plugin.py:288 +msgid "This room has been deleted from Vidyo" +msgstr "Cette salle a été supprimée de Vidyo" + +#: indico_vc_zoom/templates/buttons.html:7 +#, python-format +msgid "You will be the owner of this Vidyo room, replacing %(name)s." +msgstr "Vous deviendrez le responsable de cette salle Vidyo, à la place de %(name)s." + +#: indico_vc_zoom/templates/buttons.html:9 +msgid "Make me owner" +msgstr "Nommez moi responsable" + +#: indico_vc_zoom/templates/buttons.html:19 +msgid "Join" +msgstr "Rejoindre" + +#: indico_vc_zoom/templates/info_box.html:5 +msgid "Name" +msgstr "Nom" + +#: indico_vc_zoom/templates/info_box.html:10 +#: indico_vc_zoom/templates/manage_event_info_box.html:8 +msgid "Extension" +msgstr "Extension" + +#: indico_vc_zoom/templates/info_box.html:22 +#: indico_vc_zoom/templates/manage_event_info_box.html:45 +msgid "Auto-join URL" +msgstr "URL pour connexion à la salle" + +#: indico_vc_zoom/templates/info_box.html:29 +msgid "Useful links" +msgstr "Liens utiles" + +#: indico_vc_zoom/templates/info_box.html:33 +msgid "Phone numbers" +msgstr "Numéros de téléphone" + +#: indico_vc_zoom/templates/manage_event_info_box.html:18 +msgid "Linked to" +msgstr "attachée à" + +#: indico_vc_zoom/templates/manage_event_info_box.html:24 +msgid "the whole event" +msgstr "l'événement entier" + +#: indico_vc_zoom/templates/manage_event_info_box.html:26 +msgid "Contribution" +msgstr "La contribution" + +#: indico_vc_zoom/templates/manage_event_info_box.html:28 +msgid "Session" +msgstr "La session" + +#: indico_vc_zoom/templates/manage_event_info_box.html:49 +msgid "Created on" +msgstr "Créée le " + +#: indico_vc_zoom/templates/manage_event_info_box.html:52 +msgid "Modified on" +msgstr "Modifiée le " diff --git a/indico_vc_zoom/util.py b/indico_vc_zoom/util.py new file mode 100644 index 0000000..a527786 --- /dev/null +++ b/indico_vc_zoom/util.py @@ -0,0 +1,90 @@ + + +from __future__ import unicode_literals + +import re + +from flask_multipass import IdentityRetrievalFailed + +from indico.core.auth import multipass +from indico.core.db import db +from indico.modules.auth import Identity +from indico.modules.users import User + + +authenticators_re = re.compile(r'\s*,\s*') + + +def iter_user_identities(user): + """Iterates over all existing user identities that can be used with Zoom""" + from indico_vc_zoom.plugin import ZoomPlugin + providers = authenticators_re.split(ZoomPlugin.settings.get('authenticators')) + done = set() + for provider in providers: + for _, identifier in user.iter_identifiers(check_providers=True, providers={provider}): + if identifier in done: + continue + done.add(identifier) + yield identifier + + +def get_user_from_identifier(settings, identifier): + """Get an actual User object from an identifier""" + providers = list(auth.strip() for auth in settings.get('authenticators').split(',')) + identities = Identity.find_all(Identity.provider.in_(providers), Identity.identifier == identifier) + if identities: + return sorted(identities, key=lambda x: providers.index(x.provider))[0].user + for provider in providers: + try: + identity_info = multipass.get_identity(provider, identifier) + except IdentityRetrievalFailed: + continue + if identity_info is None: + continue + if not identity_info.provider.settings.get('trusted_email'): + continue + emails = {email.lower() for email in identity_info.data.getlist('email') if email} + if not emails: + continue + user = User.find_first(~User.is_deleted, User.all_emails.in_(list(emails))) + if user: + return user + + +def iter_extensions(prefix, event_id): + """Return extension (prefix + event_id) with an optional suffix which is + incremented step by step in case of collision + """ + extension = '{prefix}{event_id}'.format(prefix=prefix, event_id=event_id) + yield extension + suffix = 1 + while True: + yield '{extension}{suffix}'.format(extension=extension, suffix=suffix) + suffix += 1 + + +def update_room_from_obj(settings, vc_room, room_obj): + """Updates a VCRoom DB object using a SOAP room object returned by the API""" + vc_room.name = room_obj.name + if room_obj.ownerName != vc_room.data['owner_identity']: + owner = get_user_from_identifier(settings, room_obj.ownerName) or User.get_system_user() + vc_room.zoom_meeting.owned_by_user = owner + + vc_room.data.update({ + 'description': room_obj.description, + 'zoom_id': unicode(room_obj.roomID), + 'url': room_obj.RoomMode.roomURL, + 'owner_identity': room_obj.ownerName, + 'room_pin': room_obj.RoomMode.roomPIN if room_obj.RoomMode.hasPIN else "", + 'moderation_pin': room_obj.RoomMode.moderatorPIN if room_obj.RoomMode.hasModeratorPIN else "", + }) + vc_room.zoom_meeting.extension = int(room_obj.extension) + + +def retrieve_principal(principal): + from indico.modules.users import User + type_, id_ = principal + if type_ in {'Avatar', 'User'}: + return User.get(int(id_)) + else: + raise ValueError('Unexpected type: {}'.format(type_)) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7472b25 --- /dev/null +++ b/setup.py @@ -0,0 +1,29 @@ +from __future__ import unicode_literals + +from setuptools import find_packages, setup + + +setup( + name='indico-plugin-vc-zoom', + version='0.2-dev', + description='Zoom video-conferencing plugin for Indico', + url='', + license='MIT', + author='Giovanni Mariano - ENEA', + author_email='giovanni.mariano@enea.it', + packages=find_packages(), + zip_safe=False, + include_package_data=True, + install_requires=[ + 'indico>=2', + 'requests', + 'PyJWT' + ], + classifiers=[ + 'Environment :: Plugins', + 'Environment :: Web Environment', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 2.7' + ], + entry_points={'indico.plugins': {'vc_zoom = indico_vc_zoom.plugin:ZoomPlugin'}} +) diff --git a/tests/task_test.py b/tests/task_test.py new file mode 100644 index 0000000..43714fa --- /dev/null +++ b/tests/task_test.py @@ -0,0 +1,24 @@ + +from datetime import datetime + +import pytest +from pytz import utc + +from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomStatus + +from indico_vc_zoom.models.zoom_meetings import ZoomMeeting + + +@pytest.fixture +def create_dummy_room(db, dummy_user): + """Returns a callable which lets you create dummy Zoom room occurrences""" + pass + + +def test_room_cleanup(create_event, create_dummy_room, freeze_time, db): + """Test that 'old' Zoom rooms are correctly detected""" + freeze_time(datetime(2015, 2, 1)) + + pass + + assert {r.id for r in find_old_zoom_rooms(180)} == {2, 3, 5} diff --git a/url_map.json b/url_map.json new file mode 100644 index 0000000..65fb589 --- /dev/null +++ b/url_map.json @@ -0,0 +1,30163 @@ +{ + "rules": { + "abstracts.abstracts_csv_export": { + "endpoint": "abstracts.abstracts_csv_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/abstracts.csv", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.abstracts_json_export": { + "endpoint": "abstracts.abstracts_json_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/abstracts.json", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.abstracts_pdf_export": { + "endpoint": "abstracts.abstracts_pdf_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/abstracts.pdf", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.abstracts_xlsx_export": { + "endpoint": "abstracts.abstracts_xlsx_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/abstracts.xlsx", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.call_for_abstracts": { + "endpoint": "abstracts.call_for_abstracts", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.close_abstracts_call": { + "endpoint": "abstracts.close_abstracts_call", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/close", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.comment_abstract": { + "endpoint": "abstracts.comment_abstract", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/comment", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/comment", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.create_reviewing_question": { + "endpoint": "abstracts.create_reviewing_question", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/questions/create", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.customize_abstract_list": { + "endpoint": "abstracts.customize_abstract_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/list/customize", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.delete_abstract_comment": { + "endpoint": "abstracts.delete_abstract_comment", + "rules": [ + { + "args": [ + "abstract_id", + "comment_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter", + "comment_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/comments/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "abstract_id", + "comment_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter", + "comment_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/comments/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.delete_reviewing_question": { + "endpoint": "abstracts.delete_reviewing_question", + "rules": [ + { + "args": [ + "confId", + "question_id" + ], + "converters": { + "question_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/questions/", + "isDynamic": false + }, + { + "data": "question_id", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.display_abstract": { + "endpoint": "abstracts.display_abstract", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_abstract_pdf_export": { + "endpoint": "abstracts.display_abstract_pdf_export", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/abstract.pdf", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/abstract.pdf", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_abstracts_csv_export": { + "endpoint": "abstracts.display_abstracts_csv_export", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + }, + { + "data": "/abstracts.csv", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_abstracts_pdf_export": { + "endpoint": "abstracts.display_abstracts_pdf_export", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + }, + { + "data": "/abstracts.pdf", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_abstracts_xlsx_export": { + "endpoint": "abstracts.display_abstracts_xlsx_export", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + }, + { + "data": "/abstracts.xlsx", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_customize_abstract_list": { + "endpoint": "abstracts.display_customize_abstract_list", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + }, + { + "data": "/customize", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_download_attachments": { + "endpoint": "abstracts.display_download_attachments", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + }, + { + "data": "/attachments", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_reviewable_track_abstracts": { + "endpoint": "abstracts.display_reviewable_track_abstracts", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.display_reviewable_tracks": { + "endpoint": "abstracts.display_reviewable_tracks", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/reviewing", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.download_attachment": { + "endpoint": "abstracts.download_attachment", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "file_id", + "filename", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "file_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "file_id", + "filename", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "file_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.download_attachments": { + "endpoint": "abstracts.download_attachments", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/attachments", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.edit_abstract": { + "endpoint": "abstracts.edit_abstract", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.edit_abstract_comment": { + "endpoint": "abstracts.edit_abstract_comment", + "rules": [ + { + "args": [ + "abstract_id", + "comment_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter", + "comment_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/comments/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "abstract_id", + "comment_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter", + "comment_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/comments/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.edit_review": { + "endpoint": "abstracts.edit_review", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management", + "review_id" + ], + "converters": { + "abstract_id": "IntegerConverter", + "review_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/reviews/", + "isDynamic": false + }, + { + "data": "review_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management", + "review_id" + ], + "converters": { + "abstract_id": "IntegerConverter", + "review_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/reviews/", + "isDynamic": false + }, + { + "data": "review_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.edit_review_tracks": { + "endpoint": "abstracts.edit_review_tracks", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/reviewing-tracks", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/reviewing-tracks", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.edit_reviewing_question": { + "endpoint": "abstracts.edit_reviewing_question", + "rules": [ + { + "args": [ + "confId", + "question_id" + ], + "converters": { + "question_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/questions/", + "isDynamic": false + }, + { + "data": "question_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.email_tpl_add": { + "endpoint": "abstracts.email_tpl_add", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates/add", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.email_tpl_delete": { + "endpoint": "abstracts.email_tpl_delete", + "rules": [ + { + "args": [ + "confId", + "email_tpl_id" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates/", + "isDynamic": false + }, + { + "data": "email_tpl_id", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.email_tpl_list": { + "endpoint": "abstracts.email_tpl_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.email_tpl_rest": { + "endpoint": "abstracts.email_tpl_rest", + "rules": [ + { + "args": [ + "confId", + "email_tpl_id" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates/", + "isDynamic": false + }, + { + "data": "email_tpl_id", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.email_tpl_rule_edit": { + "endpoint": "abstracts.email_tpl_rule_edit", + "rules": [ + { + "args": [ + "confId", + "email_tpl_id" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates/", + "isDynamic": false + }, + { + "data": "email_tpl_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.email_tpl_sort": { + "endpoint": "abstracts.email_tpl_sort", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates/sort", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.email_tpl_text_edit": { + "endpoint": "abstracts.email_tpl_text_edit", + "rules": [ + { + "args": [ + "confId", + "email_tpl_id" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/email-templates/", + "isDynamic": false + }, + { + "data": "email_tpl_id", + "isDynamic": true + }, + { + "data": "/edit-text", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.export_boa": { + "endpoint": "abstracts.export_boa", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/book-of-abstracts.pdf", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.export_boa_tex": { + "endpoint": "abstracts.export_boa_tex", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/book-of-abstracts.zip", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.generate_static_url": { + "endpoint": "abstracts.generate_static_url", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/list/static-url", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.judge_abstract": { + "endpoint": "abstracts.judge_abstract", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/judge", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/judge", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_abstract_list": { + "endpoint": "abstracts.manage_abstract_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/list", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_abstract_pdf_export": { + "endpoint": "abstracts.manage_abstract_pdf_export", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/abstract-reviews.pdf", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/abstract-reviews.pdf", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_boa": { + "endpoint": "abstracts.manage_boa", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/boa", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_create_abstract": { + "endpoint": "abstracts.manage_create_abstract", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/create", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_delete_abstracts": { + "endpoint": "abstracts.manage_delete_abstracts", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/delete", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_judge_abstracts": { + "endpoint": "abstracts.manage_judge_abstracts", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/judge", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_reviewing_questions": { + "endpoint": "abstracts.manage_reviewing_questions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/questions", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_reviewing_roles": { + "endpoint": "abstracts.manage_reviewing_roles", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/teams", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_reviewing_settings": { + "endpoint": "abstracts.manage_reviewing_settings", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/review-settings", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.manage_submission_settings": { + "endpoint": "abstracts.manage_submission_settings", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/settings", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.management": { + "endpoint": "abstracts.management", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.my_abstracts_pdf": { + "endpoint": "abstracts.my_abstracts_pdf", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/mine.pdf", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.notification_log": { + "endpoint": "abstracts.notification_log", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/notifications", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/notifications", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.open_abstracts_call": { + "endpoint": "abstracts.open_abstracts_call", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/open", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.other_abstracts": { + "endpoint": "abstracts.other_abstracts", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/other-list", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.person_list": { + "endpoint": "abstracts.person_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/person-list", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.reset_abstract_state": { + "endpoint": "abstracts.reset_abstract_state", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/reset", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/reset", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.review_abstract": { + "endpoint": "abstracts.review_abstract", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management", + "track_id" + ], + "converters": { + "abstract_id": "IntegerConverter", + "track_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/review/track/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management", + "track_id" + ], + "converters": { + "abstract_id": "IntegerConverter", + "track_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/review/track/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.schedule_abstracts_call": { + "endpoint": "abstracts.schedule_abstracts_call", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/schedule", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.sort_reviewing_questions": { + "endpoint": "abstracts.sort_reviewing_questions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/questions/sort", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.submit": { + "endpoint": "abstracts.submit", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/submit", + "isDynamic": false + } + ] + } + ] + }, + "abstracts.submit_invited_abstract": { + "endpoint": "abstracts.submit_invited_abstract", + "rules": [ + { + "args": [ + "confId", + "uuid" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/submit/", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "abstracts.withdraw_abstract": { + "endpoint": "abstracts.withdraw_abstract", + "rules": [ + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/withdraw", + "isDynamic": false + } + ] + }, + { + "args": [ + "abstract_id", + "confId", + "management" + ], + "converters": { + "abstract_id": "IntegerConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/abstracts/", + "isDynamic": false + }, + { + "data": "abstract_id", + "isDynamic": true + }, + { + "data": "/withdraw", + "isDynamic": false + } + ] + } + ] + }, + "agreements.agreement_form": { + "endpoint": "agreements.agreement_form", + "rules": [ + { + "args": [ + "confId", + "id", + "uuid" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/agreement/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "agreements.download_file": { + "endpoint": "agreements.download_file", + "rules": [ + { + "args": [ + "confId", + "definition", + "filename", + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/download/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "agreements.event_agreements": { + "endpoint": "agreements.event_agreements", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "agreements.event_agreements_details": { + "endpoint": "agreements.event_agreements_details", + "rules": [ + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "agreements.event_agreements_details_remind": { + "endpoint": "agreements.event_agreements_details_remind", + "rules": [ + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/remind", + "isDynamic": false + } + ] + } + ] + }, + "agreements.event_agreements_details_remind_all": { + "endpoint": "agreements.event_agreements_details_remind_all", + "rules": [ + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/remind-all", + "isDynamic": false + } + ] + } + ] + }, + "agreements.event_agreements_details_send": { + "endpoint": "agreements.event_agreements_details_send", + "rules": [ + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/send", + "isDynamic": false + } + ] + } + ] + }, + "agreements.event_agreements_details_send_all": { + "endpoint": "agreements.event_agreements_details_send_all", + "rules": [ + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/send-all", + "isDynamic": false + } + ] + } + ] + }, + "agreements.event_agreements_details_submit_answer": { + "endpoint": "agreements.event_agreements_details_submit_answer", + "rules": [ + { + "args": [ + "confId", + "definition", + "id" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/submit/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + } + ] + }, + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/submit", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "agreements.toggle_notifications": { + "endpoint": "agreements.toggle_notifications", + "rules": [ + { + "args": [ + "confId", + "definition" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/agreements/", + "isDynamic": false + }, + { + "data": "definition", + "isDynamic": true + }, + { + "data": "/toggle-notifications", + "isDynamic": false + } + ] + } + ] + }, + "announcement.manage": { + "endpoint": "announcement.manage", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/announcement", + "isDynamic": false + } + ] + } + ] + }, + "api.admin_keys": { + "endpoint": "api.admin_keys", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/api/keys", + "isDynamic": false + } + ] + } + ] + }, + "api.admin_settings": { + "endpoint": "api.admin_settings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/api", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "api.build_urls": { + "endpoint": "api.build_urls", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/build-urls", + "isDynamic": false + } + ] + } + ] + }, + "api.httpapi": { + "endpoint": "api.httpapi", + "rules": [ + { + "args": [ + "path", + "prefix" + ], + "converters": { + "path": "PathConverter" + }, + "defaults": { + "prefix": "export" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/export/", + "isDynamic": false + }, + { + "data": "path", + "isDynamic": true + } + ] + }, + { + "args": [ + "path", + "prefix" + ], + "converters": { + "path": "PathConverter" + }, + "defaults": { + "prefix": "api" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/", + "isDynamic": false + }, + { + "data": "path", + "isDynamic": true + } + ] + }, + { + "args": [ + "prefix" + ], + "converters": { + "prefix": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "prefix", + "isDynamic": true + } + ] + } + ] + }, + "api.jsonrpc": { + "endpoint": "api.jsonrpc", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/services/json-rpc", + "isDynamic": false + } + ] + } + ] + }, + "api.key_block": { + "endpoint": "api.key_block", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/api/block", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api/block", + "isDynamic": false + } + ] + } + ] + }, + "api.key_create": { + "endpoint": "api.key_create", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/api/create", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api/create", + "isDynamic": false + } + ] + } + ] + }, + "api.key_delete": { + "endpoint": "api.key_delete", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/api/delete", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api/delete", + "isDynamic": false + } + ] + } + ] + }, + "api.key_toggle_persistent": { + "endpoint": "api.key_toggle_persistent", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/api/persistent", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api/persistent", + "isDynamic": false + } + ] + } + ] + }, + "api.user_profile": { + "endpoint": "api.user_profile", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/api", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "assets.css": { + "endpoint": "assets.css", + "rules": [ + { + "args": [ + "filename" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/css/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "assets.custom": { + "endpoint": "assets.custom", + "rules": [ + { + "args": [ + "filename", + "folder" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": { + "folder": "files" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/static/custom/files/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "filename", + "folder" + ], + "converters": { + "filename": "PathConverter", + "folder": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/static/custom/", + "isDynamic": false + }, + { + "data": "folder", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "assets.dist": { + "endpoint": "assets.dist", + "rules": [ + { + "args": [ + "filename" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/dist/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "assets.favicon": { + "endpoint": "assets.favicon", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/favicon.ico", + "isDynamic": false + } + ] + } + ] + }, + "assets.folder_file": { + "endpoint": "assets.folder_file", + "rules": [ + { + "args": [ + "fileext", + "filename", + "folder", + "version" + ], + "converters": { + "filename": "PathConverter", + "folder": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "folder", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + }, + { + "data": "__v", + "isDynamic": false + }, + { + "data": "version", + "isDynamic": true + }, + { + "data": ".", + "isDynamic": false + }, + { + "data": "fileext", + "isDynamic": true + } + ] + }, + { + "args": [ + "fileext", + "filename", + "folder" + ], + "converters": { + "filename": "PathConverter", + "folder": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "folder", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + }, + { + "data": ".", + "isDynamic": false + }, + { + "data": "fileext", + "isDynamic": true + } + ] + } + ] + }, + "assets.fonts": { + "endpoint": "assets.fonts", + "rules": [ + { + "args": [ + "filename" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/fonts/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "assets.i18n_locale": { + "endpoint": "assets.i18n_locale", + "rules": [ + { + "args": [ + "locale_name" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/assets/i18n/", + "isDynamic": false + }, + { + "data": "locale_name", + "isDynamic": true + }, + { + "data": ".js", + "isDynamic": false + } + ] + } + ] + }, + "assets.i18n_locale_react": { + "endpoint": "assets.i18n_locale_react", + "rules": [ + { + "args": [ + "locale_name" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/assets/i18n/", + "isDynamic": false + }, + { + "data": "locale_name", + "isDynamic": true + }, + { + "data": "-react.js", + "isDynamic": false + } + ] + } + ] + }, + "assets.image": { + "endpoint": "assets.image", + "rules": [ + { + "args": [ + "filename" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/images/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "assets.js_vars_global": { + "endpoint": "assets.js_vars_global", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/assets/js-vars/global.js", + "isDynamic": false + } + ] + } + ] + }, + "assets.js_vars_user": { + "endpoint": "assets.js_vars_user", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/assets/js-vars/user.js", + "isDynamic": false + } + ] + } + ] + }, + "assets.plugin_file": { + "endpoint": "assets.plugin_file", + "rules": [ + { + "args": [ + "fileext", + "filename", + "plugin", + "version" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/static/plugins/", + "isDynamic": false + }, + { + "data": "plugin", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + }, + { + "data": "__v", + "isDynamic": false + }, + { + "data": "version", + "isDynamic": true + }, + { + "data": ".", + "isDynamic": false + }, + { + "data": "fileext", + "isDynamic": true + } + ] + }, + { + "args": [ + "fileext", + "filename", + "plugin" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/static/plugins/", + "isDynamic": false + }, + { + "data": "plugin", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + }, + { + "data": ".", + "isDynamic": false + }, + { + "data": "fileext", + "isDynamic": true + } + ] + } + ] + }, + "assets.root": { + "endpoint": "assets.root", + "rules": [ + { + "args": [ + "filename" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "attachments.add_link": { + "endpoint": "attachments.add_link", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/add/link", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/add/link", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/add/link", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/add/link", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/add/link", + "isDynamic": false + } + ] + } + ] + }, + "attachments.create_folder": { + "endpoint": "attachments.create_folder", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/create-folder", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/create-folder", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/create-folder", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/create-folder", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/create-folder", + "isDynamic": false + } + ] + } + ] + }, + "attachments.delete_attachment": { + "endpoint": "attachments.delete_attachment", + "rules": [ + { + "args": [ + "attachment_id", + "confId", + "contrib_id", + "folder_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "contrib_id", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "folder_id", + "object_type", + "session_id" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "folder_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "category_id", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "category_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "attachments.delete_folder": { + "endpoint": "attachments.delete_folder", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "folder_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "folder_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "folder_id", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "folder_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "folder_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "folder_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "attachments.download": { + "endpoint": "attachments.download", + "rules": [ + { + "args": [ + "attachment_id", + "confId", + "contrib_id", + "filename", + "folder_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "attachment_id": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "contrib_id", + "filename", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "filename", + "folder_id", + "object_type", + "session_id" + ], + "converters": { + "attachment_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "filename", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "attachment_id", + "category_id", + "filename", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "attachments.edit_folder": { + "endpoint": "attachments.edit_folder", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "folder_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "folder_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "folder_id", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "folder_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "folder_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "folder_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "attachments.list_folder": { + "endpoint": "attachments.list_folder", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "folder_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "folder_id", + "object_type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "folder_id", + "object_type", + "session_id" + ], + "converters": { + "folder_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "folder_id", + "object_type" + ], + "converters": { + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "attachments.management": { + "endpoint": "attachments.management", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "attachments.management_info_column": { + "endpoint": "attachments.management_info_column", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/info-column", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/info-column", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/info-column", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/info-column", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/info-column", + "isDynamic": false + } + ] + } + ] + }, + "attachments.modify_attachment": { + "endpoint": "attachments.modify_attachment", + "rules": [ + { + "args": [ + "attachment_id", + "confId", + "contrib_id", + "folder_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "contrib_id", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "folder_id", + "object_type", + "session_id" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "folder_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "confId", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "confId": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "attachment_id", + "category_id", + "folder_id", + "object_type" + ], + "converters": { + "attachment_id": "IntegerConverter", + "category_id": "IntegerConverter", + "folder_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/", + "isDynamic": false + }, + { + "data": "folder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "attachment_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "attachments.package": { + "endpoint": "attachments.package", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/attachments/package", + "isDynamic": false + } + ] + } + ] + }, + "attachments.package_management": { + "endpoint": "attachments.package_management", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/package", + "isDynamic": false + } + ] + } + ] + }, + "attachments.upload": { + "endpoint": "attachments.upload", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/attachments/add/files", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "confId": "IntegerConverter", + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/attachments/add/files", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "confId": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/attachments/add/files", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/attachments/add/files", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/attachments/add/files", + "isDynamic": false + } + ] + } + ] + }, + "auth.accounts": { + "endpoint": "auth.accounts", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/accounts", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/accounts", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "auth.admin_impersonate": { + "endpoint": "auth.admin_impersonate", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/impersonate", + "isDynamic": false + } + ] + } + ] + }, + "auth.link_account": { + "endpoint": "auth.link_account", + "rules": [ + { + "args": [ + "provider" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/login/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/link-account", + "isDynamic": false + } + ] + } + ] + }, + "auth.login": { + "endpoint": "auth.login", + "rules": [ + { + "args": [ + "provider" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/login/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/login", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "auth.login_form": { + "endpoint": "auth.login_form", + "rules": [ + { + "args": [ + "provider" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/login/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/form", + "isDynamic": false + } + ] + } + ] + }, + "auth.logout": { + "endpoint": "auth.logout", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/logout", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "auth.register": { + "endpoint": "auth.register", + "rules": [ + { + "args": [ + "provider" + ], + "converters": {}, + "defaults": { + "provider": null + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/register", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "provider" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/register/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + } + ] + } + ] + }, + "auth.remove_account": { + "endpoint": "auth.remove_account", + "rules": [ + { + "args": [ + "identity", + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/accounts/", + "isDynamic": false + }, + { + "data": "identity", + "isDynamic": true + }, + { + "data": "/remove", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "identity" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/accounts/", + "isDynamic": false + }, + { + "data": "identity", + "isDynamic": true + }, + { + "data": "/remove", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "auth.resetpass": { + "endpoint": "auth.resetpass", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/reset-password", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "bootstrap.index": { + "endpoint": "bootstrap.index", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/bootstrap", + "isDynamic": false + } + ] + } + ] + }, + "categories._redirect": { + "endpoint": "categories._redirect", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/categ/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/c/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + } + ] + } + ] + }, + "categories._redirect_event_creation": { + "endpoint": "categories._redirect_event_creation", + "rules": [ + { + "args": [ + "category_id", + "event_type" + ], + "converters": { + "category_id": "IntegerConverter", + "event_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/create/event/", + "isDynamic": false + }, + { + "data": "event_type", + "isDynamic": true + } + ] + } + ] + }, + "categories.calendar": { + "endpoint": "categories.calendar", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/calendar", + "isDynamic": false + } + ] + } + ] + }, + "categories.category_xml_info": { + "endpoint": "categories.category_xml_info", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/xmlGateway.py/getCategoryInfo", + "isDynamic": false + } + ] + } + ] + }, + "categories.create_subcategory": { + "endpoint": "categories.create_subcategory", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/subcategories/create", + "isDynamic": false + } + ] + } + ] + }, + "categories.delete": { + "endpoint": "categories.delete", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/delete", + "isDynamic": false + } + ] + } + ] + }, + "categories.delete_events": { + "endpoint": "categories.delete_events", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/events/delete", + "isDynamic": false + } + ] + } + ] + }, + "categories.delete_subcategories": { + "endpoint": "categories.delete_subcategories", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/subcategories/delete", + "isDynamic": false + } + ] + } + ] + }, + "categories.display": { + "endpoint": "categories.display", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": {}, + "defaults": { + "category_id": 0 + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "categories.display_icon": { + "endpoint": "categories.display_icon", + "rules": [ + { + "args": [ + "category_id", + "slug" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/icon-", + "isDynamic": false + }, + { + "data": "slug", + "isDynamic": true + }, + { + "data": ".png", + "isDynamic": false + } + ] + } + ] + }, + "categories.display_logo": { + "endpoint": "categories.display_logo", + "rules": [ + { + "args": [ + "category_id", + "slug" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/logo-", + "isDynamic": false + }, + { + "data": "slug", + "isDynamic": true + }, + { + "data": ".png", + "isDynamic": false + } + ] + } + ] + }, + "categories.event_list": { + "endpoint": "categories.event_list", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/event-list", + "isDynamic": false + } + ] + } + ] + }, + "categories.export_atom": { + "endpoint": "categories.export_atom", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/events.atom", + "isDynamic": false + } + ] + } + ] + }, + "categories.export_ical": { + "endpoint": "categories.export_ical", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/events.ics", + "isDynamic": false + } + ] + } + ] + }, + "categories.export_rss": { + "endpoint": "categories.export_rss", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/events.rss", + "isDynamic": false + } + ] + } + ] + }, + "categories.info": { + "endpoint": "categories.info", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/info", + "isDynamic": false + } + ] + } + ] + }, + "categories.info_from": { + "endpoint": "categories.info_from", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/info-from", + "isDynamic": false + } + ] + } + ] + }, + "categories.manage_content": { + "endpoint": "categories.manage_content", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "categories.manage_icon": { + "endpoint": "categories.manage_icon", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/icon", + "isDynamic": false + } + ] + } + ] + }, + "categories.manage_logo": { + "endpoint": "categories.manage_logo", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/logo", + "isDynamic": false + } + ] + } + ] + }, + "categories.manage_protection": { + "endpoint": "categories.manage_protection", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/protection", + "isDynamic": false + } + ] + } + ] + }, + "categories.manage_settings": { + "endpoint": "categories.manage_settings", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/settings", + "isDynamic": false + } + ] + } + ] + }, + "categories.manage_upcoming": { + "endpoint": "categories.manage_upcoming", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/upcoming-events", + "isDynamic": false + } + ] + } + ] + }, + "categories.move": { + "endpoint": "categories.move", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/move", + "isDynamic": false + } + ] + } + ] + }, + "categories.move_events": { + "endpoint": "categories.move_events", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/events/move", + "isDynamic": false + } + ] + } + ] + }, + "categories.move_subcategories": { + "endpoint": "categories.move_subcategories", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/subcategories/move", + "isDynamic": false + } + ] + } + ] + }, + "categories.overview": { + "endpoint": "categories.overview", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/overview", + "isDynamic": false + } + ] + } + ] + }, + "categories.search": { + "endpoint": "categories.search", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/search", + "isDynamic": false + } + ] + } + ] + }, + "categories.show_future_events": { + "endpoint": "categories.show_future_events", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/show-future-events", + "isDynamic": false + } + ] + } + ] + }, + "categories.show_past_events": { + "endpoint": "categories.show_past_events", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/show-past-events", + "isDynamic": false + } + ] + } + ] + }, + "categories.sort_subcategories": { + "endpoint": "categories.sort_subcategories", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/subcategories/sort", + "isDynamic": false + } + ] + } + ] + }, + "categories.split_category": { + "endpoint": "categories.split_category", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/events/split", + "isDynamic": false + } + ] + } + ] + }, + "categories.statistics": { + "endpoint": "categories.statistics", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/statistics", + "isDynamic": false + } + ] + } + ] + }, + "categories.subcat_info": { + "endpoint": "categories.subcat_info", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/subcat-info", + "isDynamic": false + } + ] + } + ] + }, + "categories.upcoming_event": { + "endpoint": "categories.upcoming_event", + "rules": [ + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/upcoming", + "isDynamic": false + } + ] + } + ] + }, + "celery.index": { + "endpoint": "celery.index", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/tasks", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "cephalopod.index": { + "endpoint": "cephalopod.index", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/community-hub", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "cephalopod.sync": { + "endpoint": "cephalopod.sync", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/community-hub/sync", + "isDynamic": false + } + ] + } + ] + }, + "cephalopod.system-info": { + "endpoint": "cephalopod.system-info", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/system-info", + "isDynamic": false + } + ] + } + ] + }, + "contributions.acl": { + "endpoint": "contributions.acl", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/acl", + "isDynamic": false + } + ] + } + ] + }, + "contributions.acl_message": { + "endpoint": "contributions.acl_message", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/acl-message", + "isDynamic": false + } + ] + } + ] + }, + "contributions.author_list": { + "endpoint": "contributions.author_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/authors", + "isDynamic": false + } + ] + } + ] + }, + "contributions.clone_contribution": { + "endpoint": "contributions.clone_contribution", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/clone", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contribution_list": { + "endpoint": "contributions.contribution_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contribution_list_pdf": { + "endpoint": "contributions.contribution_list_pdf", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/contributions.pdf", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contribution_list_static_url": { + "endpoint": "contributions.contribution_list_static_url", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/static-url", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contributions_csv_export": { + "endpoint": "contributions.contributions_csv_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/contributions.csv", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contributions_excel_export": { + "endpoint": "contributions.contributions_excel_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/contributions.xlsx", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contributions_import": { + "endpoint": "contributions.contributions_import", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/import", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contributions_pdf_export": { + "endpoint": "contributions.contributions_pdf_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/contributions.pdf", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contributions_tex_export": { + "endpoint": "contributions.contributions_tex_export", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/contributions.zip", + "isDynamic": false + } + ] + } + ] + }, + "contributions.contributions_tex_export_book": { + "endpoint": "contributions.contributions_tex_export_book", + "rules": [ + { + "args": [ + "confId", + "uuid" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/tex-export/", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "contributions.contributions_tex_export_dialog": { + "endpoint": "contributions.contributions_tex_export_dialog", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/tex-export-dialog", + "isDynamic": false + } + ] + } + ] + }, + "contributions.create_contrib_reference_rest": { + "endpoint": "contributions.create_contrib_reference_rest", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/references", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.create_field": { + "endpoint": "contributions.create_field", + "rules": [ + { + "args": [ + "confId", + "field_type" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/fields/create/", + "isDynamic": false + }, + { + "data": "field_type", + "isDynamic": true + } + ] + } + ] + }, + "contributions.create_subcontrib_reference_rest": { + "endpoint": "contributions.create_subcontrib_reference_rest", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/references", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.create_subcontrib_rest": { + "endpoint": "contributions.create_subcontrib_rest", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.create_type": { + "endpoint": "contributions.create_type", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/types/create", + "isDynamic": false + } + ] + } + ] + }, + "contributions.customize_contrib_list": { + "endpoint": "contributions.customize_contrib_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/customize", + "isDynamic": false + } + ] + } + ] + }, + "contributions.customize_contribution_list": { + "endpoint": "contributions.customize_contribution_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/customize", + "isDynamic": false + } + ] + } + ] + }, + "contributions.delete_field": { + "endpoint": "contributions.delete_field", + "rules": [ + { + "args": [ + "confId", + "contrib_field_id" + ], + "converters": { + "contrib_field_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/fields/", + "isDynamic": false + }, + { + "data": "contrib_field_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "contributions.delete_type": { + "endpoint": "contributions.delete_type", + "rules": [ + { + "args": [ + "confId", + "contrib_type_id" + ], + "converters": { + "contrib_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/types/", + "isDynamic": false + }, + { + "data": "contrib_type_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "contributions.display_author": { + "endpoint": "contributions.display_author", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "person_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "person_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/author/", + "isDynamic": false + }, + { + "data": "person_id", + "isDynamic": true + } + ] + } + ] + }, + "contributions.display_contribution": { + "endpoint": "contributions.display_contribution", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.display_subcontribution": { + "endpoint": "contributions.display_subcontribution", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + } + ] + } + ] + }, + "contributions.export_ics": { + "endpoint": "contributions.export_ics", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/contribution.ics", + "isDynamic": false + } + ] + } + ] + }, + "contributions.export_pdf": { + "endpoint": "contributions.export_pdf", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/contribution.pdf", + "isDynamic": false + } + ] + } + ] + }, + "contributions.generate_static_url": { + "endpoint": "contributions.generate_static_url", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/static-url", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_contrib_protection": { + "endpoint": "contributions.manage_contrib_protection", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/protection", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_contrib_rest": { + "endpoint": "contributions.manage_contrib_rest", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + } + ] + } + ] + }, + "contributions.manage_contributions": { + "endpoint": "contributions.manage_contributions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_create_contrib": { + "endpoint": "contributions.manage_create_contrib", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/create", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_create_subcontrib": { + "endpoint": "contributions.manage_create_subcontrib", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/create", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_default_duration": { + "endpoint": "contributions.manage_default_duration", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/duration", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_delete_contribs": { + "endpoint": "contributions.manage_delete_contribs", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/delete", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_delete_subcontribs": { + "endpoint": "contributions.manage_delete_subcontribs", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/delete", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_description_field": { + "endpoint": "contributions.manage_description_field", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/fields/description", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_duration": { + "endpoint": "contributions.manage_duration", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/duration", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_edit_subcontrib": { + "endpoint": "contributions.manage_edit_subcontrib", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_field": { + "endpoint": "contributions.manage_field", + "rules": [ + { + "args": [ + "confId", + "contrib_field_id" + ], + "converters": { + "contrib_field_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/fields/", + "isDynamic": false + }, + { + "data": "contrib_field_id", + "isDynamic": true + } + ] + } + ] + }, + "contributions.manage_fields": { + "endpoint": "contributions.manage_fields", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/fields", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_publication": { + "endpoint": "contributions.manage_publication", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/published", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_start_date": { + "endpoint": "contributions.manage_start_date", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/start-date", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_subcontrib_rest": { + "endpoint": "contributions.manage_subcontrib_rest", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + } + ] + } + ] + }, + "contributions.manage_subcontributions": { + "endpoint": "contributions.manage_subcontributions", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_type": { + "endpoint": "contributions.manage_type", + "rules": [ + { + "args": [ + "confId", + "contrib_type_id" + ], + "converters": { + "contrib_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/types/", + "isDynamic": false + }, + { + "data": "contrib_type_id", + "isDynamic": true + } + ] + } + ] + }, + "contributions.manage_types": { + "endpoint": "contributions.manage_types", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/types", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "contributions.manage_update_contrib": { + "endpoint": "contributions.manage_update_contrib", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "contributions.material_package": { + "endpoint": "contributions.material_package", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/material-package", + "isDynamic": false + } + ] + } + ] + }, + "contributions.my_contributions": { + "endpoint": "contributions.my_contributions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/mine", + "isDynamic": false + } + ] + } + ] + }, + "contributions.person_list": { + "endpoint": "contributions.person_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/person-list", + "isDynamic": false + } + ] + } + ] + }, + "contributions.sort_fields": { + "endpoint": "contributions.sort_fields", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/fields/sort", + "isDynamic": false + } + ] + } + ] + }, + "contributions.sort_subcontributions": { + "endpoint": "contributions.sort_subcontributions", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/sort", + "isDynamic": false + } + ] + } + ] + }, + "contributions.speaker_list": { + "endpoint": "contributions.speaker_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/speakers", + "isDynamic": false + } + ] + } + ] + }, + "core.admin_dashboard": { + "endpoint": "core.admin_dashboard", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "core.change_lang": { + "endpoint": "core.change_lang", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/change-language", + "isDynamic": false + } + ] + } + ] + }, + "core.change_tz": { + "endpoint": "core.change_tz", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/change-timezone", + "isDynamic": false + } + ] + } + ] + }, + "core.contact": { + "endpoint": "core.contact", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/contact", + "isDynamic": false + } + ] + } + ] + }, + "core.ping": { + "endpoint": "core.ping", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/ping", + "isDynamic": false + } + ] + } + ] + }, + "core.principals": { + "endpoint": "core.principals", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/principals", + "isDynamic": false + } + ] + } + ] + }, + "core.report_error_api": { + "endpoint": "core.report_error_api", + "rules": [ + { + "args": [ + "error_id" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/report-error/api/", + "isDynamic": false + }, + { + "data": "error_id", + "isDynamic": true + } + ] + } + ] + }, + "core.reset_signature_tokens": { + "endpoint": "core.reset_signature_tokens", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/reset-signature-tokens", + "isDynamic": false + } + ] + } + ] + }, + "core.settings": { + "endpoint": "core.settings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/settings", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "core.sign_url": { + "endpoint": "core.sign_url", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/sign-url", + "isDynamic": false + } + ] + } + ] + }, + "core.version_check": { + "endpoint": "core.version_check", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/version-check", + "isDynamic": false + } + ] + } + ] + }, + "designer.add_template": { + "endpoint": "designer.add_template", + "rules": [ + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/add", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/add", + "isDynamic": false + } + ] + } + ] + }, + "designer.backside_template_list": { + "endpoint": "designer.backside_template_list", + "rules": [ + { + "args": [ + "confId", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/backsides", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/backsides", + "isDynamic": false + } + ] + } + ] + }, + "designer.clone_template": { + "endpoint": "designer.clone_template", + "rules": [ + { + "args": [ + "confId", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/clone", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/clone", + "isDynamic": false + } + ] + } + ] + }, + "designer.delete_template": { + "endpoint": "designer.delete_template", + "rules": [ + { + "args": [ + "confId", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "designer.download_image": { + "endpoint": "designer.download_image", + "rules": [ + { + "args": [ + "confId", + "filename", + "image_id", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "image_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/images/", + "isDynamic": false + }, + { + "data": "image_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + }, + { + "args": [ + "category_id", + "filename", + "image_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "image_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/images/", + "isDynamic": false + }, + { + "data": "image_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "designer.edit_template": { + "endpoint": "designer.edit_template", + "rules": [ + { + "args": [ + "confId", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "designer.get_template_data": { + "endpoint": "designer.get_template_data", + "rules": [ + { + "args": [ + "confId", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/data", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/data", + "isDynamic": false + } + ] + } + ] + }, + "designer.template_list": { + "endpoint": "designer.template_list", + "rules": [ + { + "args": [ + "confId", + "object_type" + ], + "converters": { + "confId": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "designer.toggle_category_default": { + "endpoint": "designer.toggle_category_default", + "rules": [ + { + "args": [ + "category_id", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/toggle-default", + "isDynamic": false + } + ] + } + ] + }, + "designer.upload_image": { + "endpoint": "designer.upload_image", + "rules": [ + { + "args": [ + "confId", + "object_type", + "template_id" + ], + "converters": { + "confId": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/images", + "isDynamic": false + } + ] + }, + { + "args": [ + "category_id", + "object_type", + "template_id" + ], + "converters": { + "category_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": { + "object_type": "category" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/category/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + }, + { + "data": "/manage/designer/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/images", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_confirm_changes": { + "endpoint": "event_editing.api_confirm_changes", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/confirm", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_create_comment": { + "endpoint": "event_editing.api_create_comment", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/comments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_create_editable": { + "endpoint": "event_editing.api_create_editable", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + } + ] + } + ] + }, + "event_editing.api_create_submitter_revision": { + "endpoint": "event_editing.api_create_submitter_revision", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/new", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_create_tag": { + "endpoint": "event_editing.api_create_tag", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/editing/api/tags", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_edit_comment": { + "endpoint": "event_editing.api_edit_comment", + "rules": [ + { + "args": [ + "comment_id", + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "comment_id": "IntegerConverter", + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/comments/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + } + ] + }, + "event_editing.api_edit_tag": { + "endpoint": "event_editing.api_edit_tag", + "rules": [ + { + "args": [ + "confId", + "tag_id" + ], + "converters": { + "tag_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/editing/api/tag/", + "isDynamic": false + }, + { + "data": "tag_id", + "isDynamic": true + } + ] + } + ] + }, + "event_editing.api_editable": { + "endpoint": "event_editing.api_editable", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + } + ] + } + ] + }, + "event_editing.api_file_types": { + "endpoint": "event_editing.api_file_types", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/editing/api/file-types", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_replace_revision": { + "endpoint": "event_editing.api_replace_revision", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/replace", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_review_editable": { + "endpoint": "event_editing.api_review_editable", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/review", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_tags": { + "endpoint": "event_editing.api_tags", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/editing/api/tags", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_undo_review": { + "endpoint": "event_editing.api_undo_review", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/review", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.api_upload": { + "endpoint": "event_editing.api_upload", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/upload", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.dashboard": { + "endpoint": "event_editing.dashboard", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/editing", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.download_file": { + "endpoint": "event_editing.download_file", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "file_id", + "filename", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "file_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "file_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "event_editing.editable": { + "endpoint": "event_editing.editable", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + } + ] + } + ] + }, + "event_editing.manage_tags": { + "endpoint": "event_editing.manage_tags", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/editing/tags", + "isDynamic": false + } + ] + } + ] + }, + "event_editing.revision_files_export": { + "endpoint": "event_editing.revision_files_export", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "revision_id", + "type" + ], + "converters": { + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/editing/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/files.zip", + "isDynamic": false + } + ] + } + ] + }, + "event_features.index": { + "endpoint": "event_features.index", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/features", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_features.switch": { + "endpoint": "event_features.switch", + "rules": [ + { + "args": [ + "confId", + "feature" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/features/", + "isDynamic": false + }, + { + "data": "feature", + "isDynamic": true + } + ] + } + ] + }, + "event_images.image_display": { + "endpoint": "event_images.image_display", + "rules": [ + { + "args": [ + "confId", + "filename", + "image_id" + ], + "converters": { + "image_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/images/", + "isDynamic": false + }, + { + "data": "image_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "event_images.logo_display": { + "endpoint": "event_images.logo_display", + "rules": [ + { + "args": [ + "confId", + "slug" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/logo-", + "isDynamic": false + }, + { + "data": "slug", + "isDynamic": true + }, + { + "data": ".png", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.css_display": { + "endpoint": "event_layout.css_display", + "rules": [ + { + "args": [ + "confId", + "slug" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "slug", + "isDynamic": true + }, + { + "data": ".css", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.css_preview": { + "endpoint": "event_layout.css_preview", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/theme/preview", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.css_save_theme": { + "endpoint": "event_layout.css_save_theme", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/theme/save", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.delete_css": { + "endpoint": "event_layout.delete_css", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/css", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.delete_logo": { + "endpoint": "event_layout.delete_logo", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/logo", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.image_delete": { + "endpoint": "event_layout.image_delete", + "rules": [ + { + "args": [ + "confId", + "filename", + "image_id" + ], + "converters": { + "image_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/images/", + "isDynamic": false + }, + { + "data": "image_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "event_layout.images": { + "endpoint": "event_layout.images", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/images", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.images_upload": { + "endpoint": "event_layout.images_upload", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/images/upload", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.index": { + "endpoint": "event_layout.index", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu": { + "endpoint": "event_layout.menu", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_add_entry": { + "endpoint": "event_layout.menu_add_entry", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/add", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_delete_entry": { + "endpoint": "event_layout.menu_delete_entry", + "rules": [ + { + "args": [ + "confId", + "menu_entry_id" + ], + "converters": { + "menu_entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/", + "isDynamic": false + }, + { + "data": "menu_entry_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_entry_edit": { + "endpoint": "event_layout.menu_entry_edit", + "rules": [ + { + "args": [ + "confId", + "menu_entry_id" + ], + "converters": { + "menu_entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/", + "isDynamic": false + }, + { + "data": "menu_entry_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_entry_position": { + "endpoint": "event_layout.menu_entry_position", + "rules": [ + { + "args": [ + "confId", + "menu_entry_id" + ], + "converters": { + "menu_entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/", + "isDynamic": false + }, + { + "data": "menu_entry_id", + "isDynamic": true + }, + { + "data": "/position", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_entry_toggle_default": { + "endpoint": "event_layout.menu_entry_toggle_default", + "rules": [ + { + "args": [ + "confId", + "menu_entry_id" + ], + "converters": { + "menu_entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/", + "isDynamic": false + }, + { + "data": "menu_entry_id", + "isDynamic": true + }, + { + "data": "/toggle-default", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_entry_toggle_enabled": { + "endpoint": "event_layout.menu_entry_toggle_enabled", + "rules": [ + { + "args": [ + "confId", + "menu_entry_id" + ], + "converters": { + "menu_entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/", + "isDynamic": false + }, + { + "data": "menu_entry_id", + "isDynamic": true + }, + { + "data": "/toggle-enabled", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.menu_toggle_custom": { + "endpoint": "event_layout.menu_toggle_custom", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/menu/toggle-customize", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.timetable_theme_form": { + "endpoint": "event_layout.timetable_theme_form", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/timetable-theme-form", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.upload_css": { + "endpoint": "event_layout.upload_css", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/css", + "isDynamic": false + } + ] + } + ] + }, + "event_layout.upload_logo": { + "endpoint": "event_layout.upload_logo", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/layout/logo", + "isDynamic": false + } + ] + } + ] + }, + "event_logs.index": { + "endpoint": "event_logs.index", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/logs", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_logs.logs": { + "endpoint": "event_logs.logs", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/logs/api/logs", + "isDynamic": false + } + ] + } + ] + }, + "event_management.acl": { + "endpoint": "event_management.acl", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/protection/acl", + "isDynamic": false + } + ] + } + ] + }, + "event_management.acl_message": { + "endpoint": "event_management.acl_message", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/protection/acl-message", + "isDynamic": false + } + ] + } + ] + }, + "event_management.api_principals": { + "endpoint": "event_management.api_principals", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/api/principals", + "isDynamic": false + } + ] + } + ] + }, + "event_management.assign_program_codes_contributions": { + "endpoint": "event_management.assign_program_codes_contributions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/program-codes/assign/contributions", + "isDynamic": false + } + ] + } + ] + }, + "event_management.assign_program_codes_session_blocks": { + "endpoint": "event_management.assign_program_codes_session_blocks", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/program-codes/assign/session-blocks", + "isDynamic": false + } + ] + } + ] + }, + "event_management.assign_program_codes_sessions": { + "endpoint": "event_management.assign_program_codes_sessions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/program-codes/assign/sessions", + "isDynamic": false + } + ] + } + ] + }, + "event_management.assign_program_codes_subcontributions": { + "endpoint": "event_management.assign_program_codes_subcontributions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/program-codes/assign/subcontributions", + "isDynamic": false + } + ] + } + ] + }, + "event_management.change_type": { + "endpoint": "event_management.change_type", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/change-type", + "isDynamic": false + } + ] + } + ] + }, + "event_management.clone": { + "endpoint": "event_management.clone", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/clone", + "isDynamic": false + } + ] + } + ] + }, + "event_management.clone_preview": { + "endpoint": "event_management.clone_preview", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/clone/preview", + "isDynamic": false + } + ] + } + ] + }, + "event_management.delete": { + "endpoint": "event_management.delete", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/delete", + "isDynamic": false + } + ] + } + ] + }, + "event_management.edit_classification": { + "endpoint": "event_management.edit_classification", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/settings/classification", + "isDynamic": false + } + ] + } + ] + }, + "event_management.edit_contact_info": { + "endpoint": "event_management.edit_contact_info", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/settings/contact-info", + "isDynamic": false + } + ] + } + ] + }, + "event_management.edit_data": { + "endpoint": "event_management.edit_data", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/settings/data", + "isDynamic": false + } + ] + } + ] + }, + "event_management.edit_dates": { + "endpoint": "event_management.edit_dates", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/settings/dates", + "isDynamic": false + } + ] + } + ] + }, + "event_management.edit_location": { + "endpoint": "event_management.edit_location", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/settings/location", + "isDynamic": false + } + ] + } + ] + }, + "event_management.edit_persons": { + "endpoint": "event_management.edit_persons", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/settings/persons", + "isDynamic": false + } + ] + } + ] + }, + "event_management.lock": { + "endpoint": "event_management.lock", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/lock", + "isDynamic": false + } + ] + } + ] + }, + "event_management.move": { + "endpoint": "event_management.move", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/move", + "isDynamic": false + } + ] + } + ] + }, + "event_management.permissions_dialog": { + "endpoint": "event_management.permissions_dialog", + "rules": [ + { + "args": [ + "type" + ], + "converters": { + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/permissions-dialog/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + } + ] + } + ] + }, + "event_management.poster_settings": { + "endpoint": "event_management.poster_settings", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/print-poster/settings", + "isDynamic": false + } + ] + } + ] + }, + "event_management.print_poster": { + "endpoint": "event_management.print_poster", + "rules": [ + { + "args": [ + "confId", + "template_id", + "uuid" + ], + "converters": { + "template_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/print-poster/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "event_management.program_code_templates": { + "endpoint": "event_management.program_code_templates", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/program-codes/templates", + "isDynamic": false + } + ] + } + ] + }, + "event_management.program_codes": { + "endpoint": "event_management.program_codes", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/program-codes", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_management.protection": { + "endpoint": "event_management.protection", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/protection", + "isDynamic": false + } + ] + } + ] + }, + "event_management.settings": { + "endpoint": "event_management.settings", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_management.show_non_inheriting": { + "endpoint": "event_management.show_non_inheriting", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/show-non-inheriting", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/show-non-inheriting", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": {}, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/show-non-inheriting", + "isDynamic": false + } + ] + } + ] + }, + "event_management.unlock": { + "endpoint": "event_management.unlock", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/unlock", + "isDynamic": false + } + ] + } + ] + }, + "event_notes.compile": { + "endpoint": "event_notes.compile", + "rules": [ + { + "args": [ + "confId", + "object_type" + ], + "converters": {}, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/note/compile", + "isDynamic": false + } + ] + } + ] + }, + "event_notes.delete": { + "endpoint": "event_notes.delete", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/note/delete", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/note/delete", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/note/delete", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": {}, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/note/delete", + "isDynamic": false + } + ] + } + ] + }, + "event_notes.edit": { + "endpoint": "event_notes.edit", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/note/edit", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/note/edit", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/note/edit", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": {}, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/note/edit", + "isDynamic": false + } + ] + } + ] + }, + "event_notes.view": { + "endpoint": "event_notes.view", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "object_type", + "subcontrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "subcontrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "subcontribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/subcontributions/", + "isDynamic": false + }, + { + "data": "subcontrib_id", + "isDynamic": true + }, + { + "data": "/note", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "contrib_id", + "object_type" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": { + "object_type": "contribution" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/note", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": { + "object_type": "session" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/note", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "object_type" + ], + "converters": {}, + "defaults": { + "object_type": "event" + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/note", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_pages.page_display": { + "endpoint": "event_pages.page_display", + "rules": [ + { + "args": [ + "confId", + "page_id", + "slug" + ], + "converters": { + "page_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/page/", + "isDynamic": false + }, + { + "data": "page_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "slug", + "isDynamic": true + } + ] + }, + { + "args": [ + "confId", + "page_id" + ], + "converters": { + "page_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/page/", + "isDynamic": false + }, + { + "data": "page_id", + "isDynamic": true + } + ] + } + ] + }, + "event_participation.manage": { + "endpoint": "event_participation.manage", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/participants", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.add_field": { + "endpoint": "event_registration.add_field", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/fields", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.add_section": { + "endpoint": "event_registration.add_section", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.add_text": { + "endpoint": "event_registration.add_text", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.api_registrant": { + "endpoint": "event_registration.api_registrant", + "rules": [ + { + "args": [ + "event_id", + "registrant_id" + ], + "converters": { + "event_id": "IntegerConverter", + "registrant_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/events/", + "isDynamic": false + }, + { + "data": "event_id", + "isDynamic": true + }, + { + "data": "/registrants/", + "isDynamic": false + }, + { + "data": "registrant_id", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.api_registrants": { + "endpoint": "event_registration.api_registrants", + "rules": [ + { + "args": [ + "event_id" + ], + "converters": { + "event_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/events/", + "isDynamic": false + }, + { + "data": "event_id", + "isDynamic": true + }, + { + "data": "/registrants", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.approve_registration": { + "endpoint": "event_registration.approve_registration", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "registration_id" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/approve", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.check_email": { + "endpoint": "event_registration.check_email", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/check-email", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.close_regform": { + "endpoint": "event_registration.close_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/close", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.create_multiple_registrations": { + "endpoint": "event_registration.create_multiple_registrations", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/create-multiple", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.create_regform": { + "endpoint": "event_registration.create_regform", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/create", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.create_registration": { + "endpoint": "event_registration.create_registration", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/create", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.customize_reglist": { + "endpoint": "event_registration.customize_reglist", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/customize", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.decline_invitation": { + "endpoint": "event_registration.decline_invitation", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/decline-invitation", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.delete_invitation": { + "endpoint": "event_registration.delete_invitation", + "rules": [ + { + "args": [ + "confId", + "invitation_id", + "reg_form_id" + ], + "converters": { + "invitation_id": "IntegerConverter", + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/invitations/", + "isDynamic": false + }, + { + "data": "invitation_id", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.delete_regform": { + "endpoint": "event_registration.delete_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.delete_registrations": { + "endpoint": "event_registration.delete_registrations", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/delete", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.display_regform": { + "endpoint": "event_registration.display_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.display_regform_list": { + "endpoint": "event_registration.display_regform_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.edit_regform": { + "endpoint": "event_registration.edit_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.edit_registration": { + "endpoint": "event_registration.edit_registration", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "registration_id" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.edit_registration_display": { + "endpoint": "event_registration.edit_registration_display", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.email_registrants": { + "endpoint": "event_registration.email_registrants", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/email", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.email_registrants_preview": { + "endpoint": "event_registration.email_registrants_preview", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/email-preview", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.generate_static_url": { + "endpoint": "event_registration.generate_static_url", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/static-url", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.invitations": { + "endpoint": "event_registration.invitations", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/invitations", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.invite": { + "endpoint": "event_registration.invite", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/invitations/invite", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manage_regform": { + "endpoint": "event_registration.manage_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manage_regform_display": { + "endpoint": "event_registration.manage_regform_display", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/display", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manage_regform_list": { + "endpoint": "event_registration.manage_regform_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manage_regforms_display": { + "endpoint": "event_registration.manage_regforms_display", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/display", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manage_registration_managers": { + "endpoint": "event_registration.manage_registration_managers", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/managers", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manage_reglist": { + "endpoint": "event_registration.manage_reglist", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.manager_decline_invitation": { + "endpoint": "event_registration.manager_decline_invitation", + "rules": [ + { + "args": [ + "confId", + "invitation_id", + "reg_form_id" + ], + "converters": { + "invitation_id": "IntegerConverter", + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/invitations/", + "isDynamic": false + }, + { + "data": "invitation_id", + "isDynamic": true + }, + { + "data": "/decline", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.modify_field": { + "endpoint": "event_registration.modify_field", + "rules": [ + { + "args": [ + "confId", + "field_id", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/fields/", + "isDynamic": false + }, + { + "data": "field_id", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.modify_regform": { + "endpoint": "event_registration.modify_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.modify_section": { + "endpoint": "event_registration.modify_section", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.modify_text": { + "endpoint": "event_registration.modify_text", + "rules": [ + { + "args": [ + "confId", + "field_id", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text/", + "isDynamic": false + }, + { + "data": "field_id", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.move_field": { + "endpoint": "event_registration.move_field", + "rules": [ + { + "args": [ + "confId", + "field_id", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/fields/", + "isDynamic": false + }, + { + "data": "field_id", + "isDynamic": true + }, + { + "data": "/move", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.move_section": { + "endpoint": "event_registration.move_section", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/move", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.move_text": { + "endpoint": "event_registration.move_text", + "rules": [ + { + "args": [ + "confId", + "field_id", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text/", + "isDynamic": false + }, + { + "data": "field_id", + "isDynamic": true + }, + { + "data": "/move", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.open_regform": { + "endpoint": "event_registration.open_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/open", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.participant_list": { + "endpoint": "event_registration.participant_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/participants", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.regform_stats": { + "endpoint": "event_registration.regform_stats", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/stats", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registration_check_in": { + "endpoint": "event_registration.registration_check_in", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "registration_id" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/check-in", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registration_details": { + "endpoint": "event_registration.registration_details", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "registration_id" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registration_file": { + "endpoint": "event_registration.registration_file", + "rules": [ + { + "args": [ + "confId", + "field_data_id", + "filename", + "reg_form_id", + "registration_id" + ], + "converters": { + "field_data_id": "IntegerConverter", + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/file/", + "isDynamic": false + }, + { + "data": "field_data_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.registrations_attachments_export": { + "endpoint": "event_registration.registrations_attachments_export", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/attachments", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_check_in": { + "endpoint": "event_registration.registrations_check_in", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/check-in", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_config_badges": { + "endpoint": "event_registration.registrations_config_badges", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/badges/config", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_config_tickets": { + "endpoint": "event_registration.registrations_config_tickets", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/tickets/config", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_csv_export": { + "endpoint": "event_registration.registrations_csv_export", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/registrations.csv", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_excel_export": { + "endpoint": "event_registration.registrations_excel_export", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/registrations.xlsx", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_import": { + "endpoint": "event_registration.registrations_import", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/import", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_modify_status": { + "endpoint": "event_registration.registrations_modify_status", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/modify-status", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_pdf_export_book": { + "endpoint": "event_registration.registrations_pdf_export_book", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/book.pdf", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_pdf_export_table": { + "endpoint": "event_registration.registrations_pdf_export_table", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/table.pdf", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.registrations_print_badges": { + "endpoint": "event_registration.registrations_print_badges", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "template_id", + "uuid" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "template_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/badges/print/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "event_registration.reject_registration": { + "endpoint": "event_registration.reject_registration", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "registration_id" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/reject", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.schedule_regform": { + "endpoint": "event_registration.schedule_regform", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/schedule", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.ticket_download": { + "endpoint": "event_registration.ticket_download", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/ticket.pdf", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.tickets": { + "endpoint": "event_registration.tickets", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/tickets", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.tickets_qrcode": { + "endpoint": "event_registration.tickets_qrcode", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/tickets/qrcode", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.tickets_qrcode_image": { + "endpoint": "event_registration.tickets_qrcode_image", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/tickets/qrcode.png", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.toggle_field": { + "endpoint": "event_registration.toggle_field", + "rules": [ + { + "args": [ + "confId", + "field_id", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/fields/", + "isDynamic": false + }, + { + "data": "field_id", + "isDynamic": true + }, + { + "data": "/toggle", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.toggle_registration_payment": { + "endpoint": "event_registration.toggle_registration_payment", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "registration_id" + ], + "converters": { + "reg_form_id": "IntegerConverter", + "registration_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "registration_id", + "isDynamic": true + }, + { + "data": "/toggle-payment", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.toggle_section": { + "endpoint": "event_registration.toggle_section", + "rules": [ + { + "args": [ + "confId", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/toggle", + "isDynamic": false + } + ] + } + ] + }, + "event_registration.toggle_text": { + "endpoint": "event_registration.toggle_text", + "rules": [ + { + "args": [ + "confId", + "field_id", + "reg_form_id", + "section_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/registration/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/form/sections/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text/", + "isDynamic": false + }, + { + "data": "field_id", + "isDynamic": true + }, + { + "data": "/toggle", + "isDynamic": false + } + ] + } + ] + }, + "event_reminders.add": { + "endpoint": "event_reminders.add", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/reminders/add", + "isDynamic": false + } + ] + } + ] + }, + "event_reminders.delete": { + "endpoint": "event_reminders.delete", + "rules": [ + { + "args": [ + "confId", + "reminder_id" + ], + "converters": { + "reminder_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/reminders/", + "isDynamic": false + }, + { + "data": "reminder_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "event_reminders.edit": { + "endpoint": "event_reminders.edit", + "rules": [ + { + "args": [ + "confId", + "reminder_id" + ], + "converters": { + "reminder_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/reminders/", + "isDynamic": false + }, + { + "data": "reminder_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_reminders.list": { + "endpoint": "event_reminders.list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/reminders", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_reminders.preview": { + "endpoint": "event_reminders.preview", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/reminders/preview", + "isDynamic": false + } + ] + } + ] + }, + "event_roles.add_members": { + "endpoint": "event_roles.add_members", + "rules": [ + { + "args": [ + "confId", + "role_id" + ], + "converters": { + "role_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/roles/", + "isDynamic": false + }, + { + "data": "role_id", + "isDynamic": true + }, + { + "data": "/members", + "isDynamic": false + } + ] + } + ] + }, + "event_roles.add_role": { + "endpoint": "event_roles.add_role", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/roles/create", + "isDynamic": false + } + ] + } + ] + }, + "event_roles.delete_role": { + "endpoint": "event_roles.delete_role", + "rules": [ + { + "args": [ + "confId", + "role_id" + ], + "converters": { + "role_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/roles/", + "isDynamic": false + }, + { + "data": "role_id", + "isDynamic": true + } + ] + } + ] + }, + "event_roles.edit_role": { + "endpoint": "event_roles.edit_role", + "rules": [ + { + "args": [ + "confId", + "role_id" + ], + "converters": { + "role_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/roles/", + "isDynamic": false + }, + { + "data": "role_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "event_roles.manage": { + "endpoint": "event_roles.manage", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/roles", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "event_roles.remove_member": { + "endpoint": "event_roles.remove_member", + "rules": [ + { + "args": [ + "confId", + "role_id", + "user_id" + ], + "converters": { + "role_id": "IntegerConverter", + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/roles/", + "isDynamic": false + }, + { + "data": "role_id", + "isDynamic": true + }, + { + "data": "/members/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + } + ] + } + ] + }, + "events.create": { + "endpoint": "events.create", + "rules": [ + { + "args": [ + "event_type" + ], + "converters": { + "event_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/create/", + "isDynamic": false + }, + { + "data": "event_type", + "isDynamic": true + } + ] + } + ] + }, + "events.create_reference_type": { + "endpoint": "events.create_reference_type", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/external-id-types/create", + "isDynamic": false + } + ] + } + ] + }, + "events.delete_reference_type": { + "endpoint": "events.delete_reference_type", + "rules": [ + { + "args": [ + "reference_type_id" + ], + "converters": { + "reference_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/external-id-types/", + "isDynamic": false + }, + { + "data": "reference_type_id", + "isDynamic": true + } + ] + } + ] + }, + "events.display": { + "endpoint": "events.display", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "events.display_other": { + "endpoint": "events.display_other", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/other-view", + "isDynamic": false + } + ] + } + ] + }, + "events.display_overview": { + "endpoint": "events.display_overview", + "rules": [ + { + "args": [ + "confId", + "force_overview" + ], + "converters": {}, + "defaults": { + "force_overview": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/overview", + "isDynamic": false + } + ] + } + ] + }, + "events.export_event_ical": { + "endpoint": "events.export_event_ical", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/event.ics", + "isDynamic": false + } + ] + } + ] + }, + "events.key_access": { + "endpoint": "events.key_access", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/key-access", + "isDynamic": false + } + ] + } + ] + }, + "events.marcxml": { + "endpoint": "events.marcxml", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/event.marc.xml", + "isDynamic": false + } + ] + } + ] + }, + "events.reference_types": { + "endpoint": "events.reference_types", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/external-id-types", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "events.shorturl": { + "endpoint": "events.shorturl", + "rules": [ + { + "args": [ + "confId", + "shorturl_namespace" + ], + "converters": { + "confId": "PathConverter" + }, + "defaults": { + "shorturl_namespace": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/e/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + } + ] + } + ] + }, + "events.update_reference_type": { + "endpoint": "events.update_reference_type", + "rules": [ + { + "args": [ + "reference_type_id" + ], + "converters": { + "reference_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/external-id-types/", + "isDynamic": false + }, + { + "data": "reference_type_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "files.delete_file": { + "endpoint": "files.delete_file", + "rules": [ + { + "args": [ + "uuid" + ], + "converters": { + "uuid": "UUIDConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/files/", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "files.file_info": { + "endpoint": "files.file_info", + "rules": [ + { + "args": [ + "uuid" + ], + "converters": { + "uuid": "UUIDConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/files/", + "isDynamic": false + }, + { + "data": "uuid", + "isDynamic": true + } + ] + } + ] + }, + "groups.group_add": { + "endpoint": "groups.group_add", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups/indico/new", + "isDynamic": false + } + ] + } + ] + }, + "groups.group_delete": { + "endpoint": "groups.group_delete", + "rules": [ + { + "args": [ + "group_id", + "provider" + ], + "converters": { + "group_id": "IntegerConverter", + "provider": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "group_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "groups.group_delete_member": { + "endpoint": "groups.group_delete_member", + "rules": [ + { + "args": [ + "group_id", + "provider", + "user_id" + ], + "converters": { + "group_id": "IntegerConverter", + "provider": "AnyConverter", + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "group_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + } + ] + } + ] + }, + "groups.group_details": { + "endpoint": "groups.group_details", + "rules": [ + { + "args": [ + "group_id", + "provider" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "group_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "groups.group_edit": { + "endpoint": "groups.group_edit", + "rules": [ + { + "args": [ + "group_id", + "provider" + ], + "converters": { + "group_id": "IntegerConverter", + "provider": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "group_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "groups.group_members": { + "endpoint": "groups.group_members", + "rules": [ + { + "args": [ + "group_id", + "provider" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups/", + "isDynamic": false + }, + { + "data": "provider", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "group_id", + "isDynamic": true + }, + { + "data": "/members", + "isDynamic": false + } + ] + } + ] + }, + "groups.group_search": { + "endpoint": "groups.group_search", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/groups/api/search", + "isDynamic": false + } + ] + } + ] + }, + "groups.groups": { + "endpoint": "groups.groups", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/groups", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "legal.display_privacy": { + "endpoint": "legal.display_privacy", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/privacy", + "isDynamic": false + } + ] + } + ] + }, + "legal.display_tos": { + "endpoint": "legal.display_tos", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/tos", + "isDynamic": false + } + ] + } + ] + }, + "legal.manage": { + "endpoint": "legal.manage", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/legal", + "isDynamic": false + } + ] + } + ] + }, + "networks.create_group": { + "endpoint": "networks.create_group", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/networks/create", + "isDynamic": false + } + ] + } + ] + }, + "networks.delete_group": { + "endpoint": "networks.delete_group", + "rules": [ + { + "args": [ + "network_group_id" + ], + "converters": { + "network_group_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/networks/", + "isDynamic": false + }, + { + "data": "network_group_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "networks.edit_group": { + "endpoint": "networks.edit_group", + "rules": [ + { + "args": [ + "network_group_id" + ], + "converters": { + "network_group_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/networks/", + "isDynamic": false + }, + { + "data": "network_group_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "networks.manage": { + "endpoint": "networks.manage", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/networks", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "news.create_news": { + "endpoint": "news.create_news", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/news/create", + "isDynamic": false + } + ] + } + ] + }, + "news.delete_news": { + "endpoint": "news.delete_news", + "rules": [ + { + "args": [ + "news_id" + ], + "converters": { + "news_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/news/", + "isDynamic": false + }, + { + "data": "news_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "news.display": { + "endpoint": "news.display", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/news", + "isDynamic": false + } + ] + } + ] + }, + "news.edit_news": { + "endpoint": "news.edit_news", + "rules": [ + { + "args": [ + "news_id" + ], + "converters": { + "news_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/news/", + "isDynamic": false + }, + { + "data": "news_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "news.manage": { + "endpoint": "news.manage", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/news", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "news.settings": { + "endpoint": "news.settings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/news/settings", + "isDynamic": false + } + ] + } + ] + }, + "oauth.app_delete": { + "endpoint": "oauth.app_delete", + "rules": [ + { + "args": [ + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/apps/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "oauth.app_details": { + "endpoint": "oauth.app_details", + "rules": [ + { + "args": [ + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/apps/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "oauth.app_new": { + "endpoint": "oauth.app_new", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/apps/new", + "isDynamic": false + } + ] + } + ] + }, + "oauth.app_reset": { + "endpoint": "oauth.app_reset", + "rules": [ + { + "args": [ + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/apps/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/reset", + "isDynamic": false + } + ] + } + ] + }, + "oauth.app_revoke": { + "endpoint": "oauth.app_revoke", + "rules": [ + { + "args": [ + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/apps/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/revoke", + "isDynamic": false + } + ] + } + ] + }, + "oauth.apps": { + "endpoint": "oauth.apps", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/apps", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "oauth.oauth_authorize": { + "endpoint": "oauth.oauth_authorize", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/oauth/authorize", + "isDynamic": false + } + ] + } + ] + }, + "oauth.oauth_errors": { + "endpoint": "oauth.oauth_errors", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/oauth/errors", + "isDynamic": false + } + ] + } + ] + }, + "oauth.oauth_token": { + "endpoint": "oauth.oauth_token", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/oauth/token", + "isDynamic": false + } + ] + } + ] + }, + "oauth.user_profile": { + "endpoint": "oauth.user_profile", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/applications", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/applications", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "oauth.user_token_revoke": { + "endpoint": "oauth.user_token_revoke", + "rules": [ + { + "args": [ + "id", + "user_id" + ], + "converters": { + "id": "IntegerConverter", + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/applications/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/revoke", + "isDynamic": false + } + ] + }, + { + "args": [ + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/applications/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": "/revoke", + "isDynamic": false + } + ] + } + ] + }, + "papers.api_delete_comment": { + "endpoint": "papers.api_delete_comment", + "rules": [ + { + "args": [ + "comment_id", + "confId", + "contrib_id", + "revision_id" + ], + "converters": { + "comment_id": "IntegerConverter", + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/api/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/revision/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/comment/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + } + ] + }, + "papers.api_judge_paper": { + "endpoint": "papers.api_judge_paper", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/api/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/judge", + "isDynamic": false + } + ] + } + ] + }, + "papers.api_paper_details": { + "endpoint": "papers.api_paper_details", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/api/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + } + ] + } + ] + }, + "papers.api_reset_paper_state": { + "endpoint": "papers.api_reset_paper_state", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/api/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + } + ] + } + ] + }, + "papers.api_submit_comment": { + "endpoint": "papers.api_submit_comment", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/api/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/comment", + "isDynamic": false + } + ] + } + ] + }, + "papers.api_submit_revision": { + "endpoint": "papers.api_submit_revision", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/api/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/paper/submit", + "isDynamic": false + } + ] + } + ] + }, + "papers.assign_papers": { + "endpoint": "papers.assign_papers", + "rules": [ + { + "args": [ + "confId", + "management", + "role" + ], + "converters": { + "role": "AnyConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/assignment-list/assign/", + "isDynamic": false + }, + { + "data": "role", + "isDynamic": true + } + ] + }, + { + "args": [ + "confId", + "management", + "role" + ], + "converters": { + "role": "AnyConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/judging/assign/", + "isDynamic": false + }, + { + "data": "role", + "isDynamic": true + } + ] + } + ] + }, + "papers.call_for_papers": { + "endpoint": "papers.call_for_papers", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.close_cfp": { + "endpoint": "papers.close_cfp", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/close", + "isDynamic": false + } + ] + } + ] + }, + "papers.contact_staff": { + "endpoint": "papers.contact_staff", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/teams/contact", + "isDynamic": false + } + ] + } + ] + }, + "papers.create_reviewing_question": { + "endpoint": "papers.create_reviewing_question", + "rules": [ + { + "args": [ + "confId", + "review_type" + ], + "converters": { + "review_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/questions/", + "isDynamic": false + }, + { + "data": "review_type", + "isDynamic": true + }, + { + "data": "/create", + "isDynamic": false + } + ] + } + ] + }, + "papers.customize_paper_list": { + "endpoint": "papers.customize_paper_list", + "rules": [ + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/assignment-list/customize", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/judging/customize", + "isDynamic": false + } + ] + } + ] + }, + "papers.delete_comment": { + "endpoint": "papers.delete_comment", + "rules": [ + { + "args": [ + "comment_id", + "confId", + "contrib_id", + "revision_id" + ], + "converters": { + "comment_id": "IntegerConverter", + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/revision/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/comment/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + } + ] + }, + "papers.delete_reviewing_question": { + "endpoint": "papers.delete_reviewing_question", + "rules": [ + { + "args": [ + "confId", + "question_id", + "review_type" + ], + "converters": { + "question_id": "IntegerConverter", + "review_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/questions/", + "isDynamic": false + }, + { + "data": "review_type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "question_id", + "isDynamic": true + } + ] + } + ] + }, + "papers.delete_template": { + "endpoint": "papers.delete_template", + "rules": [ + { + "args": [ + "confId", + "filename", + "template_id" + ], + "converters": { + "template_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/templates/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "papers.download_file": { + "endpoint": "papers.download_file", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "file_id", + "filename" + ], + "converters": { + "contrib_id": "IntegerConverter", + "file_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/files/", + "isDynamic": false + }, + { + "data": "file_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "papers.download_papers": { + "endpoint": "papers.download_papers", + "rules": [ + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/assignment-list/download", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/judging/download", + "isDynamic": false + } + ] + } + ] + }, + "papers.download_template": { + "endpoint": "papers.download_template", + "rules": [ + { + "args": [ + "confId", + "filename", + "template_id" + ], + "converters": { + "template_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/templates/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "papers.edit_comment": { + "endpoint": "papers.edit_comment", + "rules": [ + { + "args": [ + "comment_id", + "confId", + "contrib_id", + "revision_id" + ], + "converters": { + "comment_id": "IntegerConverter", + "contrib_id": "IntegerConverter", + "revision_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/revision/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/comment/", + "isDynamic": false + }, + { + "data": "comment_id", + "isDynamic": true + } + ] + } + ] + }, + "papers.edit_review": { + "endpoint": "papers.edit_review", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "review_id", + "revision_id" + ], + "converters": { + "contrib_id": "IntegerConverter", + "review_id": "IntegerConverter", + "revision_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/revision/", + "isDynamic": false + }, + { + "data": "revision_id", + "isDynamic": true + }, + { + "data": "/review/", + "isDynamic": false + }, + { + "data": "review_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "papers.edit_reviewing_question": { + "endpoint": "papers.edit_reviewing_question", + "rules": [ + { + "args": [ + "confId", + "question_id", + "review_type" + ], + "converters": { + "question_id": "IntegerConverter", + "review_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/questions/", + "isDynamic": false + }, + { + "data": "review_type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "question_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "papers.edit_template": { + "endpoint": "papers.edit_template", + "rules": [ + { + "args": [ + "confId", + "filename", + "template_id" + ], + "converters": { + "template_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/templates/", + "isDynamic": false + }, + { + "data": "template_id", + "isDynamic": true + }, + { + "data": "-", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "papers.judge_paper": { + "endpoint": "papers.judge_paper", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/judgment", + "isDynamic": false + } + ] + } + ] + }, + "papers.judge_papers": { + "endpoint": "papers.judge_papers", + "rules": [ + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/assignment-list/judge", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/judging/judge", + "isDynamic": false + } + ] + } + ] + }, + "papers.manage_competences": { + "endpoint": "papers.manage_competences", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/teams/competences", + "isDynamic": false + } + ] + } + ] + }, + "papers.manage_deadline": { + "endpoint": "papers.manage_deadline", + "rules": [ + { + "args": [ + "confId", + "role" + ], + "converters": { + "role": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/deadlines/", + "isDynamic": false + }, + { + "data": "role", + "isDynamic": true + } + ] + } + ] + }, + "papers.manage_reviewing_questions": { + "endpoint": "papers.manage_reviewing_questions", + "rules": [ + { + "args": [ + "confId", + "review_type" + ], + "converters": { + "review_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/questions/", + "isDynamic": false + }, + { + "data": "review_type", + "isDynamic": true + } + ] + } + ] + }, + "papers.manage_reviewing_settings": { + "endpoint": "papers.manage_reviewing_settings", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/settings", + "isDynamic": false + } + ] + } + ] + }, + "papers.manage_teams": { + "endpoint": "papers.manage_teams", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/teams", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.manage_templates": { + "endpoint": "papers.manage_templates", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/templates", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.management": { + "endpoint": "papers.management", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.new_paper_timeline": { + "endpoint": "papers.new_paper_timeline", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/new", + "isDynamic": false + } + ] + } + ] + }, + "papers.open_cfp": { + "endpoint": "papers.open_cfp", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/open", + "isDynamic": false + } + ] + } + ] + }, + "papers.paper_timeline": { + "endpoint": "papers.paper_timeline", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.papers_list": { + "endpoint": "papers.papers_list", + "rules": [ + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/assignment-list", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "management" + ], + "converters": {}, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/judging", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.reset_paper_state": { + "endpoint": "papers.reset_paper_state", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/judgment", + "isDynamic": false + } + ] + } + ] + }, + "papers.reviewing_area": { + "endpoint": "papers.reviewing_area", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/reviewing", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "papers.schedule_cfp": { + "endpoint": "papers.schedule_cfp", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/schedule", + "isDynamic": false + } + ] + } + ] + }, + "papers.select_contribution": { + "endpoint": "papers.select_contribution", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/select-contribution", + "isDynamic": false + } + ] + } + ] + }, + "papers.sort_reviewing_questions": { + "endpoint": "papers.sort_reviewing_questions", + "rules": [ + { + "args": [ + "confId", + "review_type" + ], + "converters": { + "review_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/questions/", + "isDynamic": false + }, + { + "data": "review_type", + "isDynamic": true + }, + { + "data": "/sort", + "isDynamic": false + } + ] + } + ] + }, + "papers.submit_comment": { + "endpoint": "papers.submit_comment", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/comment", + "isDynamic": false + } + ] + } + ] + }, + "papers.submit_review": { + "endpoint": "papers.submit_review", + "rules": [ + { + "args": [ + "confId", + "contrib_id", + "review_type" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/review/type/", + "isDynamic": false + }, + { + "data": "review_type", + "isDynamic": true + } + ] + } + ] + }, + "papers.submit_revision": { + "endpoint": "papers.submit_revision", + "rules": [ + { + "args": [ + "confId", + "contrib_id" + ], + "converters": { + "contrib_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/contributions/", + "isDynamic": false + }, + { + "data": "contrib_id", + "isDynamic": true + }, + { + "data": "/paper/submit", + "isDynamic": false + } + ] + } + ] + }, + "papers.switch": { + "endpoint": "papers.switch", + "rules": [ + { + "args": [ + "confId", + "reviewing_type" + ], + "converters": { + "reviewing_type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/enable/", + "isDynamic": false + }, + { + "data": "reviewing_type", + "isDynamic": true + } + ] + } + ] + }, + "papers.unassign_papers": { + "endpoint": "papers.unassign_papers", + "rules": [ + { + "args": [ + "confId", + "management", + "role" + ], + "converters": { + "role": "AnyConverter" + }, + "defaults": { + "management": true + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/assignment-list/unassign/", + "isDynamic": false + }, + { + "data": "role", + "isDynamic": true + } + ] + }, + { + "args": [ + "confId", + "management", + "role" + ], + "converters": { + "role": "AnyConverter" + }, + "defaults": { + "management": false + }, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/papers/judging/unassign/", + "isDynamic": false + }, + { + "data": "role", + "isDynamic": true + } + ] + } + ] + }, + "papers.upload_template": { + "endpoint": "papers.upload_template", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/papers/templates/add", + "isDynamic": false + } + ] + } + ] + }, + "payment.admin_plugin_settings": { + "endpoint": "payment.admin_plugin_settings", + "rules": [ + { + "args": [ + "plugin" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/payment/", + "isDynamic": false + }, + { + "data": "plugin", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "payment.admin_settings": { + "endpoint": "payment.admin_settings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/payment", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "payment.event_payment": { + "endpoint": "payment.event_payment", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/checkout", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "payment.event_payment_conditions": { + "endpoint": "payment.event_payment_conditions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/payment/conditions", + "isDynamic": false + } + ] + } + ] + }, + "payment.event_payment_form": { + "endpoint": "payment.event_payment_form", + "rules": [ + { + "args": [ + "confId", + "reg_form_id" + ], + "converters": { + "reg_form_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/registrations/", + "isDynamic": false + }, + { + "data": "reg_form_id", + "isDynamic": true + }, + { + "data": "/checkout/form", + "isDynamic": false + } + ] + } + ] + }, + "payment.event_plugin_edit": { + "endpoint": "payment.event_plugin_edit", + "rules": [ + { + "args": [ + "confId", + "method" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/payments/method/", + "isDynamic": false + }, + { + "data": "method", + "isDynamic": true + } + ] + } + ] + }, + "payment.event_settings": { + "endpoint": "payment.event_settings", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/payments", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "payment.event_settings_edit": { + "endpoint": "payment.event_settings_edit", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/payments/settings", + "isDynamic": false + } + ] + } + ] + }, + "persons.edit_person": { + "endpoint": "persons.edit_person", + "rules": [ + { + "args": [ + "confId", + "person_id" + ], + "converters": { + "person_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/persons/", + "isDynamic": false + }, + { + "data": "person_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "persons.email_event_persons": { + "endpoint": "persons.email_event_persons", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/persons/email", + "isDynamic": false + } + ] + } + ] + }, + "persons.grant_modification_rights": { + "endpoint": "persons.grant_modification_rights", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/persons/grant-modification", + "isDynamic": false + } + ] + } + ] + }, + "persons.grant_submission_rights": { + "endpoint": "persons.grant_submission_rights", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/persons/grant-submission", + "isDynamic": false + } + ] + } + ] + }, + "persons.person_list": { + "endpoint": "persons.person_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/persons", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "persons.revoke_submission_rights": { + "endpoint": "persons.revoke_submission_rights", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/persons/revoke-submission", + "isDynamic": false + } + ] + } + ] + }, + "plugin_vc_zoom.set_room_owner": { + "endpoint": "plugin_vc_zoom.set_room_owner", + "rules": [ + { + "args": [ + "confId", + "event_vc_room_id", + "service" + ], + "converters": { + "event_vc_room_id": "IntegerConverter", + "service": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "event_vc_room_id", + "isDynamic": true + }, + { + "data": "/room-owner", + "isDynamic": false + } + ] + } + ] + }, + "plugin_vc_zoom.static": { + "endpoint": "plugin_vc_zoom.static", + "rules": [ + { + "args": [ + "filename" + ], + "converters": { + "filename": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/static/plugins/vc_zoom/", + "isDynamic": false + }, + { + "data": "filename", + "isDynamic": true + } + ] + } + ] + }, + "plugins.details": { + "endpoint": "plugins.details", + "rules": [ + { + "args": [ + "plugin" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/plugins/", + "isDynamic": false + }, + { + "data": "plugin", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "plugins.index": { + "endpoint": "plugins.index", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/plugins", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.404": { + "endpoint": "rb.404", + "rules": [ + { + "args": [ + "path" + ], + "converters": { + "path": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/", + "isDynamic": false + }, + { + "data": "path", + "isDynamic": true + } + ] + } + ] + }, + "rb.active_bookings": { + "endpoint": "rb.active_bookings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/active", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_attributes": { + "endpoint": "rb.admin_attributes", + "rules": [ + { + "args": [ + "attribute_id" + ], + "converters": { + "attribute_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/attributes/", + "isDynamic": false + }, + { + "data": "attribute_id", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/attributes", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_equipment_types": { + "endpoint": "rb.admin_equipment_types", + "rules": [ + { + "args": [ + "equipment_type_id" + ], + "converters": { + "equipment_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/equipment-types/", + "isDynamic": false + }, + { + "data": "equipment_type_id", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/equipment-types", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_features": { + "endpoint": "rb.admin_features", + "rules": [ + { + "args": [ + "feature_id" + ], + "converters": { + "feature_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/features/", + "isDynamic": false + }, + { + "data": "feature_id", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/features", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_locations": { + "endpoint": "rb.admin_locations", + "rules": [ + { + "args": [ + "location_id" + ], + "converters": { + "location_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/locations/", + "isDynamic": false + }, + { + "data": "location_id", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/locations", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_map_areas": { + "endpoint": "rb.admin_map_areas", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/map-areas", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_room": { + "endpoint": "rb.admin_room", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.admin_room_attributes": { + "endpoint": "rb.admin_room_attributes", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/attributes", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_room_availability": { + "endpoint": "rb.admin_room_availability", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/availability", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_room_equipment": { + "endpoint": "rb.admin_room_equipment", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/equipment", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_room_photo": { + "endpoint": "rb.admin_room_photo", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/photo", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_rooms": { + "endpoint": "rb.admin_rooms", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_settings": { + "endpoint": "rb.admin_settings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/settings", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_update_room_attributes": { + "endpoint": "rb.admin_update_room_attributes", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/attributes", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_update_room_availability": { + "endpoint": "rb.admin_update_room_availability", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/availability", + "isDynamic": false + } + ] + } + ] + }, + "rb.admin_update_room_equipment": { + "endpoint": "rb.admin_update_room_equipment", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/admin/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/equipment", + "isDynamic": false + } + ] + } + ] + }, + "rb.blocking": { + "endpoint": "rb.blocking", + "rules": [ + { + "args": [ + "blocking_id" + ], + "converters": { + "blocking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/blockings/", + "isDynamic": false + }, + { + "data": "blocking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.blocking_actions": { + "endpoint": "rb.blocking_actions", + "rules": [ + { + "args": [ + "action", + "blocking_id", + "room_id" + ], + "converters": { + "action": "AnyConverter", + "blocking_id": "IntegerConverter", + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/blockings/", + "isDynamic": false + }, + { + "data": "blocking_id", + "isDynamic": true + }, + { + "data": "/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "action", + "isDynamic": true + } + ] + } + ] + }, + "rb.blocking_link": { + "endpoint": "rb.blocking_link", + "rules": [ + { + "args": [ + "blocking_id" + ], + "converters": { + "blocking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/blocking/", + "isDynamic": false + }, + { + "data": "blocking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.blockings": { + "endpoint": "rb.blockings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/blockings", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.booking_details": { + "endpoint": "rb.booking_details", + "rules": [ + { + "args": [ + "booking_id" + ], + "converters": { + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.booking_edit_calendars": { + "endpoint": "rb.booking_edit_calendars", + "rules": [ + { + "args": [ + "booking_id" + ], + "converters": { + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + }, + { + "data": "/edit/calendars", + "isDynamic": false + } + ] + } + ] + }, + "rb.booking_link": { + "endpoint": "rb.booking_link", + "rules": [ + { + "args": [ + "booking_id" + ], + "converters": { + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/booking/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.booking_occurrence_state_actions": { + "endpoint": "rb.booking_occurrence_state_actions", + "rules": [ + { + "args": [ + "action", + "booking_id", + "date" + ], + "converters": { + "action": "AnyConverter", + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "date", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "action", + "isDynamic": true + } + ] + } + ] + }, + "rb.booking_state_actions": { + "endpoint": "rb.booking_state_actions", + "rules": [ + { + "args": [ + "action", + "booking_id" + ], + "converters": { + "action": "AnyConverter", + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "action", + "isDynamic": true + } + ] + } + ] + }, + "rb.calendar": { + "endpoint": "rb.calendar", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/calendar", + "isDynamic": false + } + ] + } + ] + }, + "rb.check_room_available": { + "endpoint": "rb.check_room_available", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/availability/simple", + "isDynamic": false + } + ] + } + ] + }, + "rb.config": { + "endpoint": "rb.config", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/config", + "isDynamic": false + } + ] + } + ] + }, + "rb.create_blocking": { + "endpoint": "rb.create_blocking", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/blockings", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.create_booking": { + "endpoint": "rb.create_booking", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/booking/create", + "isDynamic": false + } + ] + } + ] + }, + "rb.delete_blocking": { + "endpoint": "rb.delete_blocking", + "rules": [ + { + "args": [ + "blocking_id" + ], + "converters": { + "blocking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/blockings/", + "isDynamic": false + }, + { + "data": "blocking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.delete_booking": { + "endpoint": "rb.delete_booking", + "rules": [ + { + "args": [ + "booking_id" + ], + "converters": { + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.equipment_types": { + "endpoint": "rb.equipment_types", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/equipment", + "isDynamic": false + } + ] + } + ] + }, + "rb.event_booking_list": { + "endpoint": "rb.event_booking_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/rooms", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.event_linkable_contributions": { + "endpoint": "rb.event_linkable_contributions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/rooms/linking/contributions", + "isDynamic": false + } + ] + } + ] + }, + "rb.event_linkable_session_blocks": { + "endpoint": "rb.event_linkable_session_blocks", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/rooms/linking/session-blocks", + "isDynamic": false + } + ] + } + ] + }, + "rb.events": { + "endpoint": "rb.events", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/events", + "isDynamic": false + } + ] + } + ] + }, + "rb.export_bookings": { + "endpoint": "rb.export_bookings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/export", + "isDynamic": false + } + ] + } + ] + }, + "rb.export_bookings_file": { + "endpoint": "rb.export_bookings_file", + "rules": [ + { + "args": [ + "format" + ], + "converters": { + "format": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/bookings/export/bookings.", + "isDynamic": false + }, + { + "data": "format", + "isDynamic": true + } + ] + } + ] + }, + "rb.favorite_rooms": { + "endpoint": "rb.favorite_rooms", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/user/favorite-rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/user/favorite-rooms", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.linked_object_data": { + "endpoint": "rb.linked_object_data", + "rules": [ + { + "args": [ + "id", + "type" + ], + "converters": { + "id": "IntegerConverter", + "type": "AnyConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/link-info/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + } + ] + } + ] + }, + "rb.locations": { + "endpoint": "rb.locations", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/locations", + "isDynamic": false + } + ] + } + ] + }, + "rb.map_areas": { + "endpoint": "rb.map_areas", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/map-areas", + "isDynamic": false + } + ] + } + ] + }, + "rb.my_bookings": { + "endpoint": "rb.my_bookings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/mine", + "isDynamic": false + } + ] + } + ] + }, + "rb.my_bookings_link": { + "endpoint": "rb.my_bookings_link", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/my-bookings", + "isDynamic": false + } + ] + } + ] + }, + "rb.permission_types": { + "endpoint": "rb.permission_types", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/permission-types", + "isDynamic": false + } + ] + } + ] + }, + "rb.room": { + "endpoint": "rb.room", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.room_attributes": { + "endpoint": "rb.room_attributes", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/attributes", + "isDynamic": false + } + ] + } + ] + }, + "rb.room_availability": { + "endpoint": "rb.room_availability", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/availability", + "isDynamic": false + } + ] + } + ] + }, + "rb.room_link": { + "endpoint": "rb.room_link", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/room/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.room_permissions": { + "endpoint": "rb.room_permissions", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/permissions", + "isDynamic": false + } + ] + } + ] + }, + "rb.room_photo": { + "endpoint": "rb.room_photo", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": ".jpg", + "isDynamic": false + } + ] + } + ] + }, + "rb.room_stats": { + "endpoint": "rb.room_stats", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/stats", + "isDynamic": false + } + ] + } + ] + }, + "rb.roombooking": { + "endpoint": "rb.roombooking", + "rules": [ + { + "args": [ + "path" + ], + "converters": { + "path": "PathConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/", + "isDynamic": false + }, + { + "data": "path", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.rooms": { + "endpoint": "rb.rooms", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "rb.rooms_permissions": { + "endpoint": "rb.rooms_permissions", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/permissions", + "isDynamic": false + } + ] + } + ] + }, + "rb.search_rooms": { + "endpoint": "rb.search_rooms", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/search", + "isDynamic": false + } + ] + } + ] + }, + "rb.sprite": { + "endpoint": "rb.sprite", + "rules": [ + { + "args": [ + "version" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/rooms-sprite-", + "isDynamic": false + }, + { + "data": "version", + "isDynamic": true + }, + { + "data": ".jpg", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/rooms-sprite.jpg", + "isDynamic": false + } + ] + } + ] + }, + "rb.stats": { + "endpoint": "rb.stats", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/stats", + "isDynamic": false + } + ] + } + ] + }, + "rb.suggestions": { + "endpoint": "rb.suggestions", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/suggestions", + "isDynamic": false + } + ] + } + ] + }, + "rb.timeline": { + "endpoint": "rb.timeline", + "rules": [ + { + "args": [ + "room_id" + ], + "converters": { + "room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/rooms/", + "isDynamic": false + }, + { + "data": "room_id", + "isDynamic": true + }, + { + "data": "/timeline", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/timeline", + "isDynamic": false + } + ] + } + ] + }, + "rb.update_blocking": { + "endpoint": "rb.update_blocking", + "rules": [ + { + "args": [ + "blocking_id" + ], + "converters": { + "blocking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/blockings/", + "isDynamic": false + }, + { + "data": "blocking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.update_booking": { + "endpoint": "rb.update_booking", + "rules": [ + { + "args": [ + "booking_id" + ], + "converters": { + "booking_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/bookings/", + "isDynamic": false + }, + { + "data": "booking_id", + "isDynamic": true + } + ] + } + ] + }, + "rb.user_info": { + "endpoint": "rb.user_info", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/rooms/api/user", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "requests.event_requests": { + "endpoint": "requests.event_requests", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/requests", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "requests.event_requests_details": { + "endpoint": "requests.event_requests_details", + "rules": [ + { + "args": [ + "confId", + "type" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/requests/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "requests.event_requests_process": { + "endpoint": "requests.event_requests_process", + "rules": [ + { + "args": [ + "confId", + "type" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/requests/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/process", + "isDynamic": false + } + ] + } + ] + }, + "requests.event_requests_withdraw": { + "endpoint": "requests.event_requests_withdraw", + "rules": [ + { + "args": [ + "confId", + "type" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/requests/", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + }, + { + "data": "/withdraw", + "isDynamic": false + } + ] + } + ] + }, + "sessions.acl": { + "endpoint": "sessions.acl", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/acl", + "isDynamic": false + } + ] + } + ] + }, + "sessions.acl_message": { + "endpoint": "sessions.acl_message", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/acl-message", + "isDynamic": false + } + ] + } + ] + }, + "sessions.create_session": { + "endpoint": "sessions.create_session", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/create", + "isDynamic": false + } + ] + } + ] + }, + "sessions.create_type": { + "endpoint": "sessions.create_type", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/types/create", + "isDynamic": false + } + ] + } + ] + }, + "sessions.delete_sessions": { + "endpoint": "sessions.delete_sessions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/delete", + "isDynamic": false + } + ] + } + ] + }, + "sessions.delete_type": { + "endpoint": "sessions.delete_type", + "rules": [ + { + "args": [ + "confId", + "session_type_id" + ], + "converters": { + "session_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/types/", + "isDynamic": false + }, + { + "data": "session_type_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "sessions.display_session": { + "endpoint": "sessions.display_session", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "sessions.export_csv": { + "endpoint": "sessions.export_csv", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/sessions.csv", + "isDynamic": false + } + ] + } + ] + }, + "sessions.export_excel": { + "endpoint": "sessions.export_excel", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/sessions.xlsx", + "isDynamic": false + } + ] + } + ] + }, + "sessions.export_ics": { + "endpoint": "sessions.export_ics", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/session.ics", + "isDynamic": false + } + ] + } + ] + }, + "sessions.export_pdf": { + "endpoint": "sessions.export_pdf", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/sessions.pdf", + "isDynamic": false + } + ] + } + ] + }, + "sessions.export_session_timetable": { + "endpoint": "sessions.export_session_timetable", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/session-timetable.pdf", + "isDynamic": false + } + ] + } + ] + }, + "sessions.manage_session_block": { + "endpoint": "sessions.manage_session_block", + "rules": [ + { + "args": [ + "block_id", + "confId", + "session_id" + ], + "converters": { + "block_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/blocks/", + "isDynamic": false + }, + { + "data": "block_id", + "isDynamic": true + } + ] + } + ] + }, + "sessions.manage_type": { + "endpoint": "sessions.manage_type", + "rules": [ + { + "args": [ + "confId", + "session_type_id" + ], + "converters": { + "session_type_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/types/", + "isDynamic": false + }, + { + "data": "session_type_id", + "isDynamic": true + } + ] + } + ] + }, + "sessions.manage_types": { + "endpoint": "sessions.manage_types", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/types", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "sessions.modify_session": { + "endpoint": "sessions.modify_session", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/modify", + "isDynamic": false + } + ] + } + ] + }, + "sessions.my_sessions": { + "endpoint": "sessions.my_sessions", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/sessions/mine", + "isDynamic": false + } + ] + } + ] + }, + "sessions.person_list": { + "endpoint": "sessions.person_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/person-list", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "sessions.session_blocks": { + "endpoint": "sessions.session_blocks", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/blocks", + "isDynamic": false + } + ] + } + ] + }, + "sessions.session_list": { + "endpoint": "sessions.session_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "sessions.session_protection": { + "endpoint": "sessions.session_protection", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/protection", + "isDynamic": false + } + ] + } + ] + }, + "sessions.session_rest": { + "endpoint": "sessions.session_rest", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/sessions/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + } + ] + } + ] + }, + "static_site.build": { + "endpoint": "static_site.build", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/offline-copy/build", + "isDynamic": false + } + ] + } + ] + }, + "static_site.download": { + "endpoint": "static_site.download", + "rules": [ + { + "args": [ + "confId", + "id" + ], + "converters": { + "id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/offline-copy/", + "isDynamic": false + }, + { + "data": "id", + "isDynamic": true + }, + { + "data": ".zip", + "isDynamic": false + } + ] + } + ] + }, + "static_site.list": { + "endpoint": "static_site.list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/offline-copy", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.add_question": { + "endpoint": "surveys.add_question", + "rules": [ + { + "args": [ + "confId", + "section_id", + "survey_id", + "type" + ], + "converters": { + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/question/add-", + "isDynamic": false + }, + { + "data": "type", + "isDynamic": true + } + ] + } + ] + }, + "surveys.add_section": { + "endpoint": "surveys.add_section", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/add-section", + "isDynamic": false + } + ] + } + ] + }, + "surveys.add_text": { + "endpoint": "surveys.add_text", + "rules": [ + { + "args": [ + "confId", + "section_id", + "survey_id" + ], + "converters": { + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text/add", + "isDynamic": false + } + ] + } + ] + }, + "surveys.close_survey": { + "endpoint": "surveys.close_survey", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/close", + "isDynamic": false + } + ] + } + ] + }, + "surveys.create": { + "endpoint": "surveys.create", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/create", + "isDynamic": false + } + ] + } + ] + }, + "surveys.delete_question": { + "endpoint": "surveys.delete_question", + "rules": [ + { + "args": [ + "confId", + "question_id", + "section_id", + "survey_id" + ], + "converters": { + "question_id": "IntegerConverter", + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/question/", + "isDynamic": false + }, + { + "data": "question_id", + "isDynamic": true + } + ] + } + ] + }, + "surveys.delete_section": { + "endpoint": "surveys.delete_section", + "rules": [ + { + "args": [ + "confId", + "section_id", + "survey_id" + ], + "converters": { + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.delete_submissions": { + "endpoint": "surveys.delete_submissions", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/submissions", + "isDynamic": false + } + ] + } + ] + }, + "surveys.delete_survey": { + "endpoint": "surveys.delete_survey", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "surveys.delete_text": { + "endpoint": "surveys.delete_text", + "rules": [ + { + "args": [ + "confId", + "section_id", + "survey_id", + "text_id" + ], + "converters": { + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter", + "text_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text/", + "isDynamic": false + }, + { + "data": "text_id", + "isDynamic": true + } + ] + } + ] + }, + "surveys.display_save_answers": { + "endpoint": "surveys.display_save_answers", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/save", + "isDynamic": false + } + ] + } + ] + }, + "surveys.display_submission": { + "endpoint": "surveys.display_submission", + "rules": [ + { + "args": [ + "confId", + "submission_id", + "survey_id" + ], + "converters": { + "submission_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/submission/", + "isDynamic": false + }, + { + "data": "submission_id", + "isDynamic": true + } + ] + } + ] + }, + "surveys.display_survey_form": { + "endpoint": "surveys.display_survey_form", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + } + ] + } + ] + }, + "surveys.display_survey_list": { + "endpoint": "surveys.display_survey_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/surveys", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.edit_question": { + "endpoint": "surveys.edit_question", + "rules": [ + { + "args": [ + "confId", + "question_id", + "section_id", + "survey_id" + ], + "converters": { + "question_id": "IntegerConverter", + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/question/", + "isDynamic": false + }, + { + "data": "question_id", + "isDynamic": true + } + ] + } + ] + }, + "surveys.edit_section": { + "endpoint": "surveys.edit_section", + "rules": [ + { + "args": [ + "confId", + "section_id", + "survey_id" + ], + "converters": { + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.edit_survey": { + "endpoint": "surveys.edit_survey", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + } + ] + } + ] + }, + "surveys.edit_text": { + "endpoint": "surveys.edit_text", + "rules": [ + { + "args": [ + "confId", + "section_id", + "survey_id", + "text_id" + ], + "converters": { + "section_id": "IntegerConverter", + "survey_id": "IntegerConverter", + "text_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/", + "isDynamic": false + }, + { + "data": "section_id", + "isDynamic": true + }, + { + "data": "/text/", + "isDynamic": false + }, + { + "data": "text_id", + "isDynamic": true + } + ] + } + ] + }, + "surveys.export_questionnaire": { + "endpoint": "surveys.export_questionnaire", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/survey.json", + "isDynamic": false + } + ] + } + ] + }, + "surveys.export_submissions_csv": { + "endpoint": "surveys.export_submissions_csv", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/submissions.csv", + "isDynamic": false + } + ] + } + ] + }, + "surveys.export_submissions_excel": { + "endpoint": "surveys.export_submissions_excel", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/submissions.xlsx", + "isDynamic": false + } + ] + } + ] + }, + "surveys.import_questionnaire": { + "endpoint": "surveys.import_questionnaire", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/import", + "isDynamic": false + } + ] + } + ] + }, + "surveys.manage_questionnaire": { + "endpoint": "surveys.manage_questionnaire", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.manage_survey": { + "endpoint": "surveys.manage_survey", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.manage_survey_list": { + "endpoint": "surveys.manage_survey_list", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "surveys.open_survey": { + "endpoint": "surveys.open_survey", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/open", + "isDynamic": false + } + ] + } + ] + }, + "surveys.schedule_survey": { + "endpoint": "surveys.schedule_survey", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/schedule", + "isDynamic": false + } + ] + } + ] + }, + "surveys.send_links": { + "endpoint": "surveys.send_links", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/send-links", + "isDynamic": false + } + ] + } + ] + }, + "surveys.sort_items": { + "endpoint": "surveys.sort_items", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/questionnaire/sort", + "isDynamic": false + } + ] + } + ] + }, + "surveys.survey_results": { + "endpoint": "surveys.survey_results", + "rules": [ + { + "args": [ + "confId", + "survey_id" + ], + "converters": { + "survey_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/surveys/", + "isDynamic": false + }, + { + "data": "survey_id", + "isDynamic": true + }, + { + "data": "/results", + "isDynamic": false + } + ] + } + ] + }, + "timetable.add_break": { + "endpoint": "timetable.add_break", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/add-break", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/add-break", + "isDynamic": false + } + ] + } + ] + }, + "timetable.add_contribution": { + "endpoint": "timetable.add_contribution", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/add-contribution", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/add-contribution", + "isDynamic": false + } + ] + } + ] + }, + "timetable.add_session": { + "endpoint": "timetable.add_session", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/add-session", + "isDynamic": false + } + ] + } + ] + }, + "timetable.add_session_block": { + "endpoint": "timetable.add_session_block", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/add-session-block", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/add-session-block", + "isDynamic": false + } + ] + } + ] + }, + "timetable.clone_contribution": { + "endpoint": "timetable.clone_contribution", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/clone-contribution", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/clone-contribution", + "isDynamic": false + } + ] + } + ] + }, + "timetable.delete_entry": { + "endpoint": "timetable.delete_entry", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/delete", + "isDynamic": false + } + ] + } + ] + }, + "timetable.edit_entry": { + "endpoint": "timetable.edit_entry", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/edit", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "timetable.edit_entry_datetime": { + "endpoint": "timetable.edit_entry_datetime", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/edit/datetime", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/edit/datetime", + "isDynamic": false + } + ] + } + ] + }, + "timetable.edit_entry_time": { + "endpoint": "timetable.edit_entry_time", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/edit/time", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/edit/time", + "isDynamic": false + } + ] + } + ] + }, + "timetable.entry_info": { + "endpoint": "timetable.entry_info", + "rules": [ + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/info", + "isDynamic": false + } + ] + } + ] + }, + "timetable.entry_info_manage": { + "endpoint": "timetable.entry_info_manage", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/info", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/info", + "isDynamic": false + } + ] + } + ] + }, + "timetable.export_default_pdf": { + "endpoint": "timetable.export_default_pdf", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/timetable/timetable.pdf", + "isDynamic": false + } + ] + } + ] + }, + "timetable.export_pdf": { + "endpoint": "timetable.export_pdf", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/timetable/pdf", + "isDynamic": false + } + ] + } + ] + }, + "timetable.fit_session_block": { + "endpoint": "timetable.fit_session_block", + "rules": [ + { + "args": [ + "block_id", + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/block/", + "isDynamic": false + }, + { + "data": "block_id", + "isDynamic": true + }, + { + "data": "/fit", + "isDynamic": false + } + ] + }, + { + "args": [ + "block_id", + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/block/", + "isDynamic": false + }, + { + "data": "block_id", + "isDynamic": true + }, + { + "data": "/fit", + "isDynamic": false + } + ] + } + ] + }, + "timetable.legacy_break_rest": { + "endpoint": "timetable.legacy_break_rest", + "rules": [ + { + "args": [ + "break_id", + "confId" + ], + "converters": { + "break_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/break/", + "isDynamic": false + }, + { + "data": "break_id", + "isDynamic": true + } + ] + } + ] + }, + "timetable.manage_session": { + "endpoint": "timetable.manage_session", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "timetable.management": { + "endpoint": "timetable.management", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "timetable.move_entry": { + "endpoint": "timetable.move_entry", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/move", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/move", + "isDynamic": false + } + ] + } + ] + }, + "timetable.not_scheduled": { + "endpoint": "timetable.not_scheduled", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/not-scheduled", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/not-scheduled", + "isDynamic": false + } + ] + } + ] + }, + "timetable.reschedule": { + "endpoint": "timetable.reschedule", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/reschedule", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/reschedule", + "isDynamic": false + } + ] + } + ] + }, + "timetable.schedule": { + "endpoint": "timetable.schedule", + "rules": [ + { + "args": [ + "block_id", + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/block/", + "isDynamic": false + }, + { + "data": "block_id", + "isDynamic": true + }, + { + "data": "/schedule", + "isDynamic": false + } + ] + }, + { + "args": [ + "block_id", + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/block/", + "isDynamic": false + }, + { + "data": "block_id", + "isDynamic": true + }, + { + "data": "/schedule", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/schedule", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/schedule", + "isDynamic": false + } + ] + } + ] + }, + "timetable.session_rest": { + "endpoint": "timetable.session_rest", + "rules": [ + { + "args": [ + "confId", + "session_id" + ], + "converters": { + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "timetable.shift_entries": { + "endpoint": "timetable.shift_entries", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/shift", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/shift", + "isDynamic": false + } + ] + } + ] + }, + "timetable.swap_entries": { + "endpoint": "timetable.swap_entries", + "rules": [ + { + "args": [ + "confId", + "entry_id", + "session_id" + ], + "converters": { + "entry_id": "IntegerConverter", + "session_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/session/", + "isDynamic": false + }, + { + "data": "session_id", + "isDynamic": true + }, + { + "data": "/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/swap", + "isDynamic": false + } + ] + }, + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/entry/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + }, + { + "data": "/swap", + "isDynamic": false + } + ] + } + ] + }, + "timetable.timetable": { + "endpoint": "timetable.timetable", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/timetable", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "timetable.timetable_rest": { + "endpoint": "timetable.timetable_rest", + "rules": [ + { + "args": [ + "confId", + "entry_id" + ], + "converters": { + "entry_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable/", + "isDynamic": false + }, + { + "data": "entry_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/timetable", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "tracks.create_track": { + "endpoint": "tracks.create_track", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/tracks/create", + "isDynamic": false + } + ] + } + ] + }, + "tracks.create_track_group": { + "endpoint": "tracks.create_track_group", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/track-groups/create", + "isDynamic": false + } + ] + } + ] + }, + "tracks.delete_track": { + "endpoint": "tracks.delete_track", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/tracks/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + } + ] + } + ] + }, + "tracks.delete_track_group": { + "endpoint": "tracks.delete_track_group", + "rules": [ + { + "args": [ + "confId", + "track_group_id" + ], + "converters": { + "track_group_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/track-groups/", + "isDynamic": false + }, + { + "data": "track_group_id", + "isDynamic": true + } + ] + } + ] + }, + "tracks.edit_program": { + "endpoint": "tracks.edit_program", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/tracks/program", + "isDynamic": false + } + ] + } + ] + }, + "tracks.edit_track": { + "endpoint": "tracks.edit_track", + "rules": [ + { + "args": [ + "confId", + "track_id" + ], + "converters": { + "track_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/tracks/", + "isDynamic": false + }, + { + "data": "track_id", + "isDynamic": true + } + ] + } + ] + }, + "tracks.edit_track_group": { + "endpoint": "tracks.edit_track_group", + "rules": [ + { + "args": [ + "confId", + "track_group_id" + ], + "converters": { + "track_group_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/track-groups/", + "isDynamic": false + }, + { + "data": "track_group_id", + "isDynamic": true + } + ] + } + ] + }, + "tracks.manage": { + "endpoint": "tracks.manage", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/tracks", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "tracks.program": { + "endpoint": "tracks.program", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/program", + "isDynamic": false + } + ] + } + ] + }, + "tracks.program_pdf": { + "endpoint": "tracks.program_pdf", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/program.pdf", + "isDynamic": false + } + ] + } + ] + }, + "tracks.sort_tracks": { + "endpoint": "tracks.sort_tracks", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/tracks/sort", + "isDynamic": false + } + ] + } + ] + }, + "users.accept_registration_request": { + "endpoint": "users.accept_registration_request", + "rules": [ + { + "args": [ + "request_id" + ], + "converters": { + "request_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/registration-requests/", + "isDynamic": false + }, + { + "data": "request_id", + "isDynamic": true + }, + { + "data": "/accept", + "isDynamic": false + } + ] + } + ] + }, + "users.admins": { + "endpoint": "users.admins", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/admins", + "isDynamic": false + } + ] + } + ] + }, + "users.authenticated_user": { + "endpoint": "users.authenticated_user", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/api/user", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.export_dashboard_ics": { + "endpoint": "users.export_dashboard_ics", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/dashboard.ics", + "isDynamic": false + } + ] + } + ] + }, + "users.favorites_api": { + "endpoint": "users.favorites_api", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api/favorites/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/api/favorites", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.registration_request_list": { + "endpoint": "users.registration_request_list", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/registration-requests", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.reject_registration_request": { + "endpoint": "users.reject_registration_request", + "rules": [ + { + "args": [ + "request_id" + ], + "converters": { + "request_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/registration-requests/", + "isDynamic": false + }, + { + "data": "request_id", + "isDynamic": true + }, + { + "data": "/reject", + "isDynamic": false + } + ] + } + ] + }, + "users.user_dashboard": { + "endpoint": "users.user_dashboard", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/dashboard", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/dashboard", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_emails": { + "endpoint": "users.user_emails", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/emails", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/emails", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_emails_delete": { + "endpoint": "users.user_emails_delete", + "rules": [ + { + "args": [ + "email", + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/emails/", + "isDynamic": false + }, + { + "data": "email", + "isDynamic": true + } + ] + }, + { + "args": [ + "email" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/emails/", + "isDynamic": false + }, + { + "data": "email", + "isDynamic": true + } + ] + } + ] + }, + "users.user_emails_set_primary": { + "endpoint": "users.user_emails_set_primary", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/emails/make-primary", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/emails/make-primary", + "isDynamic": false + } + ] + } + ] + }, + "users.user_emails_verify": { + "endpoint": "users.user_emails_verify", + "rules": [ + { + "args": [ + "token", + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/emails/verify/", + "isDynamic": false + }, + { + "data": "token", + "isDynamic": true + } + ] + }, + { + "args": [ + "token" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/emails/verify/", + "isDynamic": false + }, + { + "data": "token", + "isDynamic": true + } + ] + } + ] + }, + "users.user_favorites": { + "endpoint": "users.user_favorites", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/favorites", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/favorites", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_favorites_category_api": { + "endpoint": "users.user_favorites_category_api", + "rules": [ + { + "args": [ + "category_id", + "user_id" + ], + "converters": { + "category_id": "IntegerConverter", + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/favorites/categories/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/favorites/categories/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + } + ] + } + ] + }, + "users.user_favorites_user_remove": { + "endpoint": "users.user_favorites_user_remove", + "rules": [ + { + "args": [ + "fav_user_id", + "user_id" + ], + "converters": { + "fav_user_id": "IntegerConverter", + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/favorites/users/", + "isDynamic": false + }, + { + "data": "fav_user_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "fav_user_id" + ], + "converters": { + "fav_user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/favorites/users/", + "isDynamic": false + }, + { + "data": "fav_user_id", + "isDynamic": true + } + ] + } + ] + }, + "users.user_favorites_users_add": { + "endpoint": "users.user_favorites_users_add", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/favorites/users", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/favorites/users", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_preferences": { + "endpoint": "users.user_preferences", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/preferences", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/preferences", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_profile": { + "endpoint": "users.user_profile", + "rules": [ + { + "args": [ + "user_id" + ], + "converters": { + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/profile", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + }, + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/profile", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_search": { + "endpoint": "users.user_search", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/search", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.user_search_info": { + "endpoint": "users.user_search_info", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/search/info", + "isDynamic": false + } + ] + } + ] + }, + "users.user_suggestions_remove": { + "endpoint": "users.user_suggestions_remove", + "rules": [ + { + "args": [ + "category_id", + "user_id" + ], + "converters": { + "category_id": "IntegerConverter", + "user_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/", + "isDynamic": false + }, + { + "data": "user_id", + "isDynamic": true + }, + { + "data": "/suggestions/categories/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + } + ] + }, + { + "args": [ + "category_id" + ], + "converters": { + "category_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/user/suggestions/categories/", + "isDynamic": false + }, + { + "data": "category_id", + "isDynamic": true + } + ] + } + ] + }, + "users.users_admin": { + "endpoint": "users.users_admin", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.users_admin_settings": { + "endpoint": "users.users_admin_settings", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/settings", + "isDynamic": false + } + ] + } + ] + }, + "users.users_create": { + "endpoint": "users.users_create", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/create", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.users_merge": { + "endpoint": "users.users_merge", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/merge", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "users.users_merge_check": { + "endpoint": "users.users_merge_check", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/admin/users/merge/check", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "vc.event_videoconference": { + "endpoint": "vc.event_videoconference", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/videoconference", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms": { + "endpoint": "vc.manage_vc_rooms", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_create": { + "endpoint": "vc.manage_vc_rooms_create", + "rules": [ + { + "args": [ + "confId", + "service" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/create", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_modify": { + "endpoint": "vc.manage_vc_rooms_modify", + "rules": [ + { + "args": [ + "confId", + "event_vc_room_id", + "service" + ], + "converters": { + "event_vc_room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "event_vc_room_id", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_refresh": { + "endpoint": "vc.manage_vc_rooms_refresh", + "rules": [ + { + "args": [ + "confId", + "event_vc_room_id", + "service" + ], + "converters": { + "event_vc_room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "event_vc_room_id", + "isDynamic": true + }, + { + "data": "/refresh", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_remove": { + "endpoint": "vc.manage_vc_rooms_remove", + "rules": [ + { + "args": [ + "confId", + "event_vc_room_id", + "service" + ], + "converters": { + "event_vc_room_id": "IntegerConverter" + }, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/", + "isDynamic": false + }, + { + "data": "event_vc_room_id", + "isDynamic": true + }, + { + "data": "/remove", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_search": { + "endpoint": "vc.manage_vc_rooms_search", + "rules": [ + { + "args": [ + "confId", + "service" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/search", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_search_form": { + "endpoint": "vc.manage_vc_rooms_search_form", + "rules": [ + { + "args": [ + "confId", + "service" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/", + "isDynamic": false + }, + { + "data": "service", + "isDynamic": true + }, + { + "data": "/attach", + "isDynamic": false + }, + { + "data": "/", + "isDynamic": false + } + ] + } + ] + }, + "vc.manage_vc_rooms_select": { + "endpoint": "vc.manage_vc_rooms_select", + "rules": [ + { + "args": [ + "confId" + ], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/event/", + "isDynamic": false + }, + { + "data": "confId", + "isDynamic": true + }, + { + "data": "/manage/videoconference/select", + "isDynamic": false + } + ] + } + ] + }, + "vc.vc_room_list": { + "endpoint": "vc.vc_room_list", + "rules": [ + { + "args": [], + "converters": {}, + "defaults": {}, + "trace": [ + { + "data": "|", + "isDynamic": false + }, + { + "data": "/service/videoconference", + "isDynamic": false + } + ] + } + ] + } + }, + "version": "4d4825ff3312d57fbcb0dc6a5f6805ec" +} \ No newline at end of file diff --git a/webpack-bundles.json b/webpack-bundles.json new file mode 100644 index 0000000..5f28835 --- /dev/null +++ b/webpack-bundles.json @@ -0,0 +1,5 @@ +{ + "entry": { + "main": "./index.js" + } +} From d1bf6776655142137d19ed00cb5b03a454c35894 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 19 Jun 2020 12:56:48 +0200 Subject: [PATCH 02/94] VC/Zoom: Remove url_map.json from VC --- url_map.json | 30163 ------------------------------------------------- 1 file changed, 30163 deletions(-) delete mode 100644 url_map.json diff --git a/url_map.json b/url_map.json deleted file mode 100644 index 65fb589..0000000 --- a/url_map.json +++ /dev/null @@ -1,30163 +0,0 @@ -{ - "rules": { - "abstracts.abstracts_csv_export": { - "endpoint": "abstracts.abstracts_csv_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/abstracts.csv", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.abstracts_json_export": { - "endpoint": "abstracts.abstracts_json_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/abstracts.json", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.abstracts_pdf_export": { - "endpoint": "abstracts.abstracts_pdf_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/abstracts.pdf", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.abstracts_xlsx_export": { - "endpoint": "abstracts.abstracts_xlsx_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/abstracts.xlsx", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.call_for_abstracts": { - "endpoint": "abstracts.call_for_abstracts", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.close_abstracts_call": { - "endpoint": "abstracts.close_abstracts_call", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/close", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.comment_abstract": { - "endpoint": "abstracts.comment_abstract", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/comment", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/comment", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.create_reviewing_question": { - "endpoint": "abstracts.create_reviewing_question", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/questions/create", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.customize_abstract_list": { - "endpoint": "abstracts.customize_abstract_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/list/customize", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.delete_abstract_comment": { - "endpoint": "abstracts.delete_abstract_comment", - "rules": [ - { - "args": [ - "abstract_id", - "comment_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter", - "comment_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/comments/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "abstract_id", - "comment_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter", - "comment_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/comments/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.delete_reviewing_question": { - "endpoint": "abstracts.delete_reviewing_question", - "rules": [ - { - "args": [ - "confId", - "question_id" - ], - "converters": { - "question_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/questions/", - "isDynamic": false - }, - { - "data": "question_id", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.display_abstract": { - "endpoint": "abstracts.display_abstract", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_abstract_pdf_export": { - "endpoint": "abstracts.display_abstract_pdf_export", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/abstract.pdf", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/abstract.pdf", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_abstracts_csv_export": { - "endpoint": "abstracts.display_abstracts_csv_export", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - }, - { - "data": "/abstracts.csv", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_abstracts_pdf_export": { - "endpoint": "abstracts.display_abstracts_pdf_export", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - }, - { - "data": "/abstracts.pdf", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_abstracts_xlsx_export": { - "endpoint": "abstracts.display_abstracts_xlsx_export", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - }, - { - "data": "/abstracts.xlsx", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_customize_abstract_list": { - "endpoint": "abstracts.display_customize_abstract_list", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - }, - { - "data": "/customize", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_download_attachments": { - "endpoint": "abstracts.display_download_attachments", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - }, - { - "data": "/attachments", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_reviewable_track_abstracts": { - "endpoint": "abstracts.display_reviewable_track_abstracts", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.display_reviewable_tracks": { - "endpoint": "abstracts.display_reviewable_tracks", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/reviewing", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.download_attachment": { - "endpoint": "abstracts.download_attachment", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "file_id", - "filename", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "file_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "file_id", - "filename", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "file_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.download_attachments": { - "endpoint": "abstracts.download_attachments", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/attachments", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.edit_abstract": { - "endpoint": "abstracts.edit_abstract", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.edit_abstract_comment": { - "endpoint": "abstracts.edit_abstract_comment", - "rules": [ - { - "args": [ - "abstract_id", - "comment_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter", - "comment_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/comments/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "abstract_id", - "comment_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter", - "comment_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/comments/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.edit_review": { - "endpoint": "abstracts.edit_review", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management", - "review_id" - ], - "converters": { - "abstract_id": "IntegerConverter", - "review_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/reviews/", - "isDynamic": false - }, - { - "data": "review_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management", - "review_id" - ], - "converters": { - "abstract_id": "IntegerConverter", - "review_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/reviews/", - "isDynamic": false - }, - { - "data": "review_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.edit_review_tracks": { - "endpoint": "abstracts.edit_review_tracks", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/reviewing-tracks", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/reviewing-tracks", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.edit_reviewing_question": { - "endpoint": "abstracts.edit_reviewing_question", - "rules": [ - { - "args": [ - "confId", - "question_id" - ], - "converters": { - "question_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/questions/", - "isDynamic": false - }, - { - "data": "question_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.email_tpl_add": { - "endpoint": "abstracts.email_tpl_add", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates/add", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.email_tpl_delete": { - "endpoint": "abstracts.email_tpl_delete", - "rules": [ - { - "args": [ - "confId", - "email_tpl_id" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates/", - "isDynamic": false - }, - { - "data": "email_tpl_id", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.email_tpl_list": { - "endpoint": "abstracts.email_tpl_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.email_tpl_rest": { - "endpoint": "abstracts.email_tpl_rest", - "rules": [ - { - "args": [ - "confId", - "email_tpl_id" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates/", - "isDynamic": false - }, - { - "data": "email_tpl_id", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.email_tpl_rule_edit": { - "endpoint": "abstracts.email_tpl_rule_edit", - "rules": [ - { - "args": [ - "confId", - "email_tpl_id" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates/", - "isDynamic": false - }, - { - "data": "email_tpl_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.email_tpl_sort": { - "endpoint": "abstracts.email_tpl_sort", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates/sort", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.email_tpl_text_edit": { - "endpoint": "abstracts.email_tpl_text_edit", - "rules": [ - { - "args": [ - "confId", - "email_tpl_id" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/email-templates/", - "isDynamic": false - }, - { - "data": "email_tpl_id", - "isDynamic": true - }, - { - "data": "/edit-text", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.export_boa": { - "endpoint": "abstracts.export_boa", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/book-of-abstracts.pdf", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.export_boa_tex": { - "endpoint": "abstracts.export_boa_tex", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/book-of-abstracts.zip", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.generate_static_url": { - "endpoint": "abstracts.generate_static_url", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/list/static-url", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.judge_abstract": { - "endpoint": "abstracts.judge_abstract", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/judge", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/judge", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_abstract_list": { - "endpoint": "abstracts.manage_abstract_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/list", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_abstract_pdf_export": { - "endpoint": "abstracts.manage_abstract_pdf_export", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/abstract-reviews.pdf", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/abstract-reviews.pdf", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_boa": { - "endpoint": "abstracts.manage_boa", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/boa", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_create_abstract": { - "endpoint": "abstracts.manage_create_abstract", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/create", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_delete_abstracts": { - "endpoint": "abstracts.manage_delete_abstracts", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/delete", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_judge_abstracts": { - "endpoint": "abstracts.manage_judge_abstracts", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/judge", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_reviewing_questions": { - "endpoint": "abstracts.manage_reviewing_questions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/questions", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_reviewing_roles": { - "endpoint": "abstracts.manage_reviewing_roles", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/teams", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_reviewing_settings": { - "endpoint": "abstracts.manage_reviewing_settings", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/review-settings", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.manage_submission_settings": { - "endpoint": "abstracts.manage_submission_settings", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/settings", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.management": { - "endpoint": "abstracts.management", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.my_abstracts_pdf": { - "endpoint": "abstracts.my_abstracts_pdf", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/mine.pdf", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.notification_log": { - "endpoint": "abstracts.notification_log", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/notifications", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/notifications", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.open_abstracts_call": { - "endpoint": "abstracts.open_abstracts_call", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/open", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.other_abstracts": { - "endpoint": "abstracts.other_abstracts", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/other-list", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.person_list": { - "endpoint": "abstracts.person_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/person-list", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.reset_abstract_state": { - "endpoint": "abstracts.reset_abstract_state", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/reset", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/reset", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.review_abstract": { - "endpoint": "abstracts.review_abstract", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management", - "track_id" - ], - "converters": { - "abstract_id": "IntegerConverter", - "track_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/review/track/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management", - "track_id" - ], - "converters": { - "abstract_id": "IntegerConverter", - "track_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/review/track/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.schedule_abstracts_call": { - "endpoint": "abstracts.schedule_abstracts_call", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/schedule", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.sort_reviewing_questions": { - "endpoint": "abstracts.sort_reviewing_questions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/questions/sort", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.submit": { - "endpoint": "abstracts.submit", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/submit", - "isDynamic": false - } - ] - } - ] - }, - "abstracts.submit_invited_abstract": { - "endpoint": "abstracts.submit_invited_abstract", - "rules": [ - { - "args": [ - "confId", - "uuid" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/submit/", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "abstracts.withdraw_abstract": { - "endpoint": "abstracts.withdraw_abstract", - "rules": [ - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/withdraw", - "isDynamic": false - } - ] - }, - { - "args": [ - "abstract_id", - "confId", - "management" - ], - "converters": { - "abstract_id": "IntegerConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/abstracts/", - "isDynamic": false - }, - { - "data": "abstract_id", - "isDynamic": true - }, - { - "data": "/withdraw", - "isDynamic": false - } - ] - } - ] - }, - "agreements.agreement_form": { - "endpoint": "agreements.agreement_form", - "rules": [ - { - "args": [ - "confId", - "id", - "uuid" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/agreement/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "agreements.download_file": { - "endpoint": "agreements.download_file", - "rules": [ - { - "args": [ - "confId", - "definition", - "filename", - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/download/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "agreements.event_agreements": { - "endpoint": "agreements.event_agreements", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "agreements.event_agreements_details": { - "endpoint": "agreements.event_agreements_details", - "rules": [ - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "agreements.event_agreements_details_remind": { - "endpoint": "agreements.event_agreements_details_remind", - "rules": [ - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/remind", - "isDynamic": false - } - ] - } - ] - }, - "agreements.event_agreements_details_remind_all": { - "endpoint": "agreements.event_agreements_details_remind_all", - "rules": [ - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/remind-all", - "isDynamic": false - } - ] - } - ] - }, - "agreements.event_agreements_details_send": { - "endpoint": "agreements.event_agreements_details_send", - "rules": [ - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/send", - "isDynamic": false - } - ] - } - ] - }, - "agreements.event_agreements_details_send_all": { - "endpoint": "agreements.event_agreements_details_send_all", - "rules": [ - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/send-all", - "isDynamic": false - } - ] - } - ] - }, - "agreements.event_agreements_details_submit_answer": { - "endpoint": "agreements.event_agreements_details_submit_answer", - "rules": [ - { - "args": [ - "confId", - "definition", - "id" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/submit/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - } - ] - }, - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/submit", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "agreements.toggle_notifications": { - "endpoint": "agreements.toggle_notifications", - "rules": [ - { - "args": [ - "confId", - "definition" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/agreements/", - "isDynamic": false - }, - { - "data": "definition", - "isDynamic": true - }, - { - "data": "/toggle-notifications", - "isDynamic": false - } - ] - } - ] - }, - "announcement.manage": { - "endpoint": "announcement.manage", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/announcement", - "isDynamic": false - } - ] - } - ] - }, - "api.admin_keys": { - "endpoint": "api.admin_keys", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/api/keys", - "isDynamic": false - } - ] - } - ] - }, - "api.admin_settings": { - "endpoint": "api.admin_settings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/api", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "api.build_urls": { - "endpoint": "api.build_urls", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/build-urls", - "isDynamic": false - } - ] - } - ] - }, - "api.httpapi": { - "endpoint": "api.httpapi", - "rules": [ - { - "args": [ - "path", - "prefix" - ], - "converters": { - "path": "PathConverter" - }, - "defaults": { - "prefix": "export" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/export/", - "isDynamic": false - }, - { - "data": "path", - "isDynamic": true - } - ] - }, - { - "args": [ - "path", - "prefix" - ], - "converters": { - "path": "PathConverter" - }, - "defaults": { - "prefix": "api" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/", - "isDynamic": false - }, - { - "data": "path", - "isDynamic": true - } - ] - }, - { - "args": [ - "prefix" - ], - "converters": { - "prefix": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "prefix", - "isDynamic": true - } - ] - } - ] - }, - "api.jsonrpc": { - "endpoint": "api.jsonrpc", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/services/json-rpc", - "isDynamic": false - } - ] - } - ] - }, - "api.key_block": { - "endpoint": "api.key_block", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/api/block", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api/block", - "isDynamic": false - } - ] - } - ] - }, - "api.key_create": { - "endpoint": "api.key_create", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/api/create", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api/create", - "isDynamic": false - } - ] - } - ] - }, - "api.key_delete": { - "endpoint": "api.key_delete", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/api/delete", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api/delete", - "isDynamic": false - } - ] - } - ] - }, - "api.key_toggle_persistent": { - "endpoint": "api.key_toggle_persistent", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/api/persistent", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api/persistent", - "isDynamic": false - } - ] - } - ] - }, - "api.user_profile": { - "endpoint": "api.user_profile", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/api", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "assets.css": { - "endpoint": "assets.css", - "rules": [ - { - "args": [ - "filename" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/css/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "assets.custom": { - "endpoint": "assets.custom", - "rules": [ - { - "args": [ - "filename", - "folder" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": { - "folder": "files" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/static/custom/files/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "filename", - "folder" - ], - "converters": { - "filename": "PathConverter", - "folder": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/static/custom/", - "isDynamic": false - }, - { - "data": "folder", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "assets.dist": { - "endpoint": "assets.dist", - "rules": [ - { - "args": [ - "filename" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/dist/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "assets.favicon": { - "endpoint": "assets.favicon", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/favicon.ico", - "isDynamic": false - } - ] - } - ] - }, - "assets.folder_file": { - "endpoint": "assets.folder_file", - "rules": [ - { - "args": [ - "fileext", - "filename", - "folder", - "version" - ], - "converters": { - "filename": "PathConverter", - "folder": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "folder", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - }, - { - "data": "__v", - "isDynamic": false - }, - { - "data": "version", - "isDynamic": true - }, - { - "data": ".", - "isDynamic": false - }, - { - "data": "fileext", - "isDynamic": true - } - ] - }, - { - "args": [ - "fileext", - "filename", - "folder" - ], - "converters": { - "filename": "PathConverter", - "folder": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "folder", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - }, - { - "data": ".", - "isDynamic": false - }, - { - "data": "fileext", - "isDynamic": true - } - ] - } - ] - }, - "assets.fonts": { - "endpoint": "assets.fonts", - "rules": [ - { - "args": [ - "filename" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/fonts/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "assets.i18n_locale": { - "endpoint": "assets.i18n_locale", - "rules": [ - { - "args": [ - "locale_name" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/assets/i18n/", - "isDynamic": false - }, - { - "data": "locale_name", - "isDynamic": true - }, - { - "data": ".js", - "isDynamic": false - } - ] - } - ] - }, - "assets.i18n_locale_react": { - "endpoint": "assets.i18n_locale_react", - "rules": [ - { - "args": [ - "locale_name" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/assets/i18n/", - "isDynamic": false - }, - { - "data": "locale_name", - "isDynamic": true - }, - { - "data": "-react.js", - "isDynamic": false - } - ] - } - ] - }, - "assets.image": { - "endpoint": "assets.image", - "rules": [ - { - "args": [ - "filename" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/images/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "assets.js_vars_global": { - "endpoint": "assets.js_vars_global", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/assets/js-vars/global.js", - "isDynamic": false - } - ] - } - ] - }, - "assets.js_vars_user": { - "endpoint": "assets.js_vars_user", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/assets/js-vars/user.js", - "isDynamic": false - } - ] - } - ] - }, - "assets.plugin_file": { - "endpoint": "assets.plugin_file", - "rules": [ - { - "args": [ - "fileext", - "filename", - "plugin", - "version" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/static/plugins/", - "isDynamic": false - }, - { - "data": "plugin", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - }, - { - "data": "__v", - "isDynamic": false - }, - { - "data": "version", - "isDynamic": true - }, - { - "data": ".", - "isDynamic": false - }, - { - "data": "fileext", - "isDynamic": true - } - ] - }, - { - "args": [ - "fileext", - "filename", - "plugin" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/static/plugins/", - "isDynamic": false - }, - { - "data": "plugin", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - }, - { - "data": ".", - "isDynamic": false - }, - { - "data": "fileext", - "isDynamic": true - } - ] - } - ] - }, - "assets.root": { - "endpoint": "assets.root", - "rules": [ - { - "args": [ - "filename" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "attachments.add_link": { - "endpoint": "attachments.add_link", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/add/link", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/add/link", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/add/link", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/add/link", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/add/link", - "isDynamic": false - } - ] - } - ] - }, - "attachments.create_folder": { - "endpoint": "attachments.create_folder", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/create-folder", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/create-folder", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/create-folder", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/create-folder", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/create-folder", - "isDynamic": false - } - ] - } - ] - }, - "attachments.delete_attachment": { - "endpoint": "attachments.delete_attachment", - "rules": [ - { - "args": [ - "attachment_id", - "confId", - "contrib_id", - "folder_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "contrib_id", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "folder_id", - "object_type", - "session_id" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "folder_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "category_id", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "category_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "attachments.delete_folder": { - "endpoint": "attachments.delete_folder", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "folder_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "folder_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "folder_id", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "folder_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "folder_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "folder_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "attachments.download": { - "endpoint": "attachments.download", - "rules": [ - { - "args": [ - "attachment_id", - "confId", - "contrib_id", - "filename", - "folder_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "attachment_id": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "contrib_id", - "filename", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "filename", - "folder_id", - "object_type", - "session_id" - ], - "converters": { - "attachment_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "filename", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "attachment_id", - "category_id", - "filename", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "attachments.edit_folder": { - "endpoint": "attachments.edit_folder", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "folder_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "folder_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "folder_id", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "folder_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "folder_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "folder_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "attachments.list_folder": { - "endpoint": "attachments.list_folder", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "folder_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "folder_id", - "object_type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "folder_id", - "object_type", - "session_id" - ], - "converters": { - "folder_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "folder_id", - "object_type" - ], - "converters": { - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "attachments.management": { - "endpoint": "attachments.management", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "attachments.management_info_column": { - "endpoint": "attachments.management_info_column", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/info-column", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/info-column", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/info-column", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/info-column", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/info-column", - "isDynamic": false - } - ] - } - ] - }, - "attachments.modify_attachment": { - "endpoint": "attachments.modify_attachment", - "rules": [ - { - "args": [ - "attachment_id", - "confId", - "contrib_id", - "folder_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "contrib_id", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "folder_id", - "object_type", - "session_id" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "folder_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "confId", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "confId": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "attachment_id", - "category_id", - "folder_id", - "object_type" - ], - "converters": { - "attachment_id": "IntegerConverter", - "category_id": "IntegerConverter", - "folder_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/", - "isDynamic": false - }, - { - "data": "folder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "attachment_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "attachments.package": { - "endpoint": "attachments.package", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/attachments/package", - "isDynamic": false - } - ] - } - ] - }, - "attachments.package_management": { - "endpoint": "attachments.package_management", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/package", - "isDynamic": false - } - ] - } - ] - }, - "attachments.upload": { - "endpoint": "attachments.upload", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/attachments/add/files", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "confId": "IntegerConverter", - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/attachments/add/files", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "confId": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/attachments/add/files", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/attachments/add/files", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/attachments/add/files", - "isDynamic": false - } - ] - } - ] - }, - "auth.accounts": { - "endpoint": "auth.accounts", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/accounts", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/accounts", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "auth.admin_impersonate": { - "endpoint": "auth.admin_impersonate", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/impersonate", - "isDynamic": false - } - ] - } - ] - }, - "auth.link_account": { - "endpoint": "auth.link_account", - "rules": [ - { - "args": [ - "provider" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/login/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/link-account", - "isDynamic": false - } - ] - } - ] - }, - "auth.login": { - "endpoint": "auth.login", - "rules": [ - { - "args": [ - "provider" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/login/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/login", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "auth.login_form": { - "endpoint": "auth.login_form", - "rules": [ - { - "args": [ - "provider" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/login/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/form", - "isDynamic": false - } - ] - } - ] - }, - "auth.logout": { - "endpoint": "auth.logout", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/logout", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "auth.register": { - "endpoint": "auth.register", - "rules": [ - { - "args": [ - "provider" - ], - "converters": {}, - "defaults": { - "provider": null - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/register", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "provider" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/register/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - } - ] - } - ] - }, - "auth.remove_account": { - "endpoint": "auth.remove_account", - "rules": [ - { - "args": [ - "identity", - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/accounts/", - "isDynamic": false - }, - { - "data": "identity", - "isDynamic": true - }, - { - "data": "/remove", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "identity" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/accounts/", - "isDynamic": false - }, - { - "data": "identity", - "isDynamic": true - }, - { - "data": "/remove", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "auth.resetpass": { - "endpoint": "auth.resetpass", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/reset-password", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "bootstrap.index": { - "endpoint": "bootstrap.index", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/bootstrap", - "isDynamic": false - } - ] - } - ] - }, - "categories._redirect": { - "endpoint": "categories._redirect", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/categ/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/c/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - } - ] - } - ] - }, - "categories._redirect_event_creation": { - "endpoint": "categories._redirect_event_creation", - "rules": [ - { - "args": [ - "category_id", - "event_type" - ], - "converters": { - "category_id": "IntegerConverter", - "event_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/create/event/", - "isDynamic": false - }, - { - "data": "event_type", - "isDynamic": true - } - ] - } - ] - }, - "categories.calendar": { - "endpoint": "categories.calendar", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/calendar", - "isDynamic": false - } - ] - } - ] - }, - "categories.category_xml_info": { - "endpoint": "categories.category_xml_info", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/xmlGateway.py/getCategoryInfo", - "isDynamic": false - } - ] - } - ] - }, - "categories.create_subcategory": { - "endpoint": "categories.create_subcategory", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/subcategories/create", - "isDynamic": false - } - ] - } - ] - }, - "categories.delete": { - "endpoint": "categories.delete", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/delete", - "isDynamic": false - } - ] - } - ] - }, - "categories.delete_events": { - "endpoint": "categories.delete_events", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/events/delete", - "isDynamic": false - } - ] - } - ] - }, - "categories.delete_subcategories": { - "endpoint": "categories.delete_subcategories", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/subcategories/delete", - "isDynamic": false - } - ] - } - ] - }, - "categories.display": { - "endpoint": "categories.display", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": {}, - "defaults": { - "category_id": 0 - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "categories.display_icon": { - "endpoint": "categories.display_icon", - "rules": [ - { - "args": [ - "category_id", - "slug" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/icon-", - "isDynamic": false - }, - { - "data": "slug", - "isDynamic": true - }, - { - "data": ".png", - "isDynamic": false - } - ] - } - ] - }, - "categories.display_logo": { - "endpoint": "categories.display_logo", - "rules": [ - { - "args": [ - "category_id", - "slug" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/logo-", - "isDynamic": false - }, - { - "data": "slug", - "isDynamic": true - }, - { - "data": ".png", - "isDynamic": false - } - ] - } - ] - }, - "categories.event_list": { - "endpoint": "categories.event_list", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/event-list", - "isDynamic": false - } - ] - } - ] - }, - "categories.export_atom": { - "endpoint": "categories.export_atom", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/events.atom", - "isDynamic": false - } - ] - } - ] - }, - "categories.export_ical": { - "endpoint": "categories.export_ical", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/events.ics", - "isDynamic": false - } - ] - } - ] - }, - "categories.export_rss": { - "endpoint": "categories.export_rss", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/events.rss", - "isDynamic": false - } - ] - } - ] - }, - "categories.info": { - "endpoint": "categories.info", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/info", - "isDynamic": false - } - ] - } - ] - }, - "categories.info_from": { - "endpoint": "categories.info_from", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/info-from", - "isDynamic": false - } - ] - } - ] - }, - "categories.manage_content": { - "endpoint": "categories.manage_content", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "categories.manage_icon": { - "endpoint": "categories.manage_icon", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/icon", - "isDynamic": false - } - ] - } - ] - }, - "categories.manage_logo": { - "endpoint": "categories.manage_logo", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/logo", - "isDynamic": false - } - ] - } - ] - }, - "categories.manage_protection": { - "endpoint": "categories.manage_protection", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/protection", - "isDynamic": false - } - ] - } - ] - }, - "categories.manage_settings": { - "endpoint": "categories.manage_settings", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/settings", - "isDynamic": false - } - ] - } - ] - }, - "categories.manage_upcoming": { - "endpoint": "categories.manage_upcoming", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/upcoming-events", - "isDynamic": false - } - ] - } - ] - }, - "categories.move": { - "endpoint": "categories.move", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/move", - "isDynamic": false - } - ] - } - ] - }, - "categories.move_events": { - "endpoint": "categories.move_events", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/events/move", - "isDynamic": false - } - ] - } - ] - }, - "categories.move_subcategories": { - "endpoint": "categories.move_subcategories", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/subcategories/move", - "isDynamic": false - } - ] - } - ] - }, - "categories.overview": { - "endpoint": "categories.overview", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/overview", - "isDynamic": false - } - ] - } - ] - }, - "categories.search": { - "endpoint": "categories.search", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/search", - "isDynamic": false - } - ] - } - ] - }, - "categories.show_future_events": { - "endpoint": "categories.show_future_events", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/show-future-events", - "isDynamic": false - } - ] - } - ] - }, - "categories.show_past_events": { - "endpoint": "categories.show_past_events", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/show-past-events", - "isDynamic": false - } - ] - } - ] - }, - "categories.sort_subcategories": { - "endpoint": "categories.sort_subcategories", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/subcategories/sort", - "isDynamic": false - } - ] - } - ] - }, - "categories.split_category": { - "endpoint": "categories.split_category", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/events/split", - "isDynamic": false - } - ] - } - ] - }, - "categories.statistics": { - "endpoint": "categories.statistics", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/statistics", - "isDynamic": false - } - ] - } - ] - }, - "categories.subcat_info": { - "endpoint": "categories.subcat_info", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/subcat-info", - "isDynamic": false - } - ] - } - ] - }, - "categories.upcoming_event": { - "endpoint": "categories.upcoming_event", - "rules": [ - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/upcoming", - "isDynamic": false - } - ] - } - ] - }, - "celery.index": { - "endpoint": "celery.index", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/tasks", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "cephalopod.index": { - "endpoint": "cephalopod.index", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/community-hub", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "cephalopod.sync": { - "endpoint": "cephalopod.sync", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/community-hub/sync", - "isDynamic": false - } - ] - } - ] - }, - "cephalopod.system-info": { - "endpoint": "cephalopod.system-info", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/system-info", - "isDynamic": false - } - ] - } - ] - }, - "contributions.acl": { - "endpoint": "contributions.acl", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/acl", - "isDynamic": false - } - ] - } - ] - }, - "contributions.acl_message": { - "endpoint": "contributions.acl_message", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/acl-message", - "isDynamic": false - } - ] - } - ] - }, - "contributions.author_list": { - "endpoint": "contributions.author_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/authors", - "isDynamic": false - } - ] - } - ] - }, - "contributions.clone_contribution": { - "endpoint": "contributions.clone_contribution", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/clone", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contribution_list": { - "endpoint": "contributions.contribution_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contribution_list_pdf": { - "endpoint": "contributions.contribution_list_pdf", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/contributions.pdf", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contribution_list_static_url": { - "endpoint": "contributions.contribution_list_static_url", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/static-url", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contributions_csv_export": { - "endpoint": "contributions.contributions_csv_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/contributions.csv", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contributions_excel_export": { - "endpoint": "contributions.contributions_excel_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/contributions.xlsx", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contributions_import": { - "endpoint": "contributions.contributions_import", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/import", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contributions_pdf_export": { - "endpoint": "contributions.contributions_pdf_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/contributions.pdf", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contributions_tex_export": { - "endpoint": "contributions.contributions_tex_export", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/contributions.zip", - "isDynamic": false - } - ] - } - ] - }, - "contributions.contributions_tex_export_book": { - "endpoint": "contributions.contributions_tex_export_book", - "rules": [ - { - "args": [ - "confId", - "uuid" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/tex-export/", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "contributions.contributions_tex_export_dialog": { - "endpoint": "contributions.contributions_tex_export_dialog", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/tex-export-dialog", - "isDynamic": false - } - ] - } - ] - }, - "contributions.create_contrib_reference_rest": { - "endpoint": "contributions.create_contrib_reference_rest", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/references", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.create_field": { - "endpoint": "contributions.create_field", - "rules": [ - { - "args": [ - "confId", - "field_type" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/fields/create/", - "isDynamic": false - }, - { - "data": "field_type", - "isDynamic": true - } - ] - } - ] - }, - "contributions.create_subcontrib_reference_rest": { - "endpoint": "contributions.create_subcontrib_reference_rest", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/references", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.create_subcontrib_rest": { - "endpoint": "contributions.create_subcontrib_rest", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.create_type": { - "endpoint": "contributions.create_type", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/types/create", - "isDynamic": false - } - ] - } - ] - }, - "contributions.customize_contrib_list": { - "endpoint": "contributions.customize_contrib_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/customize", - "isDynamic": false - } - ] - } - ] - }, - "contributions.customize_contribution_list": { - "endpoint": "contributions.customize_contribution_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/customize", - "isDynamic": false - } - ] - } - ] - }, - "contributions.delete_field": { - "endpoint": "contributions.delete_field", - "rules": [ - { - "args": [ - "confId", - "contrib_field_id" - ], - "converters": { - "contrib_field_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/fields/", - "isDynamic": false - }, - { - "data": "contrib_field_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "contributions.delete_type": { - "endpoint": "contributions.delete_type", - "rules": [ - { - "args": [ - "confId", - "contrib_type_id" - ], - "converters": { - "contrib_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/types/", - "isDynamic": false - }, - { - "data": "contrib_type_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "contributions.display_author": { - "endpoint": "contributions.display_author", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "person_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "person_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/author/", - "isDynamic": false - }, - { - "data": "person_id", - "isDynamic": true - } - ] - } - ] - }, - "contributions.display_contribution": { - "endpoint": "contributions.display_contribution", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.display_subcontribution": { - "endpoint": "contributions.display_subcontribution", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - } - ] - } - ] - }, - "contributions.export_ics": { - "endpoint": "contributions.export_ics", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/contribution.ics", - "isDynamic": false - } - ] - } - ] - }, - "contributions.export_pdf": { - "endpoint": "contributions.export_pdf", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/contribution.pdf", - "isDynamic": false - } - ] - } - ] - }, - "contributions.generate_static_url": { - "endpoint": "contributions.generate_static_url", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/static-url", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_contrib_protection": { - "endpoint": "contributions.manage_contrib_protection", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/protection", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_contrib_rest": { - "endpoint": "contributions.manage_contrib_rest", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - } - ] - } - ] - }, - "contributions.manage_contributions": { - "endpoint": "contributions.manage_contributions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_create_contrib": { - "endpoint": "contributions.manage_create_contrib", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/create", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_create_subcontrib": { - "endpoint": "contributions.manage_create_subcontrib", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/create", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_default_duration": { - "endpoint": "contributions.manage_default_duration", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/duration", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_delete_contribs": { - "endpoint": "contributions.manage_delete_contribs", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/delete", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_delete_subcontribs": { - "endpoint": "contributions.manage_delete_subcontribs", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/delete", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_description_field": { - "endpoint": "contributions.manage_description_field", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/fields/description", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_duration": { - "endpoint": "contributions.manage_duration", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/duration", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_edit_subcontrib": { - "endpoint": "contributions.manage_edit_subcontrib", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_field": { - "endpoint": "contributions.manage_field", - "rules": [ - { - "args": [ - "confId", - "contrib_field_id" - ], - "converters": { - "contrib_field_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/fields/", - "isDynamic": false - }, - { - "data": "contrib_field_id", - "isDynamic": true - } - ] - } - ] - }, - "contributions.manage_fields": { - "endpoint": "contributions.manage_fields", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/fields", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_publication": { - "endpoint": "contributions.manage_publication", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/published", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_start_date": { - "endpoint": "contributions.manage_start_date", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/start-date", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_subcontrib_rest": { - "endpoint": "contributions.manage_subcontrib_rest", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - } - ] - } - ] - }, - "contributions.manage_subcontributions": { - "endpoint": "contributions.manage_subcontributions", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_type": { - "endpoint": "contributions.manage_type", - "rules": [ - { - "args": [ - "confId", - "contrib_type_id" - ], - "converters": { - "contrib_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/types/", - "isDynamic": false - }, - { - "data": "contrib_type_id", - "isDynamic": true - } - ] - } - ] - }, - "contributions.manage_types": { - "endpoint": "contributions.manage_types", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/types", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "contributions.manage_update_contrib": { - "endpoint": "contributions.manage_update_contrib", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "contributions.material_package": { - "endpoint": "contributions.material_package", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/material-package", - "isDynamic": false - } - ] - } - ] - }, - "contributions.my_contributions": { - "endpoint": "contributions.my_contributions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/mine", - "isDynamic": false - } - ] - } - ] - }, - "contributions.person_list": { - "endpoint": "contributions.person_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/person-list", - "isDynamic": false - } - ] - } - ] - }, - "contributions.sort_fields": { - "endpoint": "contributions.sort_fields", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/fields/sort", - "isDynamic": false - } - ] - } - ] - }, - "contributions.sort_subcontributions": { - "endpoint": "contributions.sort_subcontributions", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/sort", - "isDynamic": false - } - ] - } - ] - }, - "contributions.speaker_list": { - "endpoint": "contributions.speaker_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/speakers", - "isDynamic": false - } - ] - } - ] - }, - "core.admin_dashboard": { - "endpoint": "core.admin_dashboard", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "core.change_lang": { - "endpoint": "core.change_lang", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/change-language", - "isDynamic": false - } - ] - } - ] - }, - "core.change_tz": { - "endpoint": "core.change_tz", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/change-timezone", - "isDynamic": false - } - ] - } - ] - }, - "core.contact": { - "endpoint": "core.contact", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/contact", - "isDynamic": false - } - ] - } - ] - }, - "core.ping": { - "endpoint": "core.ping", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/ping", - "isDynamic": false - } - ] - } - ] - }, - "core.principals": { - "endpoint": "core.principals", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/principals", - "isDynamic": false - } - ] - } - ] - }, - "core.report_error_api": { - "endpoint": "core.report_error_api", - "rules": [ - { - "args": [ - "error_id" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/report-error/api/", - "isDynamic": false - }, - { - "data": "error_id", - "isDynamic": true - } - ] - } - ] - }, - "core.reset_signature_tokens": { - "endpoint": "core.reset_signature_tokens", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/reset-signature-tokens", - "isDynamic": false - } - ] - } - ] - }, - "core.settings": { - "endpoint": "core.settings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/settings", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "core.sign_url": { - "endpoint": "core.sign_url", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/sign-url", - "isDynamic": false - } - ] - } - ] - }, - "core.version_check": { - "endpoint": "core.version_check", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/version-check", - "isDynamic": false - } - ] - } - ] - }, - "designer.add_template": { - "endpoint": "designer.add_template", - "rules": [ - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/add", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/add", - "isDynamic": false - } - ] - } - ] - }, - "designer.backside_template_list": { - "endpoint": "designer.backside_template_list", - "rules": [ - { - "args": [ - "confId", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/backsides", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/backsides", - "isDynamic": false - } - ] - } - ] - }, - "designer.clone_template": { - "endpoint": "designer.clone_template", - "rules": [ - { - "args": [ - "confId", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/clone", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/clone", - "isDynamic": false - } - ] - } - ] - }, - "designer.delete_template": { - "endpoint": "designer.delete_template", - "rules": [ - { - "args": [ - "confId", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "designer.download_image": { - "endpoint": "designer.download_image", - "rules": [ - { - "args": [ - "confId", - "filename", - "image_id", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "image_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/images/", - "isDynamic": false - }, - { - "data": "image_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - }, - { - "args": [ - "category_id", - "filename", - "image_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "image_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/images/", - "isDynamic": false - }, - { - "data": "image_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "designer.edit_template": { - "endpoint": "designer.edit_template", - "rules": [ - { - "args": [ - "confId", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "designer.get_template_data": { - "endpoint": "designer.get_template_data", - "rules": [ - { - "args": [ - "confId", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/data", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/data", - "isDynamic": false - } - ] - } - ] - }, - "designer.template_list": { - "endpoint": "designer.template_list", - "rules": [ - { - "args": [ - "confId", - "object_type" - ], - "converters": { - "confId": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "designer.toggle_category_default": { - "endpoint": "designer.toggle_category_default", - "rules": [ - { - "args": [ - "category_id", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/toggle-default", - "isDynamic": false - } - ] - } - ] - }, - "designer.upload_image": { - "endpoint": "designer.upload_image", - "rules": [ - { - "args": [ - "confId", - "object_type", - "template_id" - ], - "converters": { - "confId": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/images", - "isDynamic": false - } - ] - }, - { - "args": [ - "category_id", - "object_type", - "template_id" - ], - "converters": { - "category_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": { - "object_type": "category" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/category/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - }, - { - "data": "/manage/designer/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/images", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_confirm_changes": { - "endpoint": "event_editing.api_confirm_changes", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/confirm", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_create_comment": { - "endpoint": "event_editing.api_create_comment", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/comments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_create_editable": { - "endpoint": "event_editing.api_create_editable", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - } - ] - } - ] - }, - "event_editing.api_create_submitter_revision": { - "endpoint": "event_editing.api_create_submitter_revision", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/new", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_create_tag": { - "endpoint": "event_editing.api_create_tag", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/editing/api/tags", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_edit_comment": { - "endpoint": "event_editing.api_edit_comment", - "rules": [ - { - "args": [ - "comment_id", - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "comment_id": "IntegerConverter", - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/comments/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - } - ] - }, - "event_editing.api_edit_tag": { - "endpoint": "event_editing.api_edit_tag", - "rules": [ - { - "args": [ - "confId", - "tag_id" - ], - "converters": { - "tag_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/editing/api/tag/", - "isDynamic": false - }, - { - "data": "tag_id", - "isDynamic": true - } - ] - } - ] - }, - "event_editing.api_editable": { - "endpoint": "event_editing.api_editable", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - } - ] - } - ] - }, - "event_editing.api_file_types": { - "endpoint": "event_editing.api_file_types", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/editing/api/file-types", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_replace_revision": { - "endpoint": "event_editing.api_replace_revision", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/replace", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_review_editable": { - "endpoint": "event_editing.api_review_editable", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/review", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_tags": { - "endpoint": "event_editing.api_tags", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/editing/api/tags", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_undo_review": { - "endpoint": "event_editing.api_undo_review", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/review", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.api_upload": { - "endpoint": "event_editing.api_upload", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/upload", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.dashboard": { - "endpoint": "event_editing.dashboard", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/editing", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.download_file": { - "endpoint": "event_editing.download_file", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "file_id", - "filename", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "file_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "file_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "event_editing.editable": { - "endpoint": "event_editing.editable", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - } - ] - } - ] - }, - "event_editing.manage_tags": { - "endpoint": "event_editing.manage_tags", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/editing/tags", - "isDynamic": false - } - ] - } - ] - }, - "event_editing.revision_files_export": { - "endpoint": "event_editing.revision_files_export", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "revision_id", - "type" - ], - "converters": { - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/editing/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/files.zip", - "isDynamic": false - } - ] - } - ] - }, - "event_features.index": { - "endpoint": "event_features.index", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/features", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_features.switch": { - "endpoint": "event_features.switch", - "rules": [ - { - "args": [ - "confId", - "feature" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/features/", - "isDynamic": false - }, - { - "data": "feature", - "isDynamic": true - } - ] - } - ] - }, - "event_images.image_display": { - "endpoint": "event_images.image_display", - "rules": [ - { - "args": [ - "confId", - "filename", - "image_id" - ], - "converters": { - "image_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/images/", - "isDynamic": false - }, - { - "data": "image_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "event_images.logo_display": { - "endpoint": "event_images.logo_display", - "rules": [ - { - "args": [ - "confId", - "slug" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/logo-", - "isDynamic": false - }, - { - "data": "slug", - "isDynamic": true - }, - { - "data": ".png", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.css_display": { - "endpoint": "event_layout.css_display", - "rules": [ - { - "args": [ - "confId", - "slug" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "slug", - "isDynamic": true - }, - { - "data": ".css", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.css_preview": { - "endpoint": "event_layout.css_preview", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/theme/preview", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.css_save_theme": { - "endpoint": "event_layout.css_save_theme", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/theme/save", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.delete_css": { - "endpoint": "event_layout.delete_css", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/css", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.delete_logo": { - "endpoint": "event_layout.delete_logo", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/logo", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.image_delete": { - "endpoint": "event_layout.image_delete", - "rules": [ - { - "args": [ - "confId", - "filename", - "image_id" - ], - "converters": { - "image_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/images/", - "isDynamic": false - }, - { - "data": "image_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "event_layout.images": { - "endpoint": "event_layout.images", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/images", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.images_upload": { - "endpoint": "event_layout.images_upload", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/images/upload", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.index": { - "endpoint": "event_layout.index", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu": { - "endpoint": "event_layout.menu", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_add_entry": { - "endpoint": "event_layout.menu_add_entry", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/add", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_delete_entry": { - "endpoint": "event_layout.menu_delete_entry", - "rules": [ - { - "args": [ - "confId", - "menu_entry_id" - ], - "converters": { - "menu_entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/", - "isDynamic": false - }, - { - "data": "menu_entry_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_entry_edit": { - "endpoint": "event_layout.menu_entry_edit", - "rules": [ - { - "args": [ - "confId", - "menu_entry_id" - ], - "converters": { - "menu_entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/", - "isDynamic": false - }, - { - "data": "menu_entry_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_entry_position": { - "endpoint": "event_layout.menu_entry_position", - "rules": [ - { - "args": [ - "confId", - "menu_entry_id" - ], - "converters": { - "menu_entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/", - "isDynamic": false - }, - { - "data": "menu_entry_id", - "isDynamic": true - }, - { - "data": "/position", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_entry_toggle_default": { - "endpoint": "event_layout.menu_entry_toggle_default", - "rules": [ - { - "args": [ - "confId", - "menu_entry_id" - ], - "converters": { - "menu_entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/", - "isDynamic": false - }, - { - "data": "menu_entry_id", - "isDynamic": true - }, - { - "data": "/toggle-default", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_entry_toggle_enabled": { - "endpoint": "event_layout.menu_entry_toggle_enabled", - "rules": [ - { - "args": [ - "confId", - "menu_entry_id" - ], - "converters": { - "menu_entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/", - "isDynamic": false - }, - { - "data": "menu_entry_id", - "isDynamic": true - }, - { - "data": "/toggle-enabled", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.menu_toggle_custom": { - "endpoint": "event_layout.menu_toggle_custom", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/menu/toggle-customize", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.timetable_theme_form": { - "endpoint": "event_layout.timetable_theme_form", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/timetable-theme-form", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.upload_css": { - "endpoint": "event_layout.upload_css", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/css", - "isDynamic": false - } - ] - } - ] - }, - "event_layout.upload_logo": { - "endpoint": "event_layout.upload_logo", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/layout/logo", - "isDynamic": false - } - ] - } - ] - }, - "event_logs.index": { - "endpoint": "event_logs.index", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/logs", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_logs.logs": { - "endpoint": "event_logs.logs", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/logs/api/logs", - "isDynamic": false - } - ] - } - ] - }, - "event_management.acl": { - "endpoint": "event_management.acl", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/protection/acl", - "isDynamic": false - } - ] - } - ] - }, - "event_management.acl_message": { - "endpoint": "event_management.acl_message", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/protection/acl-message", - "isDynamic": false - } - ] - } - ] - }, - "event_management.api_principals": { - "endpoint": "event_management.api_principals", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/api/principals", - "isDynamic": false - } - ] - } - ] - }, - "event_management.assign_program_codes_contributions": { - "endpoint": "event_management.assign_program_codes_contributions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/program-codes/assign/contributions", - "isDynamic": false - } - ] - } - ] - }, - "event_management.assign_program_codes_session_blocks": { - "endpoint": "event_management.assign_program_codes_session_blocks", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/program-codes/assign/session-blocks", - "isDynamic": false - } - ] - } - ] - }, - "event_management.assign_program_codes_sessions": { - "endpoint": "event_management.assign_program_codes_sessions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/program-codes/assign/sessions", - "isDynamic": false - } - ] - } - ] - }, - "event_management.assign_program_codes_subcontributions": { - "endpoint": "event_management.assign_program_codes_subcontributions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/program-codes/assign/subcontributions", - "isDynamic": false - } - ] - } - ] - }, - "event_management.change_type": { - "endpoint": "event_management.change_type", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/change-type", - "isDynamic": false - } - ] - } - ] - }, - "event_management.clone": { - "endpoint": "event_management.clone", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/clone", - "isDynamic": false - } - ] - } - ] - }, - "event_management.clone_preview": { - "endpoint": "event_management.clone_preview", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/clone/preview", - "isDynamic": false - } - ] - } - ] - }, - "event_management.delete": { - "endpoint": "event_management.delete", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/delete", - "isDynamic": false - } - ] - } - ] - }, - "event_management.edit_classification": { - "endpoint": "event_management.edit_classification", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/settings/classification", - "isDynamic": false - } - ] - } - ] - }, - "event_management.edit_contact_info": { - "endpoint": "event_management.edit_contact_info", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/settings/contact-info", - "isDynamic": false - } - ] - } - ] - }, - "event_management.edit_data": { - "endpoint": "event_management.edit_data", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/settings/data", - "isDynamic": false - } - ] - } - ] - }, - "event_management.edit_dates": { - "endpoint": "event_management.edit_dates", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/settings/dates", - "isDynamic": false - } - ] - } - ] - }, - "event_management.edit_location": { - "endpoint": "event_management.edit_location", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/settings/location", - "isDynamic": false - } - ] - } - ] - }, - "event_management.edit_persons": { - "endpoint": "event_management.edit_persons", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/settings/persons", - "isDynamic": false - } - ] - } - ] - }, - "event_management.lock": { - "endpoint": "event_management.lock", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/lock", - "isDynamic": false - } - ] - } - ] - }, - "event_management.move": { - "endpoint": "event_management.move", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/move", - "isDynamic": false - } - ] - } - ] - }, - "event_management.permissions_dialog": { - "endpoint": "event_management.permissions_dialog", - "rules": [ - { - "args": [ - "type" - ], - "converters": { - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/permissions-dialog/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - } - ] - } - ] - }, - "event_management.poster_settings": { - "endpoint": "event_management.poster_settings", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/print-poster/settings", - "isDynamic": false - } - ] - } - ] - }, - "event_management.print_poster": { - "endpoint": "event_management.print_poster", - "rules": [ - { - "args": [ - "confId", - "template_id", - "uuid" - ], - "converters": { - "template_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/print-poster/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "event_management.program_code_templates": { - "endpoint": "event_management.program_code_templates", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/program-codes/templates", - "isDynamic": false - } - ] - } - ] - }, - "event_management.program_codes": { - "endpoint": "event_management.program_codes", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/program-codes", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_management.protection": { - "endpoint": "event_management.protection", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/protection", - "isDynamic": false - } - ] - } - ] - }, - "event_management.settings": { - "endpoint": "event_management.settings", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_management.show_non_inheriting": { - "endpoint": "event_management.show_non_inheriting", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/show-non-inheriting", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/show-non-inheriting", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": {}, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/show-non-inheriting", - "isDynamic": false - } - ] - } - ] - }, - "event_management.unlock": { - "endpoint": "event_management.unlock", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/unlock", - "isDynamic": false - } - ] - } - ] - }, - "event_notes.compile": { - "endpoint": "event_notes.compile", - "rules": [ - { - "args": [ - "confId", - "object_type" - ], - "converters": {}, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/note/compile", - "isDynamic": false - } - ] - } - ] - }, - "event_notes.delete": { - "endpoint": "event_notes.delete", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/note/delete", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/note/delete", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/note/delete", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": {}, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/note/delete", - "isDynamic": false - } - ] - } - ] - }, - "event_notes.edit": { - "endpoint": "event_notes.edit", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/note/edit", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/note/edit", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/note/edit", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": {}, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/note/edit", - "isDynamic": false - } - ] - } - ] - }, - "event_notes.view": { - "endpoint": "event_notes.view", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "object_type", - "subcontrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "subcontrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "subcontribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/subcontributions/", - "isDynamic": false - }, - { - "data": "subcontrib_id", - "isDynamic": true - }, - { - "data": "/note", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "contrib_id", - "object_type" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": { - "object_type": "contribution" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/note", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": { - "object_type": "session" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/note", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "object_type" - ], - "converters": {}, - "defaults": { - "object_type": "event" - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/note", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_pages.page_display": { - "endpoint": "event_pages.page_display", - "rules": [ - { - "args": [ - "confId", - "page_id", - "slug" - ], - "converters": { - "page_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/page/", - "isDynamic": false - }, - { - "data": "page_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "slug", - "isDynamic": true - } - ] - }, - { - "args": [ - "confId", - "page_id" - ], - "converters": { - "page_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/page/", - "isDynamic": false - }, - { - "data": "page_id", - "isDynamic": true - } - ] - } - ] - }, - "event_participation.manage": { - "endpoint": "event_participation.manage", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/participants", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.add_field": { - "endpoint": "event_registration.add_field", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/fields", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.add_section": { - "endpoint": "event_registration.add_section", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.add_text": { - "endpoint": "event_registration.add_text", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.api_registrant": { - "endpoint": "event_registration.api_registrant", - "rules": [ - { - "args": [ - "event_id", - "registrant_id" - ], - "converters": { - "event_id": "IntegerConverter", - "registrant_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/events/", - "isDynamic": false - }, - { - "data": "event_id", - "isDynamic": true - }, - { - "data": "/registrants/", - "isDynamic": false - }, - { - "data": "registrant_id", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.api_registrants": { - "endpoint": "event_registration.api_registrants", - "rules": [ - { - "args": [ - "event_id" - ], - "converters": { - "event_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/events/", - "isDynamic": false - }, - { - "data": "event_id", - "isDynamic": true - }, - { - "data": "/registrants", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.approve_registration": { - "endpoint": "event_registration.approve_registration", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "registration_id" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/approve", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.check_email": { - "endpoint": "event_registration.check_email", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/check-email", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.close_regform": { - "endpoint": "event_registration.close_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/close", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.create_multiple_registrations": { - "endpoint": "event_registration.create_multiple_registrations", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/create-multiple", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.create_regform": { - "endpoint": "event_registration.create_regform", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/create", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.create_registration": { - "endpoint": "event_registration.create_registration", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/create", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.customize_reglist": { - "endpoint": "event_registration.customize_reglist", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/customize", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.decline_invitation": { - "endpoint": "event_registration.decline_invitation", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/decline-invitation", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.delete_invitation": { - "endpoint": "event_registration.delete_invitation", - "rules": [ - { - "args": [ - "confId", - "invitation_id", - "reg_form_id" - ], - "converters": { - "invitation_id": "IntegerConverter", - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/invitations/", - "isDynamic": false - }, - { - "data": "invitation_id", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.delete_regform": { - "endpoint": "event_registration.delete_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.delete_registrations": { - "endpoint": "event_registration.delete_registrations", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/delete", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.display_regform": { - "endpoint": "event_registration.display_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.display_regform_list": { - "endpoint": "event_registration.display_regform_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.edit_regform": { - "endpoint": "event_registration.edit_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.edit_registration": { - "endpoint": "event_registration.edit_registration", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "registration_id" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.edit_registration_display": { - "endpoint": "event_registration.edit_registration_display", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.email_registrants": { - "endpoint": "event_registration.email_registrants", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/email", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.email_registrants_preview": { - "endpoint": "event_registration.email_registrants_preview", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/email-preview", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.generate_static_url": { - "endpoint": "event_registration.generate_static_url", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/static-url", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.invitations": { - "endpoint": "event_registration.invitations", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/invitations", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.invite": { - "endpoint": "event_registration.invite", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/invitations/invite", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manage_regform": { - "endpoint": "event_registration.manage_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manage_regform_display": { - "endpoint": "event_registration.manage_regform_display", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/display", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manage_regform_list": { - "endpoint": "event_registration.manage_regform_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manage_regforms_display": { - "endpoint": "event_registration.manage_regforms_display", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/display", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manage_registration_managers": { - "endpoint": "event_registration.manage_registration_managers", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/managers", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manage_reglist": { - "endpoint": "event_registration.manage_reglist", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.manager_decline_invitation": { - "endpoint": "event_registration.manager_decline_invitation", - "rules": [ - { - "args": [ - "confId", - "invitation_id", - "reg_form_id" - ], - "converters": { - "invitation_id": "IntegerConverter", - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/invitations/", - "isDynamic": false - }, - { - "data": "invitation_id", - "isDynamic": true - }, - { - "data": "/decline", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.modify_field": { - "endpoint": "event_registration.modify_field", - "rules": [ - { - "args": [ - "confId", - "field_id", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/fields/", - "isDynamic": false - }, - { - "data": "field_id", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.modify_regform": { - "endpoint": "event_registration.modify_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.modify_section": { - "endpoint": "event_registration.modify_section", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.modify_text": { - "endpoint": "event_registration.modify_text", - "rules": [ - { - "args": [ - "confId", - "field_id", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text/", - "isDynamic": false - }, - { - "data": "field_id", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.move_field": { - "endpoint": "event_registration.move_field", - "rules": [ - { - "args": [ - "confId", - "field_id", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/fields/", - "isDynamic": false - }, - { - "data": "field_id", - "isDynamic": true - }, - { - "data": "/move", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.move_section": { - "endpoint": "event_registration.move_section", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/move", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.move_text": { - "endpoint": "event_registration.move_text", - "rules": [ - { - "args": [ - "confId", - "field_id", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text/", - "isDynamic": false - }, - { - "data": "field_id", - "isDynamic": true - }, - { - "data": "/move", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.open_regform": { - "endpoint": "event_registration.open_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/open", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.participant_list": { - "endpoint": "event_registration.participant_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/participants", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.regform_stats": { - "endpoint": "event_registration.regform_stats", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/stats", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registration_check_in": { - "endpoint": "event_registration.registration_check_in", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "registration_id" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/check-in", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registration_details": { - "endpoint": "event_registration.registration_details", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "registration_id" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registration_file": { - "endpoint": "event_registration.registration_file", - "rules": [ - { - "args": [ - "confId", - "field_data_id", - "filename", - "reg_form_id", - "registration_id" - ], - "converters": { - "field_data_id": "IntegerConverter", - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/file/", - "isDynamic": false - }, - { - "data": "field_data_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.registrations_attachments_export": { - "endpoint": "event_registration.registrations_attachments_export", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/attachments", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_check_in": { - "endpoint": "event_registration.registrations_check_in", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/check-in", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_config_badges": { - "endpoint": "event_registration.registrations_config_badges", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/badges/config", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_config_tickets": { - "endpoint": "event_registration.registrations_config_tickets", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/tickets/config", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_csv_export": { - "endpoint": "event_registration.registrations_csv_export", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/registrations.csv", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_excel_export": { - "endpoint": "event_registration.registrations_excel_export", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/registrations.xlsx", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_import": { - "endpoint": "event_registration.registrations_import", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/import", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_modify_status": { - "endpoint": "event_registration.registrations_modify_status", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/modify-status", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_pdf_export_book": { - "endpoint": "event_registration.registrations_pdf_export_book", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/book.pdf", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_pdf_export_table": { - "endpoint": "event_registration.registrations_pdf_export_table", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/table.pdf", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.registrations_print_badges": { - "endpoint": "event_registration.registrations_print_badges", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "template_id", - "uuid" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "template_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/badges/print/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "event_registration.reject_registration": { - "endpoint": "event_registration.reject_registration", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "registration_id" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/reject", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.schedule_regform": { - "endpoint": "event_registration.schedule_regform", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/schedule", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.ticket_download": { - "endpoint": "event_registration.ticket_download", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/ticket.pdf", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.tickets": { - "endpoint": "event_registration.tickets", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/tickets", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.tickets_qrcode": { - "endpoint": "event_registration.tickets_qrcode", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/tickets/qrcode", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.tickets_qrcode_image": { - "endpoint": "event_registration.tickets_qrcode_image", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/tickets/qrcode.png", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.toggle_field": { - "endpoint": "event_registration.toggle_field", - "rules": [ - { - "args": [ - "confId", - "field_id", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/fields/", - "isDynamic": false - }, - { - "data": "field_id", - "isDynamic": true - }, - { - "data": "/toggle", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.toggle_registration_payment": { - "endpoint": "event_registration.toggle_registration_payment", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "registration_id" - ], - "converters": { - "reg_form_id": "IntegerConverter", - "registration_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "registration_id", - "isDynamic": true - }, - { - "data": "/toggle-payment", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.toggle_section": { - "endpoint": "event_registration.toggle_section", - "rules": [ - { - "args": [ - "confId", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/toggle", - "isDynamic": false - } - ] - } - ] - }, - "event_registration.toggle_text": { - "endpoint": "event_registration.toggle_text", - "rules": [ - { - "args": [ - "confId", - "field_id", - "reg_form_id", - "section_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/registration/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/form/sections/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text/", - "isDynamic": false - }, - { - "data": "field_id", - "isDynamic": true - }, - { - "data": "/toggle", - "isDynamic": false - } - ] - } - ] - }, - "event_reminders.add": { - "endpoint": "event_reminders.add", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/reminders/add", - "isDynamic": false - } - ] - } - ] - }, - "event_reminders.delete": { - "endpoint": "event_reminders.delete", - "rules": [ - { - "args": [ - "confId", - "reminder_id" - ], - "converters": { - "reminder_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/reminders/", - "isDynamic": false - }, - { - "data": "reminder_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "event_reminders.edit": { - "endpoint": "event_reminders.edit", - "rules": [ - { - "args": [ - "confId", - "reminder_id" - ], - "converters": { - "reminder_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/reminders/", - "isDynamic": false - }, - { - "data": "reminder_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_reminders.list": { - "endpoint": "event_reminders.list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/reminders", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_reminders.preview": { - "endpoint": "event_reminders.preview", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/reminders/preview", - "isDynamic": false - } - ] - } - ] - }, - "event_roles.add_members": { - "endpoint": "event_roles.add_members", - "rules": [ - { - "args": [ - "confId", - "role_id" - ], - "converters": { - "role_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/roles/", - "isDynamic": false - }, - { - "data": "role_id", - "isDynamic": true - }, - { - "data": "/members", - "isDynamic": false - } - ] - } - ] - }, - "event_roles.add_role": { - "endpoint": "event_roles.add_role", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/roles/create", - "isDynamic": false - } - ] - } - ] - }, - "event_roles.delete_role": { - "endpoint": "event_roles.delete_role", - "rules": [ - { - "args": [ - "confId", - "role_id" - ], - "converters": { - "role_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/roles/", - "isDynamic": false - }, - { - "data": "role_id", - "isDynamic": true - } - ] - } - ] - }, - "event_roles.edit_role": { - "endpoint": "event_roles.edit_role", - "rules": [ - { - "args": [ - "confId", - "role_id" - ], - "converters": { - "role_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/roles/", - "isDynamic": false - }, - { - "data": "role_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "event_roles.manage": { - "endpoint": "event_roles.manage", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/roles", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "event_roles.remove_member": { - "endpoint": "event_roles.remove_member", - "rules": [ - { - "args": [ - "confId", - "role_id", - "user_id" - ], - "converters": { - "role_id": "IntegerConverter", - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/roles/", - "isDynamic": false - }, - { - "data": "role_id", - "isDynamic": true - }, - { - "data": "/members/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - } - ] - } - ] - }, - "events.create": { - "endpoint": "events.create", - "rules": [ - { - "args": [ - "event_type" - ], - "converters": { - "event_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/create/", - "isDynamic": false - }, - { - "data": "event_type", - "isDynamic": true - } - ] - } - ] - }, - "events.create_reference_type": { - "endpoint": "events.create_reference_type", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/external-id-types/create", - "isDynamic": false - } - ] - } - ] - }, - "events.delete_reference_type": { - "endpoint": "events.delete_reference_type", - "rules": [ - { - "args": [ - "reference_type_id" - ], - "converters": { - "reference_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/external-id-types/", - "isDynamic": false - }, - { - "data": "reference_type_id", - "isDynamic": true - } - ] - } - ] - }, - "events.display": { - "endpoint": "events.display", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "events.display_other": { - "endpoint": "events.display_other", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/other-view", - "isDynamic": false - } - ] - } - ] - }, - "events.display_overview": { - "endpoint": "events.display_overview", - "rules": [ - { - "args": [ - "confId", - "force_overview" - ], - "converters": {}, - "defaults": { - "force_overview": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/overview", - "isDynamic": false - } - ] - } - ] - }, - "events.export_event_ical": { - "endpoint": "events.export_event_ical", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/event.ics", - "isDynamic": false - } - ] - } - ] - }, - "events.key_access": { - "endpoint": "events.key_access", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/key-access", - "isDynamic": false - } - ] - } - ] - }, - "events.marcxml": { - "endpoint": "events.marcxml", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/event.marc.xml", - "isDynamic": false - } - ] - } - ] - }, - "events.reference_types": { - "endpoint": "events.reference_types", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/external-id-types", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "events.shorturl": { - "endpoint": "events.shorturl", - "rules": [ - { - "args": [ - "confId", - "shorturl_namespace" - ], - "converters": { - "confId": "PathConverter" - }, - "defaults": { - "shorturl_namespace": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/e/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - } - ] - } - ] - }, - "events.update_reference_type": { - "endpoint": "events.update_reference_type", - "rules": [ - { - "args": [ - "reference_type_id" - ], - "converters": { - "reference_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/external-id-types/", - "isDynamic": false - }, - { - "data": "reference_type_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "files.delete_file": { - "endpoint": "files.delete_file", - "rules": [ - { - "args": [ - "uuid" - ], - "converters": { - "uuid": "UUIDConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/files/", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "files.file_info": { - "endpoint": "files.file_info", - "rules": [ - { - "args": [ - "uuid" - ], - "converters": { - "uuid": "UUIDConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/files/", - "isDynamic": false - }, - { - "data": "uuid", - "isDynamic": true - } - ] - } - ] - }, - "groups.group_add": { - "endpoint": "groups.group_add", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups/indico/new", - "isDynamic": false - } - ] - } - ] - }, - "groups.group_delete": { - "endpoint": "groups.group_delete", - "rules": [ - { - "args": [ - "group_id", - "provider" - ], - "converters": { - "group_id": "IntegerConverter", - "provider": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "group_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "groups.group_delete_member": { - "endpoint": "groups.group_delete_member", - "rules": [ - { - "args": [ - "group_id", - "provider", - "user_id" - ], - "converters": { - "group_id": "IntegerConverter", - "provider": "AnyConverter", - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "group_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - } - ] - } - ] - }, - "groups.group_details": { - "endpoint": "groups.group_details", - "rules": [ - { - "args": [ - "group_id", - "provider" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "group_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "groups.group_edit": { - "endpoint": "groups.group_edit", - "rules": [ - { - "args": [ - "group_id", - "provider" - ], - "converters": { - "group_id": "IntegerConverter", - "provider": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "group_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "groups.group_members": { - "endpoint": "groups.group_members", - "rules": [ - { - "args": [ - "group_id", - "provider" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups/", - "isDynamic": false - }, - { - "data": "provider", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "group_id", - "isDynamic": true - }, - { - "data": "/members", - "isDynamic": false - } - ] - } - ] - }, - "groups.group_search": { - "endpoint": "groups.group_search", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/groups/api/search", - "isDynamic": false - } - ] - } - ] - }, - "groups.groups": { - "endpoint": "groups.groups", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/groups", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "legal.display_privacy": { - "endpoint": "legal.display_privacy", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/privacy", - "isDynamic": false - } - ] - } - ] - }, - "legal.display_tos": { - "endpoint": "legal.display_tos", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/tos", - "isDynamic": false - } - ] - } - ] - }, - "legal.manage": { - "endpoint": "legal.manage", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/legal", - "isDynamic": false - } - ] - } - ] - }, - "networks.create_group": { - "endpoint": "networks.create_group", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/networks/create", - "isDynamic": false - } - ] - } - ] - }, - "networks.delete_group": { - "endpoint": "networks.delete_group", - "rules": [ - { - "args": [ - "network_group_id" - ], - "converters": { - "network_group_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/networks/", - "isDynamic": false - }, - { - "data": "network_group_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "networks.edit_group": { - "endpoint": "networks.edit_group", - "rules": [ - { - "args": [ - "network_group_id" - ], - "converters": { - "network_group_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/networks/", - "isDynamic": false - }, - { - "data": "network_group_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "networks.manage": { - "endpoint": "networks.manage", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/networks", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "news.create_news": { - "endpoint": "news.create_news", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/news/create", - "isDynamic": false - } - ] - } - ] - }, - "news.delete_news": { - "endpoint": "news.delete_news", - "rules": [ - { - "args": [ - "news_id" - ], - "converters": { - "news_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/news/", - "isDynamic": false - }, - { - "data": "news_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "news.display": { - "endpoint": "news.display", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/news", - "isDynamic": false - } - ] - } - ] - }, - "news.edit_news": { - "endpoint": "news.edit_news", - "rules": [ - { - "args": [ - "news_id" - ], - "converters": { - "news_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/news/", - "isDynamic": false - }, - { - "data": "news_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "news.manage": { - "endpoint": "news.manage", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/news", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "news.settings": { - "endpoint": "news.settings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/news/settings", - "isDynamic": false - } - ] - } - ] - }, - "oauth.app_delete": { - "endpoint": "oauth.app_delete", - "rules": [ - { - "args": [ - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/apps/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "oauth.app_details": { - "endpoint": "oauth.app_details", - "rules": [ - { - "args": [ - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/apps/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "oauth.app_new": { - "endpoint": "oauth.app_new", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/apps/new", - "isDynamic": false - } - ] - } - ] - }, - "oauth.app_reset": { - "endpoint": "oauth.app_reset", - "rules": [ - { - "args": [ - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/apps/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/reset", - "isDynamic": false - } - ] - } - ] - }, - "oauth.app_revoke": { - "endpoint": "oauth.app_revoke", - "rules": [ - { - "args": [ - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/apps/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/revoke", - "isDynamic": false - } - ] - } - ] - }, - "oauth.apps": { - "endpoint": "oauth.apps", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/apps", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "oauth.oauth_authorize": { - "endpoint": "oauth.oauth_authorize", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/oauth/authorize", - "isDynamic": false - } - ] - } - ] - }, - "oauth.oauth_errors": { - "endpoint": "oauth.oauth_errors", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/oauth/errors", - "isDynamic": false - } - ] - } - ] - }, - "oauth.oauth_token": { - "endpoint": "oauth.oauth_token", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/oauth/token", - "isDynamic": false - } - ] - } - ] - }, - "oauth.user_profile": { - "endpoint": "oauth.user_profile", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/applications", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/applications", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "oauth.user_token_revoke": { - "endpoint": "oauth.user_token_revoke", - "rules": [ - { - "args": [ - "id", - "user_id" - ], - "converters": { - "id": "IntegerConverter", - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/applications/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/revoke", - "isDynamic": false - } - ] - }, - { - "args": [ - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/applications/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": "/revoke", - "isDynamic": false - } - ] - } - ] - }, - "papers.api_delete_comment": { - "endpoint": "papers.api_delete_comment", - "rules": [ - { - "args": [ - "comment_id", - "confId", - "contrib_id", - "revision_id" - ], - "converters": { - "comment_id": "IntegerConverter", - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/api/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/revision/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/comment/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - } - ] - }, - "papers.api_judge_paper": { - "endpoint": "papers.api_judge_paper", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/api/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/judge", - "isDynamic": false - } - ] - } - ] - }, - "papers.api_paper_details": { - "endpoint": "papers.api_paper_details", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/api/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - } - ] - } - ] - }, - "papers.api_reset_paper_state": { - "endpoint": "papers.api_reset_paper_state", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/api/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - } - ] - } - ] - }, - "papers.api_submit_comment": { - "endpoint": "papers.api_submit_comment", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/api/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/comment", - "isDynamic": false - } - ] - } - ] - }, - "papers.api_submit_revision": { - "endpoint": "papers.api_submit_revision", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/api/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/paper/submit", - "isDynamic": false - } - ] - } - ] - }, - "papers.assign_papers": { - "endpoint": "papers.assign_papers", - "rules": [ - { - "args": [ - "confId", - "management", - "role" - ], - "converters": { - "role": "AnyConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/assignment-list/assign/", - "isDynamic": false - }, - { - "data": "role", - "isDynamic": true - } - ] - }, - { - "args": [ - "confId", - "management", - "role" - ], - "converters": { - "role": "AnyConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/judging/assign/", - "isDynamic": false - }, - { - "data": "role", - "isDynamic": true - } - ] - } - ] - }, - "papers.call_for_papers": { - "endpoint": "papers.call_for_papers", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.close_cfp": { - "endpoint": "papers.close_cfp", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/close", - "isDynamic": false - } - ] - } - ] - }, - "papers.contact_staff": { - "endpoint": "papers.contact_staff", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/teams/contact", - "isDynamic": false - } - ] - } - ] - }, - "papers.create_reviewing_question": { - "endpoint": "papers.create_reviewing_question", - "rules": [ - { - "args": [ - "confId", - "review_type" - ], - "converters": { - "review_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/questions/", - "isDynamic": false - }, - { - "data": "review_type", - "isDynamic": true - }, - { - "data": "/create", - "isDynamic": false - } - ] - } - ] - }, - "papers.customize_paper_list": { - "endpoint": "papers.customize_paper_list", - "rules": [ - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/assignment-list/customize", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/judging/customize", - "isDynamic": false - } - ] - } - ] - }, - "papers.delete_comment": { - "endpoint": "papers.delete_comment", - "rules": [ - { - "args": [ - "comment_id", - "confId", - "contrib_id", - "revision_id" - ], - "converters": { - "comment_id": "IntegerConverter", - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/revision/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/comment/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - } - ] - }, - "papers.delete_reviewing_question": { - "endpoint": "papers.delete_reviewing_question", - "rules": [ - { - "args": [ - "confId", - "question_id", - "review_type" - ], - "converters": { - "question_id": "IntegerConverter", - "review_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/questions/", - "isDynamic": false - }, - { - "data": "review_type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "question_id", - "isDynamic": true - } - ] - } - ] - }, - "papers.delete_template": { - "endpoint": "papers.delete_template", - "rules": [ - { - "args": [ - "confId", - "filename", - "template_id" - ], - "converters": { - "template_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/templates/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "papers.download_file": { - "endpoint": "papers.download_file", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "file_id", - "filename" - ], - "converters": { - "contrib_id": "IntegerConverter", - "file_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/files/", - "isDynamic": false - }, - { - "data": "file_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "papers.download_papers": { - "endpoint": "papers.download_papers", - "rules": [ - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/assignment-list/download", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/judging/download", - "isDynamic": false - } - ] - } - ] - }, - "papers.download_template": { - "endpoint": "papers.download_template", - "rules": [ - { - "args": [ - "confId", - "filename", - "template_id" - ], - "converters": { - "template_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/templates/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "papers.edit_comment": { - "endpoint": "papers.edit_comment", - "rules": [ - { - "args": [ - "comment_id", - "confId", - "contrib_id", - "revision_id" - ], - "converters": { - "comment_id": "IntegerConverter", - "contrib_id": "IntegerConverter", - "revision_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/revision/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/comment/", - "isDynamic": false - }, - { - "data": "comment_id", - "isDynamic": true - } - ] - } - ] - }, - "papers.edit_review": { - "endpoint": "papers.edit_review", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "review_id", - "revision_id" - ], - "converters": { - "contrib_id": "IntegerConverter", - "review_id": "IntegerConverter", - "revision_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/revision/", - "isDynamic": false - }, - { - "data": "revision_id", - "isDynamic": true - }, - { - "data": "/review/", - "isDynamic": false - }, - { - "data": "review_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "papers.edit_reviewing_question": { - "endpoint": "papers.edit_reviewing_question", - "rules": [ - { - "args": [ - "confId", - "question_id", - "review_type" - ], - "converters": { - "question_id": "IntegerConverter", - "review_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/questions/", - "isDynamic": false - }, - { - "data": "review_type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "question_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "papers.edit_template": { - "endpoint": "papers.edit_template", - "rules": [ - { - "args": [ - "confId", - "filename", - "template_id" - ], - "converters": { - "template_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/templates/", - "isDynamic": false - }, - { - "data": "template_id", - "isDynamic": true - }, - { - "data": "-", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "papers.judge_paper": { - "endpoint": "papers.judge_paper", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/judgment", - "isDynamic": false - } - ] - } - ] - }, - "papers.judge_papers": { - "endpoint": "papers.judge_papers", - "rules": [ - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/assignment-list/judge", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/judging/judge", - "isDynamic": false - } - ] - } - ] - }, - "papers.manage_competences": { - "endpoint": "papers.manage_competences", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/teams/competences", - "isDynamic": false - } - ] - } - ] - }, - "papers.manage_deadline": { - "endpoint": "papers.manage_deadline", - "rules": [ - { - "args": [ - "confId", - "role" - ], - "converters": { - "role": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/deadlines/", - "isDynamic": false - }, - { - "data": "role", - "isDynamic": true - } - ] - } - ] - }, - "papers.manage_reviewing_questions": { - "endpoint": "papers.manage_reviewing_questions", - "rules": [ - { - "args": [ - "confId", - "review_type" - ], - "converters": { - "review_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/questions/", - "isDynamic": false - }, - { - "data": "review_type", - "isDynamic": true - } - ] - } - ] - }, - "papers.manage_reviewing_settings": { - "endpoint": "papers.manage_reviewing_settings", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/settings", - "isDynamic": false - } - ] - } - ] - }, - "papers.manage_teams": { - "endpoint": "papers.manage_teams", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/teams", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.manage_templates": { - "endpoint": "papers.manage_templates", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/templates", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.management": { - "endpoint": "papers.management", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.new_paper_timeline": { - "endpoint": "papers.new_paper_timeline", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/new", - "isDynamic": false - } - ] - } - ] - }, - "papers.open_cfp": { - "endpoint": "papers.open_cfp", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/open", - "isDynamic": false - } - ] - } - ] - }, - "papers.paper_timeline": { - "endpoint": "papers.paper_timeline", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.papers_list": { - "endpoint": "papers.papers_list", - "rules": [ - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/assignment-list", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "management" - ], - "converters": {}, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/judging", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.reset_paper_state": { - "endpoint": "papers.reset_paper_state", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/judgment", - "isDynamic": false - } - ] - } - ] - }, - "papers.reviewing_area": { - "endpoint": "papers.reviewing_area", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/reviewing", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "papers.schedule_cfp": { - "endpoint": "papers.schedule_cfp", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/schedule", - "isDynamic": false - } - ] - } - ] - }, - "papers.select_contribution": { - "endpoint": "papers.select_contribution", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/select-contribution", - "isDynamic": false - } - ] - } - ] - }, - "papers.sort_reviewing_questions": { - "endpoint": "papers.sort_reviewing_questions", - "rules": [ - { - "args": [ - "confId", - "review_type" - ], - "converters": { - "review_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/questions/", - "isDynamic": false - }, - { - "data": "review_type", - "isDynamic": true - }, - { - "data": "/sort", - "isDynamic": false - } - ] - } - ] - }, - "papers.submit_comment": { - "endpoint": "papers.submit_comment", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/comment", - "isDynamic": false - } - ] - } - ] - }, - "papers.submit_review": { - "endpoint": "papers.submit_review", - "rules": [ - { - "args": [ - "confId", - "contrib_id", - "review_type" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/review/type/", - "isDynamic": false - }, - { - "data": "review_type", - "isDynamic": true - } - ] - } - ] - }, - "papers.submit_revision": { - "endpoint": "papers.submit_revision", - "rules": [ - { - "args": [ - "confId", - "contrib_id" - ], - "converters": { - "contrib_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/contributions/", - "isDynamic": false - }, - { - "data": "contrib_id", - "isDynamic": true - }, - { - "data": "/paper/submit", - "isDynamic": false - } - ] - } - ] - }, - "papers.switch": { - "endpoint": "papers.switch", - "rules": [ - { - "args": [ - "confId", - "reviewing_type" - ], - "converters": { - "reviewing_type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/enable/", - "isDynamic": false - }, - { - "data": "reviewing_type", - "isDynamic": true - } - ] - } - ] - }, - "papers.unassign_papers": { - "endpoint": "papers.unassign_papers", - "rules": [ - { - "args": [ - "confId", - "management", - "role" - ], - "converters": { - "role": "AnyConverter" - }, - "defaults": { - "management": true - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/assignment-list/unassign/", - "isDynamic": false - }, - { - "data": "role", - "isDynamic": true - } - ] - }, - { - "args": [ - "confId", - "management", - "role" - ], - "converters": { - "role": "AnyConverter" - }, - "defaults": { - "management": false - }, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/papers/judging/unassign/", - "isDynamic": false - }, - { - "data": "role", - "isDynamic": true - } - ] - } - ] - }, - "papers.upload_template": { - "endpoint": "papers.upload_template", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/papers/templates/add", - "isDynamic": false - } - ] - } - ] - }, - "payment.admin_plugin_settings": { - "endpoint": "payment.admin_plugin_settings", - "rules": [ - { - "args": [ - "plugin" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/payment/", - "isDynamic": false - }, - { - "data": "plugin", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "payment.admin_settings": { - "endpoint": "payment.admin_settings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/payment", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "payment.event_payment": { - "endpoint": "payment.event_payment", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/checkout", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "payment.event_payment_conditions": { - "endpoint": "payment.event_payment_conditions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/payment/conditions", - "isDynamic": false - } - ] - } - ] - }, - "payment.event_payment_form": { - "endpoint": "payment.event_payment_form", - "rules": [ - { - "args": [ - "confId", - "reg_form_id" - ], - "converters": { - "reg_form_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/registrations/", - "isDynamic": false - }, - { - "data": "reg_form_id", - "isDynamic": true - }, - { - "data": "/checkout/form", - "isDynamic": false - } - ] - } - ] - }, - "payment.event_plugin_edit": { - "endpoint": "payment.event_plugin_edit", - "rules": [ - { - "args": [ - "confId", - "method" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/payments/method/", - "isDynamic": false - }, - { - "data": "method", - "isDynamic": true - } - ] - } - ] - }, - "payment.event_settings": { - "endpoint": "payment.event_settings", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/payments", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "payment.event_settings_edit": { - "endpoint": "payment.event_settings_edit", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/payments/settings", - "isDynamic": false - } - ] - } - ] - }, - "persons.edit_person": { - "endpoint": "persons.edit_person", - "rules": [ - { - "args": [ - "confId", - "person_id" - ], - "converters": { - "person_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/persons/", - "isDynamic": false - }, - { - "data": "person_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "persons.email_event_persons": { - "endpoint": "persons.email_event_persons", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/persons/email", - "isDynamic": false - } - ] - } - ] - }, - "persons.grant_modification_rights": { - "endpoint": "persons.grant_modification_rights", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/persons/grant-modification", - "isDynamic": false - } - ] - } - ] - }, - "persons.grant_submission_rights": { - "endpoint": "persons.grant_submission_rights", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/persons/grant-submission", - "isDynamic": false - } - ] - } - ] - }, - "persons.person_list": { - "endpoint": "persons.person_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/persons", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "persons.revoke_submission_rights": { - "endpoint": "persons.revoke_submission_rights", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/persons/revoke-submission", - "isDynamic": false - } - ] - } - ] - }, - "plugin_vc_zoom.set_room_owner": { - "endpoint": "plugin_vc_zoom.set_room_owner", - "rules": [ - { - "args": [ - "confId", - "event_vc_room_id", - "service" - ], - "converters": { - "event_vc_room_id": "IntegerConverter", - "service": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "event_vc_room_id", - "isDynamic": true - }, - { - "data": "/room-owner", - "isDynamic": false - } - ] - } - ] - }, - "plugin_vc_zoom.static": { - "endpoint": "plugin_vc_zoom.static", - "rules": [ - { - "args": [ - "filename" - ], - "converters": { - "filename": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/static/plugins/vc_zoom/", - "isDynamic": false - }, - { - "data": "filename", - "isDynamic": true - } - ] - } - ] - }, - "plugins.details": { - "endpoint": "plugins.details", - "rules": [ - { - "args": [ - "plugin" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/plugins/", - "isDynamic": false - }, - { - "data": "plugin", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "plugins.index": { - "endpoint": "plugins.index", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/plugins", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.404": { - "endpoint": "rb.404", - "rules": [ - { - "args": [ - "path" - ], - "converters": { - "path": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/", - "isDynamic": false - }, - { - "data": "path", - "isDynamic": true - } - ] - } - ] - }, - "rb.active_bookings": { - "endpoint": "rb.active_bookings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/active", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_attributes": { - "endpoint": "rb.admin_attributes", - "rules": [ - { - "args": [ - "attribute_id" - ], - "converters": { - "attribute_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/attributes/", - "isDynamic": false - }, - { - "data": "attribute_id", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/attributes", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_equipment_types": { - "endpoint": "rb.admin_equipment_types", - "rules": [ - { - "args": [ - "equipment_type_id" - ], - "converters": { - "equipment_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/equipment-types/", - "isDynamic": false - }, - { - "data": "equipment_type_id", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/equipment-types", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_features": { - "endpoint": "rb.admin_features", - "rules": [ - { - "args": [ - "feature_id" - ], - "converters": { - "feature_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/features/", - "isDynamic": false - }, - { - "data": "feature_id", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/features", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_locations": { - "endpoint": "rb.admin_locations", - "rules": [ - { - "args": [ - "location_id" - ], - "converters": { - "location_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/locations/", - "isDynamic": false - }, - { - "data": "location_id", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/locations", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_map_areas": { - "endpoint": "rb.admin_map_areas", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/map-areas", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_room": { - "endpoint": "rb.admin_room", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.admin_room_attributes": { - "endpoint": "rb.admin_room_attributes", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/attributes", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_room_availability": { - "endpoint": "rb.admin_room_availability", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/availability", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_room_equipment": { - "endpoint": "rb.admin_room_equipment", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/equipment", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_room_photo": { - "endpoint": "rb.admin_room_photo", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/photo", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_rooms": { - "endpoint": "rb.admin_rooms", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_settings": { - "endpoint": "rb.admin_settings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/settings", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_update_room_attributes": { - "endpoint": "rb.admin_update_room_attributes", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/attributes", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_update_room_availability": { - "endpoint": "rb.admin_update_room_availability", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/availability", - "isDynamic": false - } - ] - } - ] - }, - "rb.admin_update_room_equipment": { - "endpoint": "rb.admin_update_room_equipment", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/admin/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/equipment", - "isDynamic": false - } - ] - } - ] - }, - "rb.blocking": { - "endpoint": "rb.blocking", - "rules": [ - { - "args": [ - "blocking_id" - ], - "converters": { - "blocking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/blockings/", - "isDynamic": false - }, - { - "data": "blocking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.blocking_actions": { - "endpoint": "rb.blocking_actions", - "rules": [ - { - "args": [ - "action", - "blocking_id", - "room_id" - ], - "converters": { - "action": "AnyConverter", - "blocking_id": "IntegerConverter", - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/blockings/", - "isDynamic": false - }, - { - "data": "blocking_id", - "isDynamic": true - }, - { - "data": "/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "action", - "isDynamic": true - } - ] - } - ] - }, - "rb.blocking_link": { - "endpoint": "rb.blocking_link", - "rules": [ - { - "args": [ - "blocking_id" - ], - "converters": { - "blocking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/blocking/", - "isDynamic": false - }, - { - "data": "blocking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.blockings": { - "endpoint": "rb.blockings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/blockings", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.booking_details": { - "endpoint": "rb.booking_details", - "rules": [ - { - "args": [ - "booking_id" - ], - "converters": { - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.booking_edit_calendars": { - "endpoint": "rb.booking_edit_calendars", - "rules": [ - { - "args": [ - "booking_id" - ], - "converters": { - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - }, - { - "data": "/edit/calendars", - "isDynamic": false - } - ] - } - ] - }, - "rb.booking_link": { - "endpoint": "rb.booking_link", - "rules": [ - { - "args": [ - "booking_id" - ], - "converters": { - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/booking/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.booking_occurrence_state_actions": { - "endpoint": "rb.booking_occurrence_state_actions", - "rules": [ - { - "args": [ - "action", - "booking_id", - "date" - ], - "converters": { - "action": "AnyConverter", - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "date", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "action", - "isDynamic": true - } - ] - } - ] - }, - "rb.booking_state_actions": { - "endpoint": "rb.booking_state_actions", - "rules": [ - { - "args": [ - "action", - "booking_id" - ], - "converters": { - "action": "AnyConverter", - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "action", - "isDynamic": true - } - ] - } - ] - }, - "rb.calendar": { - "endpoint": "rb.calendar", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/calendar", - "isDynamic": false - } - ] - } - ] - }, - "rb.check_room_available": { - "endpoint": "rb.check_room_available", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/availability/simple", - "isDynamic": false - } - ] - } - ] - }, - "rb.config": { - "endpoint": "rb.config", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/config", - "isDynamic": false - } - ] - } - ] - }, - "rb.create_blocking": { - "endpoint": "rb.create_blocking", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/blockings", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.create_booking": { - "endpoint": "rb.create_booking", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/booking/create", - "isDynamic": false - } - ] - } - ] - }, - "rb.delete_blocking": { - "endpoint": "rb.delete_blocking", - "rules": [ - { - "args": [ - "blocking_id" - ], - "converters": { - "blocking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/blockings/", - "isDynamic": false - }, - { - "data": "blocking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.delete_booking": { - "endpoint": "rb.delete_booking", - "rules": [ - { - "args": [ - "booking_id" - ], - "converters": { - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.equipment_types": { - "endpoint": "rb.equipment_types", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/equipment", - "isDynamic": false - } - ] - } - ] - }, - "rb.event_booking_list": { - "endpoint": "rb.event_booking_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/rooms", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.event_linkable_contributions": { - "endpoint": "rb.event_linkable_contributions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/rooms/linking/contributions", - "isDynamic": false - } - ] - } - ] - }, - "rb.event_linkable_session_blocks": { - "endpoint": "rb.event_linkable_session_blocks", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/rooms/linking/session-blocks", - "isDynamic": false - } - ] - } - ] - }, - "rb.events": { - "endpoint": "rb.events", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/events", - "isDynamic": false - } - ] - } - ] - }, - "rb.export_bookings": { - "endpoint": "rb.export_bookings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/export", - "isDynamic": false - } - ] - } - ] - }, - "rb.export_bookings_file": { - "endpoint": "rb.export_bookings_file", - "rules": [ - { - "args": [ - "format" - ], - "converters": { - "format": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/bookings/export/bookings.", - "isDynamic": false - }, - { - "data": "format", - "isDynamic": true - } - ] - } - ] - }, - "rb.favorite_rooms": { - "endpoint": "rb.favorite_rooms", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/user/favorite-rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/user/favorite-rooms", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.linked_object_data": { - "endpoint": "rb.linked_object_data", - "rules": [ - { - "args": [ - "id", - "type" - ], - "converters": { - "id": "IntegerConverter", - "type": "AnyConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/link-info/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - } - ] - } - ] - }, - "rb.locations": { - "endpoint": "rb.locations", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/locations", - "isDynamic": false - } - ] - } - ] - }, - "rb.map_areas": { - "endpoint": "rb.map_areas", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/map-areas", - "isDynamic": false - } - ] - } - ] - }, - "rb.my_bookings": { - "endpoint": "rb.my_bookings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/mine", - "isDynamic": false - } - ] - } - ] - }, - "rb.my_bookings_link": { - "endpoint": "rb.my_bookings_link", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/my-bookings", - "isDynamic": false - } - ] - } - ] - }, - "rb.permission_types": { - "endpoint": "rb.permission_types", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/permission-types", - "isDynamic": false - } - ] - } - ] - }, - "rb.room": { - "endpoint": "rb.room", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.room_attributes": { - "endpoint": "rb.room_attributes", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/attributes", - "isDynamic": false - } - ] - } - ] - }, - "rb.room_availability": { - "endpoint": "rb.room_availability", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/availability", - "isDynamic": false - } - ] - } - ] - }, - "rb.room_link": { - "endpoint": "rb.room_link", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/room/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.room_permissions": { - "endpoint": "rb.room_permissions", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/permissions", - "isDynamic": false - } - ] - } - ] - }, - "rb.room_photo": { - "endpoint": "rb.room_photo", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": ".jpg", - "isDynamic": false - } - ] - } - ] - }, - "rb.room_stats": { - "endpoint": "rb.room_stats", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/stats", - "isDynamic": false - } - ] - } - ] - }, - "rb.roombooking": { - "endpoint": "rb.roombooking", - "rules": [ - { - "args": [ - "path" - ], - "converters": { - "path": "PathConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/", - "isDynamic": false - }, - { - "data": "path", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.rooms": { - "endpoint": "rb.rooms", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "rb.rooms_permissions": { - "endpoint": "rb.rooms_permissions", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/permissions", - "isDynamic": false - } - ] - } - ] - }, - "rb.search_rooms": { - "endpoint": "rb.search_rooms", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/search", - "isDynamic": false - } - ] - } - ] - }, - "rb.sprite": { - "endpoint": "rb.sprite", - "rules": [ - { - "args": [ - "version" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/rooms-sprite-", - "isDynamic": false - }, - { - "data": "version", - "isDynamic": true - }, - { - "data": ".jpg", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/rooms-sprite.jpg", - "isDynamic": false - } - ] - } - ] - }, - "rb.stats": { - "endpoint": "rb.stats", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/stats", - "isDynamic": false - } - ] - } - ] - }, - "rb.suggestions": { - "endpoint": "rb.suggestions", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/suggestions", - "isDynamic": false - } - ] - } - ] - }, - "rb.timeline": { - "endpoint": "rb.timeline", - "rules": [ - { - "args": [ - "room_id" - ], - "converters": { - "room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/rooms/", - "isDynamic": false - }, - { - "data": "room_id", - "isDynamic": true - }, - { - "data": "/timeline", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/timeline", - "isDynamic": false - } - ] - } - ] - }, - "rb.update_blocking": { - "endpoint": "rb.update_blocking", - "rules": [ - { - "args": [ - "blocking_id" - ], - "converters": { - "blocking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/blockings/", - "isDynamic": false - }, - { - "data": "blocking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.update_booking": { - "endpoint": "rb.update_booking", - "rules": [ - { - "args": [ - "booking_id" - ], - "converters": { - "booking_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/bookings/", - "isDynamic": false - }, - { - "data": "booking_id", - "isDynamic": true - } - ] - } - ] - }, - "rb.user_info": { - "endpoint": "rb.user_info", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/rooms/api/user", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "requests.event_requests": { - "endpoint": "requests.event_requests", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/requests", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "requests.event_requests_details": { - "endpoint": "requests.event_requests_details", - "rules": [ - { - "args": [ - "confId", - "type" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/requests/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "requests.event_requests_process": { - "endpoint": "requests.event_requests_process", - "rules": [ - { - "args": [ - "confId", - "type" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/requests/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/process", - "isDynamic": false - } - ] - } - ] - }, - "requests.event_requests_withdraw": { - "endpoint": "requests.event_requests_withdraw", - "rules": [ - { - "args": [ - "confId", - "type" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/requests/", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - }, - { - "data": "/withdraw", - "isDynamic": false - } - ] - } - ] - }, - "sessions.acl": { - "endpoint": "sessions.acl", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/acl", - "isDynamic": false - } - ] - } - ] - }, - "sessions.acl_message": { - "endpoint": "sessions.acl_message", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/acl-message", - "isDynamic": false - } - ] - } - ] - }, - "sessions.create_session": { - "endpoint": "sessions.create_session", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/create", - "isDynamic": false - } - ] - } - ] - }, - "sessions.create_type": { - "endpoint": "sessions.create_type", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/types/create", - "isDynamic": false - } - ] - } - ] - }, - "sessions.delete_sessions": { - "endpoint": "sessions.delete_sessions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/delete", - "isDynamic": false - } - ] - } - ] - }, - "sessions.delete_type": { - "endpoint": "sessions.delete_type", - "rules": [ - { - "args": [ - "confId", - "session_type_id" - ], - "converters": { - "session_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/types/", - "isDynamic": false - }, - { - "data": "session_type_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "sessions.display_session": { - "endpoint": "sessions.display_session", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "sessions.export_csv": { - "endpoint": "sessions.export_csv", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/sessions.csv", - "isDynamic": false - } - ] - } - ] - }, - "sessions.export_excel": { - "endpoint": "sessions.export_excel", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/sessions.xlsx", - "isDynamic": false - } - ] - } - ] - }, - "sessions.export_ics": { - "endpoint": "sessions.export_ics", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/session.ics", - "isDynamic": false - } - ] - } - ] - }, - "sessions.export_pdf": { - "endpoint": "sessions.export_pdf", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/sessions.pdf", - "isDynamic": false - } - ] - } - ] - }, - "sessions.export_session_timetable": { - "endpoint": "sessions.export_session_timetable", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/session-timetable.pdf", - "isDynamic": false - } - ] - } - ] - }, - "sessions.manage_session_block": { - "endpoint": "sessions.manage_session_block", - "rules": [ - { - "args": [ - "block_id", - "confId", - "session_id" - ], - "converters": { - "block_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/blocks/", - "isDynamic": false - }, - { - "data": "block_id", - "isDynamic": true - } - ] - } - ] - }, - "sessions.manage_type": { - "endpoint": "sessions.manage_type", - "rules": [ - { - "args": [ - "confId", - "session_type_id" - ], - "converters": { - "session_type_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/types/", - "isDynamic": false - }, - { - "data": "session_type_id", - "isDynamic": true - } - ] - } - ] - }, - "sessions.manage_types": { - "endpoint": "sessions.manage_types", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/types", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "sessions.modify_session": { - "endpoint": "sessions.modify_session", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/modify", - "isDynamic": false - } - ] - } - ] - }, - "sessions.my_sessions": { - "endpoint": "sessions.my_sessions", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/sessions/mine", - "isDynamic": false - } - ] - } - ] - }, - "sessions.person_list": { - "endpoint": "sessions.person_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/person-list", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "sessions.session_blocks": { - "endpoint": "sessions.session_blocks", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/blocks", - "isDynamic": false - } - ] - } - ] - }, - "sessions.session_list": { - "endpoint": "sessions.session_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "sessions.session_protection": { - "endpoint": "sessions.session_protection", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/protection", - "isDynamic": false - } - ] - } - ] - }, - "sessions.session_rest": { - "endpoint": "sessions.session_rest", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/sessions/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - } - ] - } - ] - }, - "static_site.build": { - "endpoint": "static_site.build", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/offline-copy/build", - "isDynamic": false - } - ] - } - ] - }, - "static_site.download": { - "endpoint": "static_site.download", - "rules": [ - { - "args": [ - "confId", - "id" - ], - "converters": { - "id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/offline-copy/", - "isDynamic": false - }, - { - "data": "id", - "isDynamic": true - }, - { - "data": ".zip", - "isDynamic": false - } - ] - } - ] - }, - "static_site.list": { - "endpoint": "static_site.list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/offline-copy", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.add_question": { - "endpoint": "surveys.add_question", - "rules": [ - { - "args": [ - "confId", - "section_id", - "survey_id", - "type" - ], - "converters": { - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/question/add-", - "isDynamic": false - }, - { - "data": "type", - "isDynamic": true - } - ] - } - ] - }, - "surveys.add_section": { - "endpoint": "surveys.add_section", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/add-section", - "isDynamic": false - } - ] - } - ] - }, - "surveys.add_text": { - "endpoint": "surveys.add_text", - "rules": [ - { - "args": [ - "confId", - "section_id", - "survey_id" - ], - "converters": { - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text/add", - "isDynamic": false - } - ] - } - ] - }, - "surveys.close_survey": { - "endpoint": "surveys.close_survey", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/close", - "isDynamic": false - } - ] - } - ] - }, - "surveys.create": { - "endpoint": "surveys.create", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/create", - "isDynamic": false - } - ] - } - ] - }, - "surveys.delete_question": { - "endpoint": "surveys.delete_question", - "rules": [ - { - "args": [ - "confId", - "question_id", - "section_id", - "survey_id" - ], - "converters": { - "question_id": "IntegerConverter", - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/question/", - "isDynamic": false - }, - { - "data": "question_id", - "isDynamic": true - } - ] - } - ] - }, - "surveys.delete_section": { - "endpoint": "surveys.delete_section", - "rules": [ - { - "args": [ - "confId", - "section_id", - "survey_id" - ], - "converters": { - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.delete_submissions": { - "endpoint": "surveys.delete_submissions", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/submissions", - "isDynamic": false - } - ] - } - ] - }, - "surveys.delete_survey": { - "endpoint": "surveys.delete_survey", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "surveys.delete_text": { - "endpoint": "surveys.delete_text", - "rules": [ - { - "args": [ - "confId", - "section_id", - "survey_id", - "text_id" - ], - "converters": { - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter", - "text_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text/", - "isDynamic": false - }, - { - "data": "text_id", - "isDynamic": true - } - ] - } - ] - }, - "surveys.display_save_answers": { - "endpoint": "surveys.display_save_answers", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/save", - "isDynamic": false - } - ] - } - ] - }, - "surveys.display_submission": { - "endpoint": "surveys.display_submission", - "rules": [ - { - "args": [ - "confId", - "submission_id", - "survey_id" - ], - "converters": { - "submission_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/submission/", - "isDynamic": false - }, - { - "data": "submission_id", - "isDynamic": true - } - ] - } - ] - }, - "surveys.display_survey_form": { - "endpoint": "surveys.display_survey_form", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - } - ] - } - ] - }, - "surveys.display_survey_list": { - "endpoint": "surveys.display_survey_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/surveys", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.edit_question": { - "endpoint": "surveys.edit_question", - "rules": [ - { - "args": [ - "confId", - "question_id", - "section_id", - "survey_id" - ], - "converters": { - "question_id": "IntegerConverter", - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/question/", - "isDynamic": false - }, - { - "data": "question_id", - "isDynamic": true - } - ] - } - ] - }, - "surveys.edit_section": { - "endpoint": "surveys.edit_section", - "rules": [ - { - "args": [ - "confId", - "section_id", - "survey_id" - ], - "converters": { - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.edit_survey": { - "endpoint": "surveys.edit_survey", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - } - ] - } - ] - }, - "surveys.edit_text": { - "endpoint": "surveys.edit_text", - "rules": [ - { - "args": [ - "confId", - "section_id", - "survey_id", - "text_id" - ], - "converters": { - "section_id": "IntegerConverter", - "survey_id": "IntegerConverter", - "text_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/", - "isDynamic": false - }, - { - "data": "section_id", - "isDynamic": true - }, - { - "data": "/text/", - "isDynamic": false - }, - { - "data": "text_id", - "isDynamic": true - } - ] - } - ] - }, - "surveys.export_questionnaire": { - "endpoint": "surveys.export_questionnaire", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/survey.json", - "isDynamic": false - } - ] - } - ] - }, - "surveys.export_submissions_csv": { - "endpoint": "surveys.export_submissions_csv", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/submissions.csv", - "isDynamic": false - } - ] - } - ] - }, - "surveys.export_submissions_excel": { - "endpoint": "surveys.export_submissions_excel", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/submissions.xlsx", - "isDynamic": false - } - ] - } - ] - }, - "surveys.import_questionnaire": { - "endpoint": "surveys.import_questionnaire", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/import", - "isDynamic": false - } - ] - } - ] - }, - "surveys.manage_questionnaire": { - "endpoint": "surveys.manage_questionnaire", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.manage_survey": { - "endpoint": "surveys.manage_survey", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.manage_survey_list": { - "endpoint": "surveys.manage_survey_list", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "surveys.open_survey": { - "endpoint": "surveys.open_survey", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/open", - "isDynamic": false - } - ] - } - ] - }, - "surveys.schedule_survey": { - "endpoint": "surveys.schedule_survey", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/schedule", - "isDynamic": false - } - ] - } - ] - }, - "surveys.send_links": { - "endpoint": "surveys.send_links", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/send-links", - "isDynamic": false - } - ] - } - ] - }, - "surveys.sort_items": { - "endpoint": "surveys.sort_items", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/questionnaire/sort", - "isDynamic": false - } - ] - } - ] - }, - "surveys.survey_results": { - "endpoint": "surveys.survey_results", - "rules": [ - { - "args": [ - "confId", - "survey_id" - ], - "converters": { - "survey_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/surveys/", - "isDynamic": false - }, - { - "data": "survey_id", - "isDynamic": true - }, - { - "data": "/results", - "isDynamic": false - } - ] - } - ] - }, - "timetable.add_break": { - "endpoint": "timetable.add_break", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/add-break", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/add-break", - "isDynamic": false - } - ] - } - ] - }, - "timetable.add_contribution": { - "endpoint": "timetable.add_contribution", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/add-contribution", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/add-contribution", - "isDynamic": false - } - ] - } - ] - }, - "timetable.add_session": { - "endpoint": "timetable.add_session", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/add-session", - "isDynamic": false - } - ] - } - ] - }, - "timetable.add_session_block": { - "endpoint": "timetable.add_session_block", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/add-session-block", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/add-session-block", - "isDynamic": false - } - ] - } - ] - }, - "timetable.clone_contribution": { - "endpoint": "timetable.clone_contribution", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/clone-contribution", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/clone-contribution", - "isDynamic": false - } - ] - } - ] - }, - "timetable.delete_entry": { - "endpoint": "timetable.delete_entry", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/delete", - "isDynamic": false - } - ] - } - ] - }, - "timetable.edit_entry": { - "endpoint": "timetable.edit_entry", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/edit", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "timetable.edit_entry_datetime": { - "endpoint": "timetable.edit_entry_datetime", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/edit/datetime", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/edit/datetime", - "isDynamic": false - } - ] - } - ] - }, - "timetable.edit_entry_time": { - "endpoint": "timetable.edit_entry_time", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/edit/time", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/edit/time", - "isDynamic": false - } - ] - } - ] - }, - "timetable.entry_info": { - "endpoint": "timetable.entry_info", - "rules": [ - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/info", - "isDynamic": false - } - ] - } - ] - }, - "timetable.entry_info_manage": { - "endpoint": "timetable.entry_info_manage", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/info", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/info", - "isDynamic": false - } - ] - } - ] - }, - "timetable.export_default_pdf": { - "endpoint": "timetable.export_default_pdf", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/timetable/timetable.pdf", - "isDynamic": false - } - ] - } - ] - }, - "timetable.export_pdf": { - "endpoint": "timetable.export_pdf", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/timetable/pdf", - "isDynamic": false - } - ] - } - ] - }, - "timetable.fit_session_block": { - "endpoint": "timetable.fit_session_block", - "rules": [ - { - "args": [ - "block_id", - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/block/", - "isDynamic": false - }, - { - "data": "block_id", - "isDynamic": true - }, - { - "data": "/fit", - "isDynamic": false - } - ] - }, - { - "args": [ - "block_id", - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/block/", - "isDynamic": false - }, - { - "data": "block_id", - "isDynamic": true - }, - { - "data": "/fit", - "isDynamic": false - } - ] - } - ] - }, - "timetable.legacy_break_rest": { - "endpoint": "timetable.legacy_break_rest", - "rules": [ - { - "args": [ - "break_id", - "confId" - ], - "converters": { - "break_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/break/", - "isDynamic": false - }, - { - "data": "break_id", - "isDynamic": true - } - ] - } - ] - }, - "timetable.manage_session": { - "endpoint": "timetable.manage_session", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "timetable.management": { - "endpoint": "timetable.management", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "timetable.move_entry": { - "endpoint": "timetable.move_entry", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/move", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/move", - "isDynamic": false - } - ] - } - ] - }, - "timetable.not_scheduled": { - "endpoint": "timetable.not_scheduled", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/not-scheduled", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/not-scheduled", - "isDynamic": false - } - ] - } - ] - }, - "timetable.reschedule": { - "endpoint": "timetable.reschedule", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/reschedule", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/reschedule", - "isDynamic": false - } - ] - } - ] - }, - "timetable.schedule": { - "endpoint": "timetable.schedule", - "rules": [ - { - "args": [ - "block_id", - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/block/", - "isDynamic": false - }, - { - "data": "block_id", - "isDynamic": true - }, - { - "data": "/schedule", - "isDynamic": false - } - ] - }, - { - "args": [ - "block_id", - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/block/", - "isDynamic": false - }, - { - "data": "block_id", - "isDynamic": true - }, - { - "data": "/schedule", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/schedule", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/schedule", - "isDynamic": false - } - ] - } - ] - }, - "timetable.session_rest": { - "endpoint": "timetable.session_rest", - "rules": [ - { - "args": [ - "confId", - "session_id" - ], - "converters": { - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "timetable.shift_entries": { - "endpoint": "timetable.shift_entries", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/shift", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/shift", - "isDynamic": false - } - ] - } - ] - }, - "timetable.swap_entries": { - "endpoint": "timetable.swap_entries", - "rules": [ - { - "args": [ - "confId", - "entry_id", - "session_id" - ], - "converters": { - "entry_id": "IntegerConverter", - "session_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/session/", - "isDynamic": false - }, - { - "data": "session_id", - "isDynamic": true - }, - { - "data": "/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/swap", - "isDynamic": false - } - ] - }, - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/entry/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - }, - { - "data": "/swap", - "isDynamic": false - } - ] - } - ] - }, - "timetable.timetable": { - "endpoint": "timetable.timetable", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/timetable", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "timetable.timetable_rest": { - "endpoint": "timetable.timetable_rest", - "rules": [ - { - "args": [ - "confId", - "entry_id" - ], - "converters": { - "entry_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable/", - "isDynamic": false - }, - { - "data": "entry_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/timetable", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "tracks.create_track": { - "endpoint": "tracks.create_track", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/tracks/create", - "isDynamic": false - } - ] - } - ] - }, - "tracks.create_track_group": { - "endpoint": "tracks.create_track_group", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/track-groups/create", - "isDynamic": false - } - ] - } - ] - }, - "tracks.delete_track": { - "endpoint": "tracks.delete_track", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/tracks/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - } - ] - } - ] - }, - "tracks.delete_track_group": { - "endpoint": "tracks.delete_track_group", - "rules": [ - { - "args": [ - "confId", - "track_group_id" - ], - "converters": { - "track_group_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/track-groups/", - "isDynamic": false - }, - { - "data": "track_group_id", - "isDynamic": true - } - ] - } - ] - }, - "tracks.edit_program": { - "endpoint": "tracks.edit_program", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/tracks/program", - "isDynamic": false - } - ] - } - ] - }, - "tracks.edit_track": { - "endpoint": "tracks.edit_track", - "rules": [ - { - "args": [ - "confId", - "track_id" - ], - "converters": { - "track_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/tracks/", - "isDynamic": false - }, - { - "data": "track_id", - "isDynamic": true - } - ] - } - ] - }, - "tracks.edit_track_group": { - "endpoint": "tracks.edit_track_group", - "rules": [ - { - "args": [ - "confId", - "track_group_id" - ], - "converters": { - "track_group_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/track-groups/", - "isDynamic": false - }, - { - "data": "track_group_id", - "isDynamic": true - } - ] - } - ] - }, - "tracks.manage": { - "endpoint": "tracks.manage", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/tracks", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "tracks.program": { - "endpoint": "tracks.program", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/program", - "isDynamic": false - } - ] - } - ] - }, - "tracks.program_pdf": { - "endpoint": "tracks.program_pdf", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/program.pdf", - "isDynamic": false - } - ] - } - ] - }, - "tracks.sort_tracks": { - "endpoint": "tracks.sort_tracks", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/tracks/sort", - "isDynamic": false - } - ] - } - ] - }, - "users.accept_registration_request": { - "endpoint": "users.accept_registration_request", - "rules": [ - { - "args": [ - "request_id" - ], - "converters": { - "request_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/registration-requests/", - "isDynamic": false - }, - { - "data": "request_id", - "isDynamic": true - }, - { - "data": "/accept", - "isDynamic": false - } - ] - } - ] - }, - "users.admins": { - "endpoint": "users.admins", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/admins", - "isDynamic": false - } - ] - } - ] - }, - "users.authenticated_user": { - "endpoint": "users.authenticated_user", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/api/user", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.export_dashboard_ics": { - "endpoint": "users.export_dashboard_ics", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/dashboard.ics", - "isDynamic": false - } - ] - } - ] - }, - "users.favorites_api": { - "endpoint": "users.favorites_api", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api/favorites/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/api/favorites", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.registration_request_list": { - "endpoint": "users.registration_request_list", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/registration-requests", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.reject_registration_request": { - "endpoint": "users.reject_registration_request", - "rules": [ - { - "args": [ - "request_id" - ], - "converters": { - "request_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/registration-requests/", - "isDynamic": false - }, - { - "data": "request_id", - "isDynamic": true - }, - { - "data": "/reject", - "isDynamic": false - } - ] - } - ] - }, - "users.user_dashboard": { - "endpoint": "users.user_dashboard", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/dashboard", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/dashboard", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_emails": { - "endpoint": "users.user_emails", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/emails", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/emails", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_emails_delete": { - "endpoint": "users.user_emails_delete", - "rules": [ - { - "args": [ - "email", - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/emails/", - "isDynamic": false - }, - { - "data": "email", - "isDynamic": true - } - ] - }, - { - "args": [ - "email" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/emails/", - "isDynamic": false - }, - { - "data": "email", - "isDynamic": true - } - ] - } - ] - }, - "users.user_emails_set_primary": { - "endpoint": "users.user_emails_set_primary", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/emails/make-primary", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/emails/make-primary", - "isDynamic": false - } - ] - } - ] - }, - "users.user_emails_verify": { - "endpoint": "users.user_emails_verify", - "rules": [ - { - "args": [ - "token", - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/emails/verify/", - "isDynamic": false - }, - { - "data": "token", - "isDynamic": true - } - ] - }, - { - "args": [ - "token" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/emails/verify/", - "isDynamic": false - }, - { - "data": "token", - "isDynamic": true - } - ] - } - ] - }, - "users.user_favorites": { - "endpoint": "users.user_favorites", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/favorites", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/favorites", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_favorites_category_api": { - "endpoint": "users.user_favorites_category_api", - "rules": [ - { - "args": [ - "category_id", - "user_id" - ], - "converters": { - "category_id": "IntegerConverter", - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/favorites/categories/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/favorites/categories/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - } - ] - } - ] - }, - "users.user_favorites_user_remove": { - "endpoint": "users.user_favorites_user_remove", - "rules": [ - { - "args": [ - "fav_user_id", - "user_id" - ], - "converters": { - "fav_user_id": "IntegerConverter", - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/favorites/users/", - "isDynamic": false - }, - { - "data": "fav_user_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "fav_user_id" - ], - "converters": { - "fav_user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/favorites/users/", - "isDynamic": false - }, - { - "data": "fav_user_id", - "isDynamic": true - } - ] - } - ] - }, - "users.user_favorites_users_add": { - "endpoint": "users.user_favorites_users_add", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/favorites/users", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/favorites/users", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_preferences": { - "endpoint": "users.user_preferences", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/preferences", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/preferences", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_profile": { - "endpoint": "users.user_profile", - "rules": [ - { - "args": [ - "user_id" - ], - "converters": { - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/profile", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - }, - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/profile", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_search": { - "endpoint": "users.user_search", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/search", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.user_search_info": { - "endpoint": "users.user_search_info", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/search/info", - "isDynamic": false - } - ] - } - ] - }, - "users.user_suggestions_remove": { - "endpoint": "users.user_suggestions_remove", - "rules": [ - { - "args": [ - "category_id", - "user_id" - ], - "converters": { - "category_id": "IntegerConverter", - "user_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/", - "isDynamic": false - }, - { - "data": "user_id", - "isDynamic": true - }, - { - "data": "/suggestions/categories/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - } - ] - }, - { - "args": [ - "category_id" - ], - "converters": { - "category_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/user/suggestions/categories/", - "isDynamic": false - }, - { - "data": "category_id", - "isDynamic": true - } - ] - } - ] - }, - "users.users_admin": { - "endpoint": "users.users_admin", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.users_admin_settings": { - "endpoint": "users.users_admin_settings", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/settings", - "isDynamic": false - } - ] - } - ] - }, - "users.users_create": { - "endpoint": "users.users_create", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/create", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.users_merge": { - "endpoint": "users.users_merge", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/merge", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "users.users_merge_check": { - "endpoint": "users.users_merge_check", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/admin/users/merge/check", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "vc.event_videoconference": { - "endpoint": "vc.event_videoconference", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/videoconference", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms": { - "endpoint": "vc.manage_vc_rooms", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_create": { - "endpoint": "vc.manage_vc_rooms_create", - "rules": [ - { - "args": [ - "confId", - "service" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/create", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_modify": { - "endpoint": "vc.manage_vc_rooms_modify", - "rules": [ - { - "args": [ - "confId", - "event_vc_room_id", - "service" - ], - "converters": { - "event_vc_room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "event_vc_room_id", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_refresh": { - "endpoint": "vc.manage_vc_rooms_refresh", - "rules": [ - { - "args": [ - "confId", - "event_vc_room_id", - "service" - ], - "converters": { - "event_vc_room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "event_vc_room_id", - "isDynamic": true - }, - { - "data": "/refresh", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_remove": { - "endpoint": "vc.manage_vc_rooms_remove", - "rules": [ - { - "args": [ - "confId", - "event_vc_room_id", - "service" - ], - "converters": { - "event_vc_room_id": "IntegerConverter" - }, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/", - "isDynamic": false - }, - { - "data": "event_vc_room_id", - "isDynamic": true - }, - { - "data": "/remove", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_search": { - "endpoint": "vc.manage_vc_rooms_search", - "rules": [ - { - "args": [ - "confId", - "service" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/search", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_search_form": { - "endpoint": "vc.manage_vc_rooms_search_form", - "rules": [ - { - "args": [ - "confId", - "service" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/", - "isDynamic": false - }, - { - "data": "service", - "isDynamic": true - }, - { - "data": "/attach", - "isDynamic": false - }, - { - "data": "/", - "isDynamic": false - } - ] - } - ] - }, - "vc.manage_vc_rooms_select": { - "endpoint": "vc.manage_vc_rooms_select", - "rules": [ - { - "args": [ - "confId" - ], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/event/", - "isDynamic": false - }, - { - "data": "confId", - "isDynamic": true - }, - { - "data": "/manage/videoconference/select", - "isDynamic": false - } - ] - } - ] - }, - "vc.vc_room_list": { - "endpoint": "vc.vc_room_list", - "rules": [ - { - "args": [], - "converters": {}, - "defaults": {}, - "trace": [ - { - "data": "|", - "isDynamic": false - }, - { - "data": "/service/videoconference", - "isDynamic": false - } - ] - } - ] - } - }, - "version": "4d4825ff3312d57fbcb0dc6a5f6805ec" -} \ No newline at end of file From 936cd87ca3b9c04e0de9153cf972fd44a9d3fffc Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 19 Jun 2020 12:57:33 +0200 Subject: [PATCH 03/94] VC/Zoom: Add code linting config --- .flake8 | 37 +++++++++++++++++++++++++++++++++++++ setup.cfg | 2 ++ 2 files changed, 39 insertions(+) create mode 100644 .flake8 create mode 100644 setup.cfg diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..aff3b92 --- /dev/null +++ b/.flake8 @@ -0,0 +1,37 @@ +[flake8] +max-line-length = 120 + +# colored output +format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s + +# decent quote styles +inline-quotes = single +multiline-quotes = single +docstring-quotes = double +avoid-escape = true + +exclude = + build + dist + docs + ext_modules + htmlcov + indico.egg-info + node_modules + .*/ + # TODO: remove the next two entries and use extend-exclude once flake8 3.8.0 is out + .git + __pycache__ + +ignore = + # allow omitting whitespace around arithmetic operators + E226 + # don't require specific wrapping before/after binary operators + W503 + W504 + # allow assigning lambdas (it's useful for single-line functions defined inside other functions) + E731 + # while single quotes are nicer, we have double quotes in way too many places + Q000 + # for non-docstring multiline strings we don't really enforce a quote style + Q001 diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..a5814c8 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[pydocstyle] +ignore = D100,D101,D102,D103,D104,D105,D107,D203,D213 From 8600b566b47f4d54c847ca700150448c3d9e6f78 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 19 Jun 2020 13:04:38 +0200 Subject: [PATCH 04/94] VC/Zoom: Second version of plugin Many configuration improvements, proper updating of rooms. --- indico_vc_zoom/__init__.py | 2 +- indico_vc_zoom/api/__init__.py | 7 +- indico_vc_zoom/api/client.py | 534 ++++-------------- indico_vc_zoom/blueprint.py | 8 +- indico_vc_zoom/controllers.py | 2 +- indico_vc_zoom/forms.py | 66 ++- ...20200312_1030_b79318836818_crea_tabella.py | 52 -- ...20200403_1957_d86e85a383c1_create_table.py | 66 --- ...20200405_1539_d54585a383v1_create_table.py | 46 -- ...107_f0f5f81fefca_add_zoom_plugin_tables.py | 39 ++ indico_vc_zoom/models/zoom_meetings.py | 5 - indico_vc_zoom/plugin.py | 327 +++++++---- indico_vc_zoom/task.py | 9 +- indico_vc_zoom/templates/info_box.html | 6 +- .../templates/manage_event_info_box.html | 18 +- indico_vc_zoom/util.py | 93 +-- setup.py | 1 - 17 files changed, 469 insertions(+), 812 deletions(-) delete mode 100644 indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py delete mode 100644 indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py delete mode 100644 indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py create mode 100644 indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py diff --git a/indico_vc_zoom/__init__.py b/indico_vc_zoom/__init__.py index 22dd971..6b83e11 100644 --- a/indico_vc_zoom/__init__.py +++ b/indico_vc_zoom/__init__.py @@ -9,4 +9,4 @@ _ = make_bound_gettext('vc_zoom') @signals.import_tasks.connect def _import_tasks(sender, **kwargs): - import indico_vc_zoom.task + import indico_vc_zoom.task # noqa: F401 diff --git a/indico_vc_zoom/api/__init__.py b/indico_vc_zoom/api/__init__.py index bba1dbe..bd7f914 100644 --- a/indico_vc_zoom/api/__init__.py +++ b/indico_vc_zoom/api/__init__.py @@ -1,7 +1,4 @@ +from .client import ZoomIndicoClient, ZoomClient - -from .client import ZoomIndicoClient, APIException, RoomNotFoundAPIException, ZoomClient - - -__all__ = ['ZoomIndicoClient', 'APIException', 'RoomNotFoundAPIException', 'ZoomClient'] +__all__ = ['ZoomIndicoClient', 'ZoomClient'] diff --git a/indico_vc_zoom/api/client.py b/indico_vc_zoom/api/client.py index b9ad131..8dbc9e7 100644 --- a/indico_vc_zoom/api/client.py +++ b/indico_vc_zoom/api/client.py @@ -1,487 +1,199 @@ from __future__ import absolute_import, unicode_literals -from requests import Session -from requests.auth import HTTPBasicAuth -import contextlib -import json -import requests import time + import jwt +from requests import Session +from requests.exceptions import HTTPError +from pytz import utc -class ApiClient(object): - """Simple wrapper for REST API requests""" +def format_iso_dt(d): + """Convertdatetime objects to a UTC-based string. - def __init__(self, base_uri=None, timeout=15, **kwargs): - """Setup a new API Client - - :param base_uri: The base URI to the API - :param timeout: The timeout to use for requests - :param kwargs: Any other attributes. These will be added as - attributes to the ApiClient object. - """ - self.base_uri = base_uri - self.timeout = timeout - for k, v in kwargs.items(): - setattr(self, k, v) - - @property - def timeout(self): - """The timeout""" - return self._timeout - - @timeout.setter - def timeout(self, value): - """The default timeout""" - if value is not None: - try: - value = int(value) - except ValueError: - raise ValueError("timeout value must be an integer") - self._timeout = value - - @property - def base_uri(self): - """The base_uri""" - return self._base_uri - - @base_uri.setter - def base_uri(self, value): - """The default base_uri""" - if value and value.endswith("/"): - value = value[:-1] - self._base_uri = value - - def url_for(self, endpoint): - """Get the URL for the given endpoint - - :param endpoint: The endpoint - :return: The full URL for the endpoint - """ - if not endpoint.startswith("/"): - endpoint = "/{}".format(endpoint) - if endpoint.endswith("/"): - endpoint = endpoint[:-1] - return self.base_uri + endpoint - - def get_request(self, endpoint, params=None, headers=None): - """Helper function for GET requests - - :param endpoint: The endpoint - :param params: The URL parameters - :param headers: request headers - :return: The :class:``requests.Response`` object for this request - """ - if headers is None: - headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} - return requests.get( - self.url_for(endpoint), params=params, headers=headers, timeout=self.timeout - ) - - def post_request( - self, endpoint, params=None, data=None, headers=None, cookies=None - ): - """Helper function for POST requests - - :param endpoint: The endpoint - :param params: The URL parameters - :param data: The data (either as a dict or dumped JSON string) to - include with the POST - :param headers: request headers - :param cookies: request cookies - :return: The :class:``requests.Response`` object for this request - """ - if data and not is_str_type(data): - data = json.dumps(data) - if headers is None: - headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} - return requests.post( - self.url_for(endpoint), - params=params, - data=data, - headers=headers, - cookies=cookies, - timeout=self.timeout, - ) - - def patch_request( - self, endpoint, params=None, data=None, headers=None, cookies=None - ): - """Helper function for PATCH requests - - :param endpoint: The endpoint - :param params: The URL parameters - :param data: The data (either as a dict or dumped JSON string) to - include with the PATCH - :param headers: request headers - :param cookies: request cookies - :return: The :class:``requests.Response`` object for this request - """ - if data and not is_str_type(data): - data = json.dumps(data) - if headers is None: - headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} - return requests.patch( - self.url_for(endpoint), - params=params, - data=data, - headers=headers, - cookies=cookies, - timeout=self.timeout, - ) - - def delete_request( - self, endpoint, params=None, data=None, headers=None, cookies=None - ): - """Helper function for DELETE requests - - :param endpoint: The endpoint - :param params: The URL parameters - :param data: The data (either as a dict or dumped JSON string) to - include with the DELETE - :param headers: request headers - :param cookies: request cookies - :return: The :class:``requests.Response`` object for this request - """ - if data and not is_str_type(data): - data = json.dumps(data) - if headers is None: - headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} - return requests.delete( - self.url_for(endpoint), - params=params, - data=data, - headers=headers, - cookies=cookies, - timeout=self.timeout, - ) - - def put_request(self, endpoint, params=None, data=None, headers=None, cookies=None): - """Helper function for PUT requests - - :param endpoint: The endpoint - :param params: The URL paramaters - :param data: The data (either as a dict or dumped JSON string) to - include with the PUT - :param headers: request headers - :param cookies: request cookies - :return: The :class:``requests.Response`` object for this request - """ - if data and not is_str_type(data): - data = json.dumps(data) - if headers is None: - headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} - return requests.put( - self.url_for(endpoint), - params=params, - data=data, - headers=headers, - cookies=cookies, - timeout=self.timeout, - ) - - -@contextlib.contextmanager -def ignored(*exceptions): - """Simple context manager to ignore expected Exceptions - - :param \*exceptions: The exceptions to safely ignore - """ - try: - yield - except exceptions: - pass - - -def is_str_type(val): - """Check whether the input is of a string type. - - We use this method to ensure python 2-3 capatibility. - - :param val: The value to check wither it is a string - :return: In python2 it will return ``True`` if :attr:`val` is either an - instance of str or unicode. In python3 it will return ``True`` if - it is an instance of str - """ - with ignored(NameError): - return isinstance(val, basestring) - return isinstance(val, str) - - -def require_keys(d, keys, allow_none=True): - """Require that the object have the given keys - - :param d: The dict the check - :param keys: The keys to check :attr:`obj` for. This can either be a single - string, or an iterable of strings - - :param allow_none: Whether ``None`` values are allowed - :raises: - :ValueError: If any of the keys are missing from the obj - """ - if is_str_type(keys): - keys = [keys] - for k in keys: - if k not in d: - raise ValueError("'{}' must be set".format(k)) - if not allow_none and d[k] is None: - raise ValueError("'{}' cannot be None".format(k)) - return True - - -def date_to_str_gmt(d): - """Convert date and datetime objects to a string - - Note, this does not do any timezone conversion. - - :param d: The :class:`datetime.date` or :class:`datetime.datetime` to - convert to a string + :param d: The :class:`datetime.datetime` to convert to a string :returns: The string representation of the date """ - return d.strftime("%Y-%m-%dT%H:%M:%SZ") - -def date_to_str_local(d): - """Convert date and datetime objects to a string - - Note, this does not do any timezone conversion. - - :param d: The :class:`datetime.date` or :class:`datetime.datetime` to - convert to a string - :returns: The string representation of the date - """ - return d.strftime("%Y-%m-%dT%H:%M:%S") - - -def generate_jwt(key, secret): - header = {"alg": "HS256", "typ": "JWT"} - - payload = {"iss": key, "exp": int(time.time() + 3600)} - - token = jwt.encode(payload, secret, algorithm="HS256", headers=header) - return token.decode("utf-8") - + return d.astimezone(utc).strftime("%Y-%m-%dT%H:%M:%SZ") +def _handle_response(resp, expected_code=200, expects_json=True): + resp.raise_for_status() + if resp.status_code != expected_code: + raise HTTPError("Unexpected status code {}".format(resp.status_code), response=resp) + if expects_json: + return resp.json() + else: + return resp class APIException(Exception): pass -class RoomNotFoundAPIException(APIException): - pass +class BaseComponent(object): + def __init__(self, base_uri, config, timeout): + self.base_uri = base_uri + self.config = config + self.timeout = timeout + @property + def token(self): + header = {"alg": "HS256", "typ": "JWT"} + payload = {"iss": self.config['api_key'], "exp": int(time.time() + 3600)} + token = jwt.encode(payload, self.config['api_secret'], algorithm="HS256", headers=header) + return token.decode("utf-8") + @property + def session(self): + session = Session() + session.headers = { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer {}'.format(self.token) + } + return session - -class BaseComponent(ApiClient): - """A base component""" - - def __init__(self, base_uri=None, config=None, timeout=15, **kwargs): - """Setup a base component - - :param base_uri: The base URI to the API - :param config: The config details - :param timeout: The timeout to use for requests - :param kwargs: Any other attributes. These will be added as - attributes to the ApiClient object. - """ - super(BaseComponent, self).__init__( - base_uri=base_uri, timeout=timeout, config=config, **kwargs - ) - - def post_request( - self, endpoint, params=None, data=None, headers=None, cookies=None - ): - """Helper function for POST requests - - Since the Zoom.us API only uses POST requests and each post request - must include all of the config data, this method ensures that all - of that data is there - - :param endpoint: The endpoint - :param params: The URL parameters - :param data: The data (either as a dict or dumped JSON string) to - include with the POST - :param headers: request headers - :param cookies: request cookies - :return: The :class:``requests.Response`` object for this request - """ - params = params or {} - if headers is None: - headers = {"Content-Type": "application/json", "Authorization": "Bearer {}".format(self.config.get("token"))} - return super(BaseComponent, self).post_request( - endpoint, params=params, data=data, headers=headers, cookies=cookies - ) - class MeetingComponent(BaseComponent): - def list(self, **kwargs): - require_keys(kwargs, "user_id") - return self.get_request( - "/users/{}/meetings".format(kwargs.get("user_id")), params=kwargs + def list(self, user_id, **kwargs): + return self.get( + "{}/users/{}/meetings".format(self.base_uri, user_id), params=kwargs ) - def create(self, **kwargs): - require_keys(kwargs, "user_id") + def create(self, user_id, **kwargs): if kwargs.get("start_time"): - if kwargs.get("timezone"): - kwargs["start_time"] = date_to_str_local(kwargs["start_time"]) - else: - kwargs["start_time"] = date_to_str_gmt(kwargs["start_time"]) - return self.post_request( - "/users/{}/meetings".format(kwargs.get("user_id")), params=kwargs['user_id'], data={x: kwargs[x] for x in kwargs.keys() if x not in ['user_id']} + kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + return self.session.post( + "{}/users/{}/meetings".format(self.base_uri, user_id), + json=kwargs ) - def get(self, **kwargs): - require_keys(kwargs, "id") - return self.get_request("/meetings/{}".format(kwargs.get("id")), params=kwargs) + def get(self, meeting_id, **kwargs): + return self.session.get("{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs) - def update(self, **kwargs): - require_keys(kwargs, "id") + def update(self, meeting_id, **kwargs): if kwargs.get("start_time"): - if kwargs.get("timezone"): - kwargs["start_time"] = date_to_str_local(kwargs["start_time"]) - else: - kwargs["start_time"] = date_to_str_gmt(kwargs["start_time"]) - return self.patch_request( - "/meetings/{}".format(kwargs.get("id")), params=kwargs + kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + return self.session.patch( + "{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs ) - def delete(self, **kwargs): - require_keys(kwargs, "id") - return self.delete_request( - "/meetings/{}".format(kwargs.get("id")), params=kwargs + def delete(self, meeting_id, **kwargs): + return self.session.delete( + "{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs ) - def get_invitation(self, **kwargs): - require_keys(kwargs, "id") - return self.get_request("/meetings/{}/invitation".format(kwargs.get("id")), params=kwargs) + def get_invitation(self, meeting_id, **kwargs): + return self.session.get("{}/meetings/{}/invitation".format(self.base_uri, meeting_id), json=kwargs) class UserComponent(BaseComponent): + def me(self): + return self.get('me') + def list(self, **kwargs): - return self.get_request("/users", params=kwargs) + return self.session.get("{}/users".format(self.base_uri), params=kwargs) def create(self, **kwargs): - return self.post_request("/users", params=kwargs) + return self.session.post("{}/users".format(self.base_uri), params=kwargs) - def update(self, **kwargs): - require_keys(kwargs, "id") - return self.patch_request("/users/{}".format(kwargs.get("id")), params=kwargs) + def update(self, user_id, **kwargs): + return self.session.patch("{}/users/{}".format(self.base_uri, user_id), params=kwargs) - def delete(self, **kwargs): - require_keys(kwargs, "id") - return self.delete_request("/users/{}".format(kwargs.get("id")), params=kwargs) + def delete(self, user_id, **kwargs): + return self.session.delete("{}/users/{}".format(self.base_uri, user_id), params=kwargs) - def get(self, **kwargs): - require_keys(kwargs, "id") - return self.get_request("/users/{}".format(kwargs.get("id")), params=kwargs) + def add_assistant(self, user_id, **kwargs): + return self.session.post("{}/users/{}/assistants".format(self.base_uri, user_id), json=kwargs) + + def get_assistants(self, user_id, **kwargs): + return self.session.get("{}/users/{}/assistants".format(self.base_uri, user_id), params=kwargs) + + def get(self, user_id, **kwargs): + return self.session.get("{}/users/{}".format(self.base_uri, user_id), params=kwargs) +class ZoomClient(object): + """Zoom REST API Python Client.""" -class ZoomClient(ApiClient): - """Zoom.us REST API Python Client""" + _components = { + 'user': UserComponent, + 'meeting': MeetingComponent + } - """Base URL for Zoom API""" + def __init__(self, api_key, api_secret, timeout=15): + """Create a new Zoom client. - def __init__( - self, api_key, api_secret, data_type="json", timeout=15 - ): - """Create a new Zoom client - - :param api_key: The Zooom.us API key - :param api_secret: The Zoom.us API secret - :param data_type: The expected return data type. Either 'json' or 'xml' - :param timeout: The time out to use for API requests + :param api_key: the Zoom JWT API key + :param api_secret: the Zoom JWT API Secret + :param timeout: the time out to use for API requests """ - BASE_URI = "https://api.zoom.us/v2" - self.components = {"user": UserComponent, - "meeting": MeetingComponent} - - super(ZoomClient, self).__init__(base_uri=BASE_URI, timeout=timeout) # Setup the config details - self.config = { + config = { "api_key": api_key, - "api_secret": api_secret, - "data_type": data_type, - "token": generate_jwt(api_key, api_secret), + "api_secret": api_secret } # Instantiate the components - for key in self.components.keys(): - self.components[key] = self.components[key]( - base_uri=BASE_URI, config=self.config - ) - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - return - - def refresh_token(self): - self.config["token"] = ( - generate_jwt(self.config["api_key"], self.config["api_secret"]), - ) - - @property - def api_key(self): - """The Zoom.us api_key""" - return self.config.get("api_key") - - @api_key.setter - def api_key(self, value): - """Set the api_key""" - self.config["api_key"] = value - self.refresh_token() - - @property - def api_secret(self): - """The Zoom.us api_secret""" - return self.config.get("api_secret") - - @api_secret.setter - def api_secret(self, value): - """Set the api_secret""" - self.config["api_secret"] = value - self.refresh_token() + self.components = { + key: component(base_uri=BASE_URI, config=config, timeout=timeout) + for key, component in self._components.viewitems() + } @property def meeting(self): - """Get the meeting component""" + """Get the meeting component.""" return self.components.get("meeting") @property def user(self): - """Get the user component""" + """Get the user component.""" return self.components.get("user") + @property + def webinar(self): + """Get the user component.""" + return self.components.get("webinar") class ZoomIndicoClient(object): - def __init__(self, settings): - api_key=settings.get('api_key') - api_secret=settings.get('api_secret') - self.client=ZoomClient(api_key, api_secret) + def __init__(self): + self._refresh_client() - def create_meeting(self, **kwargs): - return json.loads(self.client.meeting.create(**kwargs).content) + def _refresh_client(self): + from indico_vc_zoom.plugin import ZoomPlugin + settings = ZoomPlugin.settings + self.client = ZoomClient( + settings.get('api_key'), + settings.get('api_secret') + ) - - def get_meeting(self, zoom_id): - return json.loads(self.client.meeting.get(id=zoom_id).content) + def create_meeting(self, user_id, **kwargs): + return _handle_response(self.client.meeting.create(user_id, **kwargs), 201) - - def get_meeting_invitation(self, zoom_id): - return json.loads(self.client.meeting.get_invitation(id=zoom_id).content) + def get_meeting(self, meeting_id): + return _handle_response(self.client.meeting.get(meeting_id)) - def delete_meeting(self, zoom_id): - self.client.meeting.delete(id=zoom_id) + def update_meeting(self, meeting_id, data): + return _handle_response(self.client.meeting.update(meeting_id, **data), 204, expects_json=False) - def check_user_meeting_time(self, userID, start_dt, end_dt): + def get_meeting_invitation(self, meeting_id): + return _handle_response(self.client.meeting.get_invitation(meeting_id)) + + def delete_meeting(self, meeting_id): + return _handle_response(self.client.meeting.delete(meeting_id), 204, expects_json=False) + + def check_user_meeting_time(self, user_id, start_dt, end_dt): pass + def get_user(self, user_id): + return _handle_response(self.client.user.get(user_id)) + def get_assistants_for_user(self, user_id): + return _handle_response(self.client.user.get_assistants(user_id)) + + def add_assistant_to_user(self, user_id, assistant_email): + return _handle_response(self.client.user.add_assistant(user_id, assistants=[{'email': assistant_email}]), 201) diff --git a/indico_vc_zoom/blueprint.py b/indico_vc_zoom/blueprint.py index e29b2d6..bcb7103 100644 --- a/indico_vc_zoom/blueprint.py +++ b/indico_vc_zoom/blueprint.py @@ -1,10 +1,8 @@ - - from __future__ import unicode_literals from indico.core.plugins import IndicoPluginBlueprint -from indico_vc_zoom.controllers import RHZoomRoomOwner +from indico_vc_zoom.controllers import RHRoomHost blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') @@ -12,5 +10,5 @@ blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') # Room management # using any(zoom) instead of defaults since the event vc room locator # includes the service and normalization skips values provided in 'defaults' -blueprint.add_url_rule('/event//manage/videoconference///room-owner', - 'set_room_owner', RHZoomRoomOwner, methods=('POST',)) +blueprint.add_url_rule('/event//manage/videoconference/zoom//room-host', + 'set_room_host', RHRoomHost, methods=('POST',)) diff --git a/indico_vc_zoom/controllers.py b/indico_vc_zoom/controllers.py index 5b46443..29e2dd2 100644 --- a/indico_vc_zoom/controllers.py +++ b/indico_vc_zoom/controllers.py @@ -10,7 +10,7 @@ from indico.modules.vc.exceptions import VCRoomError from indico.util.i18n import _ -class RHZoomRoomOwner(RHVCSystemEventBase): +class RHRoomOwner(RHVCSystemEventBase): def _process(self): result = {} self.vc_room.zoom_meeting.owned_by_user = session.user diff --git a/indico_vc_zoom/forms.py b/indico_vc_zoom/forms.py index 0b6e195..1f17f97 100644 --- a/indico_vc_zoom/forms.py +++ b/indico_vc_zoom/forms.py @@ -1,27 +1,26 @@ - - from __future__ import unicode_literals from flask import session from wtforms.fields.core import BooleanField -from wtforms.fields.simple import TextAreaField, HiddenField -from wtforms.validators import DataRequired, Length, Optional, Regexp, ValidationError +from wtforms.fields.simple import TextAreaField +from wtforms.validators import DataRequired, ValidationError from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase from indico.web.forms.base import generated_data -from indico.web.forms.fields import IndicoPasswordField, PrincipalField +from indico.web.forms.fields import IndicoRadioField, PrincipalField +from indico.web.forms.validators import HiddenUnless from indico.web.forms.widgets import SwitchWidget from indico_vc_zoom import _ -from indico_vc_zoom.util import iter_user_identities, retrieve_principal - - -PIN_VALIDATORS = [Optional(), Length(min=3, max=10), Regexp(r'^\d+$', message=_("The PIN must be a number"))] +from indico_vc_zoom.util import retrieve_principal class ZoomAdvancedFormMixin(object): # Advanced options (per event) - + + show_password = BooleanField(_('Show Password'), + widget=SwitchWidget(), + description=_("Show the Zoom Room Password on the event page")) show_autojoin = BooleanField(_('Show Auto-join URL'), widget=SwitchWidget(), description=_("Show the auto-join URL on the event page")) @@ -35,33 +34,46 @@ class VCRoomAttachForm(VCRoomAttachFormBase, ZoomAdvancedFormMixin): class VCRoomForm(VCRoomFormBase, ZoomAdvancedFormMixin): - """Contains all information concerning a Zoom booking""" + """Contains all information concerning a Zoom booking.""" - advanced_fields = {'show_autojoin', 'show_phone_numbers'} | VCRoomFormBase.advanced_fields + advanced_fields = {'show_password', 'show_autojoin', 'show_phone_numbers'} | VCRoomFormBase.advanced_fields skip_fields = advanced_fields | VCRoomFormBase.conditional_fields - description = TextAreaField(_('Description'), [DataRequired()], description=_('The description of the room')) - #owner_user = PrincipalField(_('Owner'), [DataRequired()], description=_('The owner of the room')) - #owner_user = HiddenField(default=session.user) - #moderation_pin = IndicoPasswordField(_('Moderation PIN'), PIN_VALIDATORS, toggle=True, - # description=_('Used to moderate the VC Room. Only digits allowed.')) - #room_pin = IndicoPasswordField(_('Room PIN'), PIN_VALIDATORS, toggle=True, - # description=_('Used to protect the access to the VC Room (leave blank for open ' - # 'access). Only digits allowed.')) - + description = TextAreaField(_('Description'), description=_('The description of the room')) + + owner_choice = IndicoRadioField(_("Owner of Room"), [DataRequired()], + choices=[('myself', _("Myself")), ('someone_else', _("Someone else"))]) + owner_user = PrincipalField(_("User"), + [HiddenUnless('owner_choice', 'someone_else'), DataRequired()]) + + mute_audio = BooleanField(_('Mute audio'), + widget=SwitchWidget(), + description=_('Participants will join the VC room muted by default ')) + + mute_host_video = BooleanField(_('Mute video (host)'), + widget=SwitchWidget(), + description=_('The host will join the VC room with video disabled')) + + mute_participant_video = BooleanField(_('Mute video (participants)'), + widget=SwitchWidget(), + description=_('Participants will join the VC room with video disabled')) + + waiting_room = BooleanField(_('Waiting room'), + widget=SwitchWidget(), + description=_('Participants may be kept in a waiting room by the host')) def __init__(self, *args, **kwargs): defaults = kwargs['obj'] if defaults.owner_user is None and defaults.owner is not None: - defaults.owner_user = retrieve_principal(defaults.owner) + owner = retrieve_principal(defaults.owner) + defaults.owner_choice = 'myself' if owner == session.user else 'someone_else' + defaults.owner_user = None if owner == session.user else owner super(VCRoomForm, self).__init__(*args, **kwargs) - #@generated_data - #def owner(self): - # return self.owner_user.data.default + @generated_data + def owner(self): + return session.user.as_principal if self.owner_choice.data == 'myself' else self.owner_user.data.as_principal def validate_owner_user(self, field): if not field.data: raise ValidationError(_("Unable to find this user in Indico.")) - #if not next(iter_user_identities(field.data), None): - # raise ValidationError(_("This user does not have a suitable account to use Zoom.")) diff --git a/indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py b/indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py deleted file mode 100644 index c865a47..0000000 --- a/indico_vc_zoom/migrations/20200312_1030_b79318836818_crea_tabella.py +++ /dev/null @@ -1,52 +0,0 @@ -"""crea tabella - -Revision ID: b79318836818 -Revises: -Create Date: 2020-03-12 10:30:09.256157 -""" - -import sqlalchemy as sa -from alembic import op - -from sqlalchemy.sql.ddl import CreateSchema, DropSchema - - -# revision identifiers, used by Alembic. -revision = 'b79318836818' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - op.execute(CreateSchema('plugin_vc_zoom')) - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('zoom_extensions', - sa.Column('vc_room_id', sa.Integer(), nullable=False), - sa.Column('url_zoom', sa.Text(), nullable=False), - sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=op.f('fk_zoom_extensions_vc_room_id_vc_rooms')), - sa.PrimaryKeyConstraint('vc_room_id', name=op.f('pk_zoom_extensions')), - schema='plugin_vc_zoom' - ) - op.create_index(op.f('ix_zoom_extensions_url_zoom'), 'zoom_extensions', ['url_zoom'], unique=False, schema='plugin_vc_zoom') - op.create_table('zoom_licenses', - sa.Column('id', sa.Integer(), nullable=False), - sa.Column('license_id', sa.Text(), nullable=False), - sa.Column('license_name', sa.Text(), nullable=False), - sa.PrimaryKeyConstraint('id', name=op.f('pk_zoom_licenses')), - schema='plugin_vc_zoom' - ) - op.create_index(op.f('ix_uq_zoom_licenses_license_id'), 'zoom_licenses', ['license_id'], unique=True, schema='plugin_vc_zoom') - op.create_index(op.f('ix_zoom_licenses_license_name'), 'zoom_licenses', ['license_name'], unique=False, schema='plugin_vc_zoom') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_zoom_licenses_license_name'), table_name='zoom_licenses', schema='plugin_vc_zoom') - op.drop_index(op.f('ix_uq_zoom_licenses_license_id'), table_name='zoom_licenses', schema='plugin_vc_zoom') - op.drop_table('zoom_licenses', schema='plugin_vc_zoom') - op.drop_index(op.f('ix_zoom_extensions_url_zoom'), table_name='zoom_extensions', schema='plugin_vc_zoom') - op.drop_table('zoom_extensions', schema='plugin_vc_zoom') - # ### end Alembic commands ### - op.execute(DropSchema('plugin_vc_zoom')) diff --git a/indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py b/indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py deleted file mode 100644 index 399511d..0000000 --- a/indico_vc_zoom/migrations/20200403_1957_d86e85a383c1_create_table.py +++ /dev/null @@ -1,66 +0,0 @@ -"""create table - -Revision ID: d86e85a383c1 -Revises: b79318836818 -Create Date: 2020-04-03 19:57:35.771416 -""" - -import sqlalchemy as sa -from alembic import op - - - -# revision identifiers, used by Alembic. -revision = 'd86e85a383c1' -down_revision = 'b79318836818' -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('zoom_meetings', - sa.Column('vc_room_id', sa.Integer(), nullable=False), - sa.Column('meeting', sa.BigInteger(), nullable=True), - sa.Column('url_zoom', sa.Text(), nullable=False), - sa.Column('owned_by_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['owned_by_id'], [u'users.users.id'], name=op.f('fk_zoom_meetings_owned_by_id_users')), - sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=op.f('fk_zoom_meetings_vc_room_id_vc_rooms')), - sa.PrimaryKeyConstraint('vc_room_id', name=op.f('pk_zoom_meetings')), - schema='plugin_vc_zoom' - ) - op.create_index(op.f('ix_zoom_meetings_meeting'), 'zoom_meetings', ['meeting'], unique=False, schema='plugin_vc_zoom') - op.create_index(op.f('ix_zoom_meetings_owned_by_id'), 'zoom_meetings', ['owned_by_id'], unique=False, schema='plugin_vc_zoom') - op.create_index(op.f('ix_zoom_meetings_url_zoom'), 'zoom_meetings', ['url_zoom'], unique=False, schema='plugin_vc_zoom') - op.drop_index('ix_zoom_extensions_url_zoom', table_name='zoom_extensions', schema='plugin_vc_zoom') - op.drop_table('zoom_extensions', schema='plugin_vc_zoom') - op.drop_index('ix_uq_zoom_licenses_license_id', table_name='zoom_licenses', schema='plugin_vc_zoom') - op.drop_index('ix_zoom_licenses_license_name', table_name='zoom_licenses', schema='plugin_vc_zoom') - op.drop_table('zoom_licenses', schema='plugin_vc_zoom') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.create_table('zoom_licenses', - sa.Column('id', sa.INTEGER(), server_default=sa.text(u"nextval('plugin_vc_zoom.zoom_licenses_id_seq'::regclass)"), autoincrement=True, nullable=False), - sa.Column('license_id', sa.TEXT(), autoincrement=False, nullable=False), - sa.Column('license_name', sa.TEXT(), autoincrement=False, nullable=False), - sa.PrimaryKeyConstraint('id', name=u'pk_zoom_licenses'), - schema='plugin_vc_zoom' - ) - op.create_index('ix_zoom_licenses_license_name', 'zoom_licenses', ['license_name'], unique=False, schema='plugin_vc_zoom') - op.create_index('ix_uq_zoom_licenses_license_id', 'zoom_licenses', ['license_id'], unique=True, schema='plugin_vc_zoom') - op.create_table('zoom_extensions', - sa.Column('vc_room_id', sa.INTEGER(), autoincrement=False, nullable=False), - sa.Column('url_zoom', sa.TEXT(), autoincrement=False, nullable=False), - sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=u'fk_zoom_extensions_vc_room_id_vc_rooms'), - sa.PrimaryKeyConstraint('vc_room_id', name=u'pk_zoom_extensions'), - schema='plugin_vc_zoom' - ) - op.create_index('ix_zoom_extensions_url_zoom', 'zoom_extensions', ['url_zoom'], unique=False, schema='plugin_vc_zoom') - op.drop_index(op.f('ix_zoom_meetings_url_zoom'), table_name='zoom_meetings', schema='plugin_vc_zoom') - op.drop_index(op.f('ix_zoom_meetings_owned_by_id'), table_name='zoom_meetings', schema='plugin_vc_zoom') - op.drop_index(op.f('ix_zoom_meetings_meeting'), table_name='zoom_meetings', schema='plugin_vc_zoom') - op.drop_table('zoom_meetings', schema='plugin_vc_zoom') - # ### end Alembic commands ### diff --git a/indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py b/indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py deleted file mode 100644 index 15afd8f..0000000 --- a/indico_vc_zoom/migrations/20200405_1539_d54585a383v1_create_table.py +++ /dev/null @@ -1,46 +0,0 @@ -"""create table - -Revision ID: d54585a383v1 -Revises: b79318836818 -Create Date: 2020-04-05 15:39:35.771416 -""" - -import sqlalchemy as sa -from alembic import op - -from sqlalchemy.sql.ddl import CreateSchema, DropSchema - -# revision identifiers, used by Alembic. -revision = 'd54585a383v1' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.execute(CreateSchema('plugin_vc_zoom')) - op.create_table('zoom_meetings', - sa.Column('vc_room_id', sa.Integer(), nullable=False), - sa.Column('meeting', sa.BigInteger(), nullable=True), - sa.Column('url_zoom', sa.Text(), nullable=False), - sa.Column('owned_by_id', sa.Integer(), nullable=False), - sa.ForeignKeyConstraint(['owned_by_id'], [u'users.users.id'], name=op.f('fk_zoom_meetings_owned_by_id_users')), - sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], name=op.f('fk_zoom_meetings_vc_room_id_vc_rooms')), - sa.PrimaryKeyConstraint('vc_room_id', name=op.f('pk_zoom_meetings')), - schema='plugin_vc_zoom' - ) - op.create_index(op.f('ix_zoom_meetings_meeting'), 'zoom_meetings', ['meeting'], unique=False, schema='plugin_vc_zoom') - op.create_index(op.f('ix_zoom_meetings_owned_by_id'), 'zoom_meetings', ['owned_by_id'], unique=False, schema='plugin_vc_zoom') - op.create_index(op.f('ix_zoom_meetings_url_zoom'), 'zoom_meetings', ['url_zoom'], unique=False, schema='plugin_vc_zoom') - # ### end Alembic commands ### - - -def downgrade(): - # ### commands auto generated by Alembic - please adjust! ### - op.drop_index(op.f('ix_zoom_meetings_url_zoom'), table_name='zoom_meetings', schema='plugin_vc_zoom') - op.drop_index(op.f('ix_zoom_meetings_owned_by_id'), table_name='zoom_meetings', schema='plugin_vc_zoom') - op.drop_index(op.f('ix_zoom_meetings_meeting'), table_name='zoom_meetings', schema='plugin_vc_zoom') - op.drop_table('zoom_meetings', schema='plugin_vc_zoom') - op.execute(DropSchema('plugin_vc_zoom')) - # ### end Alembic commands ### diff --git a/indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py b/indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py new file mode 100644 index 0000000..97108e0 --- /dev/null +++ b/indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py @@ -0,0 +1,39 @@ +"""Add Zoom plugin tables. + +Revision ID: f0f5f81fefca +Revises: +Create Date: 2020-06-10 11:07:58.821382 +""" + +import sqlalchemy as sa +from alembic import op + +from sqlalchemy.sql.ddl import CreateSchema, DropSchema + + +# revision identifiers, used by Alembic. +revision = 'f0f5f81fefca' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute(CreateSchema('plugin_vc_zoom')) + op.create_table( + 'zoom_meetings', + sa.Column('vc_room_id', sa.Integer(), primary_key=True, nullable=False), + sa.Column('meeting', sa.BigInteger(), nullable=True, index=True), + sa.Column('url_zoom', sa.String(), nullable=False), + sa.Column('owned_by_id', sa.Integer(), nullable=False, index=True), + sa.ForeignKeyConstraint(['owned_by_id'], [u'users.users.id'], + name=op.f('fk_zoom_meetings_owned_by_id_users')), + sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], + name=op.f('fk_zoom_meetings_vc_room_id_vc_rooms')), + schema='plugin_vc_zoom' + ) + + +def downgrade(): + op.drop_table('zoom_meetings', schema='plugin_vc_zoom') + op.execute(DropSchema('plugin_vc_zoom')) diff --git a/indico_vc_zoom/models/zoom_meetings.py b/indico_vc_zoom/models/zoom_meetings.py index 040d0e0..c8124c2 100644 --- a/indico_vc_zoom/models/zoom_meetings.py +++ b/indico_vc_zoom/models/zoom_meetings.py @@ -1,9 +1,5 @@ - - from __future__ import unicode_literals -import urllib - from sqlalchemy.event import listens_for from sqlalchemy.orm.attributes import flag_modified @@ -59,7 +55,6 @@ class ZoomMeeting(db.Model): @property def join_url(self): - from indico_vc_zoom.plugin import ZoomPlugin url = self.vc_room.data['url'] return url diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index 0b30f4e..358bc43 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -1,79 +1,118 @@ - - from __future__ import unicode_literals -from flask import session -from flask_pluginengine import current_plugin +import random +import string + +from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified +from werkzeug.exceptions import Forbidden, NotFound from wtforms.fields.core import BooleanField from wtforms.fields import IntegerField, TextAreaField from wtforms.fields.html5 import EmailField, URLField -from wtforms.fields.simple import StringField, BooleanField +from wtforms.fields.simple import StringField +from indico.web.forms.fields.simple import IndicoPasswordField from indico.web.forms.widgets import SwitchWidget from indico.web.flask.templating import get_template_module from wtforms.validators import DataRequired, NumberRange from indico.core.notifications import make_email, send_email -from indico.core.plugins import get_plugin_template_module from indico.core import signals -from indico.core.auth import multipass from indico.core.config import config from indico.core.plugins import IndicoPlugin, url_for_plugin from indico.modules.events.views import WPSimpleEventDisplay from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent -from indico.web.forms.fields import IndicoPasswordField from indico.web.forms.widgets import CKEditorWidget from indico.web.http_api.hooks.base import HTTPAPIHook -from indico.modules.vc.notifications import _send from indico_vc_zoom import _ -from indico_vc_zoom.api import ZoomIndicoClient, APIException, RoomNotFoundAPIException +from indico_vc_zoom.api import ZoomIndicoClient from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.http_api import DeleteVCRoomAPI from indico_vc_zoom.models.zoom_meetings import ZoomMeeting -from indico_vc_zoom.util import iter_extensions, iter_user_identities, retrieve_principal, update_room_from_obj +from indico_vc_zoom.util import find_enterprise_email, retrieve_principal + + +def _gen_random_password(): + return ''.join(random.sample(string.ascii_lowercase + string.ascii_uppercase + string.digits, 10)) + + +def _fetch_zoom_meeting(vc_room, client=None): + try: + client = client or ZoomIndicoClient() + return client.get_meeting(vc_room.data['zoom_id']) + except HTTPError as e: + if e.response.status_code == 404: + # Indico will automatically mark this room as deleted + raise VCRoomNotFoundError(_("This room has been deleted from Zoom")) + else: + ZoomPlugin.logger.exception('Error getting Zoom Room: %s', e.response.content) + raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) + + +def _update_zoom_meeting(zoom_id, changes): + client = ZoomIndicoClient() + try: + client.update_meeting(zoom_id, changes) + except HTTPError as e: + ZoomPlugin.logger.exception("Error updating meeting '%s': %s", zoom_id, e.response.content) + raise VCRoomError(_("Can't update meeting. Please contact support if the error persists.")) + + +def _get_schedule_args(obj): + return { + 'start_time': obj.start_dt, + 'duration': (obj.end_dt - obj.start_dt).total_seconds() / 60, + } class PluginSettingsForm(VCPluginSettingsFormBase): support_email = EmailField(_('Zoom email support')) - api_key = StringField(_('API KEY'), [DataRequired()]) + api_key = StringField(_('API Key'), [DataRequired()]) - api_secret = StringField(_('API SECRET'), [DataRequired()]) + api_secret = IndicoPasswordField(_('API Secret'), [DataRequired()], toggle=True) - auto_mute = BooleanField(_('Auto mute'), - widget=SwitchWidget(_('On'), _('Off')), - description=_('The Zoom clients will join the VC room muted by default ')) + email_domains = StringField(_('E-mail domains'), [DataRequired()], + description=_("Comma-separated list of e-mail domains which can use the Zoom API.")) - host_video = BooleanField(_('Host Video'), - widget=SwitchWidget(_('On'), _('Off')), - description=_('Start video when the host joins the meeting.')) + assistant_id = StringField(_('Assistant Zoom ID'), [DataRequired()], + description=_('Account to be used as owner of all rooms. It will get "assistant" ' + 'privileges on all accounts for which it books rooms')) - participant_video = BooleanField(_('Participant Video'), - widget=SwitchWidget(_('On'), _('Off')), - description=_('Start video when participants join the meeting. ')) + mute_audio = BooleanField(_('Mute audio'), + widget=SwitchWidget(), + description=_('Participants will join the VC room muted by default ')) + + mute_host_video = BooleanField(_('Mute video (host)'), + widget=SwitchWidget(), + description=_('The host will join the VC room with video disabled')) + + mute_participant_video = BooleanField(_('Mute video (participants)'), + widget=SwitchWidget(), + description=_('Participants will join the VC room with video disabled')) join_before_host = BooleanField(_('Join Before Host'), - widget=SwitchWidget(_('On'), _('Off')), - description=_('Allow participants to join the meeting before the host starts the meeting. Only used for scheduled or recurring meetings.')) + widget=SwitchWidget(), + description=_('Allow participants to join the meeting before the host starts the ' + 'meeting. Only used for scheduled or recurring meetings.')) + + waiting_room = BooleanField(_('Waiting room'), + widget=SwitchWidget(), + description=_('Participants may be kept in a waiting room by the host')) - #indico_room_prefix = IntegerField(_('Indico tenant prefix'), [NumberRange(min=0)], - # description=_('The tenant prefix for Indico rooms created on this server')) - #room_group_name = StringField(_("Public rooms' group name"), [DataRequired()], - # description=_('Group name for public videoconference rooms created by Indico')) num_days_old = IntegerField(_('VC room age threshold'), [NumberRange(min=1), DataRequired()], description=_('Number of days after an Indico event when a videoconference room is ' 'considered old')) max_rooms_warning = IntegerField(_('Max. num. VC rooms before warning'), [NumberRange(min=1), DataRequired()], description=_('Maximum number of rooms until a warning is sent to the managers')) zoom_phone_link = URLField(_('ZoomVoice phone number'), - description=_('Link to the list of ZoomVoice phone numbers')) - + description=_('Link to the list of ZoomVoice phone numbers')) + creation_email_footer = TextAreaField(_('Creation email footer'), widget=CKEditorWidget(), description=_('Footer to append to emails sent upon creation of a VC room')) @@ -81,8 +120,8 @@ class PluginSettingsForm(VCPluginSettingsFormBase): class ZoomPlugin(VCPluginMixin, IndicoPlugin): """Zoom - Videoconferencing with Zoom - """ + Zoom Plugin for Indico.""" + configurable = True settings_form = PluginSettingsForm vc_room_form = VCRoomForm @@ -101,17 +140,15 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def default_settings(self): return dict(VCPluginMixin.default_settings, **{ 'support_email': config.SUPPORT_EMAIL, + 'assistant_id': config.SUPPORT_EMAIL, 'api_key': '', 'api_secret': '', - #'indico_room_prefix': 10, - 'auto_mute':True, - 'host_video':False, - 'participant_video':True, - 'join_before_host':True, - #'room_group_name': 'Indico', - # we skip identity providers in the default list if they don't support get_identity. - # these providers (local accounts, oauth) are unlikely be the correct ones to integrate - # with the zoom infrastructure. + 'email_domains': '', + 'mute_host_video': True, + 'mute_audio': True, + 'mute_participant_video': True, + 'join_before_host': True, + 'waiting_room': False, 'num_days_old': 5, 'max_rooms_warning': 5000, 'zoom_phone_link': None, @@ -129,91 +166,178 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def _extend_indico_cli(self, sender, **kwargs): return cli - def update_data_association(self, event, vc_room, event_vc_room, data): - super(ZoomPlugin, self).update_data_association(event, vc_room, event_vc_room, data) + def update_data_association(self, event, vc_room, room_assoc, data): + # XXX: This feels slightly hacky. Maybe we should change the API on the core? + association_is_new = room_assoc.vc_room is None + old_link = room_assoc.link_object + super(ZoomPlugin, self).update_data_association(event, vc_room, room_assoc, data) - event_vc_room.data.update({key: data.pop(key) for key in [ + if vc_room.data: + # this is not a new room + if association_is_new: + # this means we are updating an existing meeting with a new vc_room-event association + _update_zoom_meeting(vc_room.data['zoom_id'], { + 'start_time': None, + 'duration': None, + 'type': 3 + }) + elif room_assoc.link_object != old_link: + # the booking should now be linked to something else + new_schedule_args = _get_schedule_args(room_assoc.link_object) + meeting = _fetch_zoom_meeting(vc_room) + current_schedule_args = {k: meeting[k] for k in {'start_time', 'duration'}} + + # check whether the start time / duration of the scheduled meeting differs + if new_schedule_args != current_schedule_args: + _update_zoom_meeting(vc_room.data['zoom_id'], new_schedule_args) + + room_assoc.data.update({key: data.pop(key) for key in [ + 'show_password', 'show_autojoin', 'show_phone_numbers' ]}) - flag_modified(event_vc_room, 'data') + flag_modified(room_assoc, 'data') def update_data_vc_room(self, vc_room, data): super(ZoomPlugin, self).update_data_vc_room(vc_room, data) - for key in ['description', 'owner', 'auto_mute', 'host_video', 'participant_video', 'join_before_host']: + for key in {'description', 'owner', 'mute_audio', 'mute_participant_video', 'mute_host_video', + 'join_before_host', 'waiting_room'}: if key in data: vc_room.data[key] = data.pop(key) flag_modified(vc_room, 'data') + def _check_indico_is_assistant(self, user_id): + client = ZoomIndicoClient() + assistant_id = self.settings.get('assistant_id') + + if user_id != assistant_id: + try: + assistants = {assist['email'] for assist in client.get_assistants_for_user(user_id)['assistants']} + except HTTPError as e: + if e.response.status_code == 404: + raise NotFound(_("No Zoom account found for this user")) + self.logger.exception('Error getting assistants for account %s: %s', user_id, e.response.content) + raise VCRoomError(_("Problem getting information about Zoom account")) + if assistant_id not in assistants: + client.add_assistant_to_user(user_id, assistant_id) + def create_room(self, vc_room, event): """Create a new Zoom room for an event, given a VC room. - In order to create the Zoom room, the function will try to do so with - all the available identities of the user based on the authenticators - defined in Zoom plugin's settings, in that order. + In order to create the Zoom room, the function will try to get + a valid e-mail address for the user in question, which can be + use with the Zoom API. - :param vc_room: VCRoom -- The VC room from which to create the Zoom - room - :param event: Event -- The event to the Zoom room will be attached + :param vc_room: the VC room from which to create the Zoom room + :param event: the event to the Zoom room will be attached """ - client = ZoomIndicoClient(self.settings) - #owner = retrieve_principal(vc_room.data['owner']) - owner= session.user - user_id=owner.email - topic=vc_room.name - time_zone=event.timezone - start=event.start_dt_local - end=event.end_dt - topic=vc_room.data['description'] - type_meeting=2 - host_video=self.settings.get('host_video') - participant_video=self.settings.get('participant_video') - join_before_host=self.settings.get('join_before_host') - mute_upon_entry=self.settings.get('auto_mute') + client = ZoomIndicoClient() + owner = retrieve_principal(vc_room.data['owner']) + owner_id = find_enterprise_email(owner) + # get the object that this booking is linked to + vc_room_assoc = vc_room.events[0] + link_obj = vc_room_assoc.link_object - meeting_obj = client.create_meeting(user_id=user_id, - type=type_meeting, - start_time=start, - topic=topic, - timezone=time_zone, - host_video=host_video, - participant_video=participant_video, - join_before_host=join_before_host, - mute_upon_entry=mute_upon_entry) + scheduling_args = _get_schedule_args(link_obj) if link_obj.start_dt else {} + + self._check_indico_is_assistant(owner_id) + + try: + settings = { + 'host_video': vc_room.data['mute_host_video'], + 'participant_video': not vc_room.data['mute_participant_video'], + 'join_before_host': self.settings.get('join_before_host'), + 'mute_upon_entry': vc_room.data['mute_audio'], + 'waiting_room': vc_room.data['waiting_room'] + } + meeting_obj = client.create_meeting(self.settings.get('assistant_id'), + type=2 if scheduling_args else 3, # scheduled vs. recurring meeting + topic=vc_room.name, + password=_gen_random_password(), + schedule_for=owner_id, + timezone=event.timezone, + settings=settings, + **scheduling_args) + except HTTPError as e: + self.logger.exception('Error creating Zoom Room: %s', e.response.content) + raise VCRoomError(_("Could not create the room in Zoom. Please contact support if the error persists")) - if not meeting_obj: - raise VCRoomNotFoundError(_("Could not find newly created room in Zoom")) vc_room.data.update({ 'zoom_id': unicode(meeting_obj['id']), 'url': meeting_obj['join_url'], - 'start_url':meeting_obj['start_url'] + 'start_url': meeting_obj['start_url'], + 'password': meeting_obj['password'] }) flag_modified(vc_room, 'data') vc_room.zoom_meeting = ZoomMeeting(vc_room_id=vc_room.id, meeting=meeting_obj['id'], - owned_by_user=owner, url_zoom=meeting_obj['join_url']) + owned_by_user=owner, url_zoom=meeting_obj['join_url']) self.notify_owner_start_url(vc_room) - def update_room(self, vc_room, event): - pass + client = ZoomIndicoClient() + zoom_meeting = _fetch_zoom_meeting(vc_room, client=client) + changes = {} + + owner = retrieve_principal(vc_room.data['owner']) + host_id = zoom_meeting['host_id'] + + try: + host_data = client.get_user(host_id) + except HTTPError as e: + self.logger.exception("Error retrieving user '%s': %s", host_id, e.response.content) + raise VCRoomError(_("Can't get information about user. Please contact support if the error persists.")) + + # owner changed + if host_data['email'] not in owner.all_emails: + email = find_enterprise_email(owner) + + if not email: + raise Forbidden(_("This user doesn't seem to have an associated Zoom account")) + + changes['schedule_for'] = email + self._check_indico_is_assistant(email) + vc_room.zoom_meeting.owned_by_user = owner + + if vc_room.name != zoom_meeting['topic']: + changes['topic'] = vc_room.name + + zoom_meeting_settings = zoom_meeting['settings'] + if vc_room.data['mute_audio'] != zoom_meeting_settings['mute_upon_entry']: + changes.setdefault('settings', {})['mute_upon_entry'] = vc_room.data['mute_audio'] + if vc_room.data['mute_participant_video'] == zoom_meeting_settings['participant_video']: + changes.setdefault('settings', {})['participant_video'] = not vc_room.data['mute_participant_video'] + if vc_room.data['mute_host_video'] == zoom_meeting_settings['host_video']: + changes.setdefault('settings', {})['host_video'] = not vc_room.data['mute_host_video'] + if vc_room.data['waiting_room'] != zoom_meeting_settings['waiting_room']: + changes.setdefault('settings', {})['waiting_room'] = vc_room.data['waiting_room'] + + if changes: + _update_zoom_meeting(vc_room.data['zoom_id'], changes) def refresh_room(self, vc_room, event): - pass + zoom_meeting = _fetch_zoom_meeting(vc_room) + vc_room.name = zoom_meeting['topic'] + vc_room.data.update({ + 'url': zoom_meeting['start_url'], + 'zoom_id': zoom_meeting['id'] + }) + flag_modified(vc_room, 'data') def delete_room(self, vc_room, event): - client = ZoomIndicoClient(self.settings) + client = ZoomIndicoClient() zoom_id = vc_room.data['zoom_id'] - client.delete_meeting(zoom_id) - - - def get_meeting(self, vc_room): - client = ZoomIndicoClient(self.settings) - return client.get_meeting(vc_room.data['zoom_id']) + try: + client.delete_meeting(zoom_id) + except HTTPError as e: + # if there's a 404, there is no problem, since the room is supposed to be gone anyway + if not e.response.status_code == 404: + self.logger.exception('Error getting Zoom Room: %s', e.response.content) + raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) def get_blueprints(self): return blueprint @@ -221,18 +345,24 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def get_vc_room_form_defaults(self, event): defaults = super(ZoomPlugin, self).get_vc_room_form_defaults(event) defaults.update({ + 'mute_audio': self.settings.get('mute_audio'), + 'mute_host_video': self.settings.get('mute_host_video'), + 'mute_participant_video': self.settings.get('mute_participant_video'), + 'waiting_room': self.settings.get('waiting_room'), 'show_autojoin': True, 'show_phone_numbers': True, - 'owner_user': session.user + 'show_password': True, + 'owner_choice': 'myself', + 'owner_user': None }) - return defaults def get_vc_room_attach_form_defaults(self, event): defaults = super(ZoomPlugin, self).get_vc_room_attach_form_defaults(event) defaults.update({ 'show_autojoin': True, - 'show_phone_numbers': True + 'show_phone_numbers': True, + 'show_password': True }) return defaults @@ -248,13 +378,18 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def get_notification_cc_list(self, action, vc_room, event): return {vc_room.zoom_meeting.owned_by_user.email} - def notify_owner_start_url(self, vc_room): user = vc_room.zoom_meeting.owned_by_user to_list = {user.email} - template_module = get_template_module('vc_zoom:emails/notify_start_url.html', plugin=ZoomPlugin.instance, vc_room=vc_room, event=None, - vc_room_event=None, user=user) + template_module = get_template_module( + 'vc_zoom:emails/notify_start_url.html', + plugin=ZoomPlugin.instance, + vc_room=vc_room, + event=None, + vc_room_event=None, + user=user + ) email = make_email(to_list, template=template_module, html=True) - send_email(email, None, 'Zoom') + send_email(email, None, 'Zoom') diff --git a/indico_vc_zoom/task.py b/indico_vc_zoom/task.py index 402099a..78b4572 100644 --- a/indico_vc_zoom/task.py +++ b/indico_vc_zoom/task.py @@ -10,13 +10,12 @@ from indico.core.celery import celery from indico.core.db import db from indico.core.plugins import get_plugin_template_module from indico.modules.events import Event +from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomStatus from indico.modules.vc.notifications import _send from indico.util.date_time import now_utc from indico.util.struct.iterables import committing_iterator -from indico_vc_zoom.api import APIException, RoomNotFoundAPIException - def find_old_zoom_rooms(max_room_event_age): """Finds all Zoom rooms that are: @@ -48,7 +47,7 @@ def zoom_cleanup(dry_run=False): max_room_event_age = ZoomPlugin.settings.get('num_days_old') ZoomPlugin.logger.info('Deleting Zoom rooms that are not used or linked to events all older than %d days', - max_room_event_age) + max_room_event_age) candidate_rooms = find_old_zoom_rooms(max_room_event_age) ZoomPlugin.logger.info('%d rooms found', len(candidate_rooms)) @@ -63,8 +62,8 @@ def zoom_cleanup(dry_run=False): ZoomPlugin.logger.info('Room %s deleted from Zoom server', vc_room) notify_owner(ZoomPlugin.instance, vc_room) vc_room.status = VCRoomStatus.deleted - except RoomNotFoundAPIException: + except VCRoomNotFoundError: ZoomPlugin.logger.warning('Room %s had been already deleted from the Zoom server', vc_room) vc_room.status = VCRoomStatus.deleted - except APIException: + except VCRoomError: ZoomPlugin.logger.exception('Impossible to delete Zoom room %s', vc_room) diff --git a/indico_vc_zoom/templates/info_box.html b/indico_vc_zoom/templates/info_box.html index 4dbf5d3..24a0fe2 100644 --- a/indico_vc_zoom/templates/info_box.html +++ b/indico_vc_zoom/templates/info_box.html @@ -4,8 +4,6 @@
    {% trans %}Name{% endtrans %}
    {{ vc_room.name }}
    -
    {% trans %}Meeting Topic{% endtrans %}
    -
    {{ vc_room.data.description }}
    {% if vc_room.zoom_meeting %}
    {% trans %}Meeting ID{% endtrans %}
    {{ vc_room.zoom_meeting.meeting }}
    @@ -14,6 +12,10 @@
    {% trans %}Owner{% endtrans %}
    {{ owner.full_name }}
    {% endif %} + {% if vc_room.data.password %} +
    {% trans %}Password{% endtrans %}
    +
    {{ vc_room.data.password }}
    + {% endif %} {% if event_vc_room.data.show_pin and vc_room.data.room_pin %}
    {% trans %}Room PIN{% endtrans %}
    {{ vc_room.data.room_pin }}
    diff --git a/indico_vc_zoom/templates/manage_event_info_box.html b/indico_vc_zoom/templates/manage_event_info_box.html index 5068f4c..bd720c9 100644 --- a/indico_vc_zoom/templates/manage_event_info_box.html +++ b/indico_vc_zoom/templates/manage_event_info_box.html @@ -3,8 +3,6 @@ {% set owner = vc_room.zoom_meeting.owned_by_user %} {% set phone_link = settings.get('zoom_phone_link') %}
    -
    {% trans %}Meeting Topic{% endtrans %}
    -
    {{ vc_room.data.description }}
    {% trans %}Meeting ID{% endtrans %}
    {{ vc_room.zoom_meeting.meeting }}
    {% trans %}Owner{% endtrans %}
    @@ -28,20 +26,8 @@ {% trans %}Session{% endtrans %}: {{ obj.full_title }} {% endif %} - {% if vc_room.data.room_pin %} -
    {% trans %}Room PIN{% endtrans %}
    -
    - {{ password('vc-room-pin-%s'|format(event_vc_room.id), value=vc_room.data.room_pin, toggle=True, - readonly=true) }} -
    - {% endif %} - {% if vc_room.data.moderation_pin %} -
    {% trans %}Moderation PIN{% endtrans %}
    -
    - {{ password('vc-moderation-pin-%s'|format(event_vc_room.id), value=vc_room.data.moderation_pin, - toggle=True, readonly=true) }} -
    - {% endif %} +
    {% trans %}Password{% endtrans %}
    +
    {{ vc_room.data.password }}
    {% trans %}Zoom URL{% endtrans %}
    {{ clipboard_input(vc_room.zoom_meeting.join_url, name="vc-room-url") }} diff --git a/indico_vc_zoom/util.py b/indico_vc_zoom/util.py index a527786..5f2081d 100644 --- a/indico_vc_zoom/util.py +++ b/indico_vc_zoom/util.py @@ -1,87 +1,34 @@ - - from __future__ import unicode_literals -import re -from flask_multipass import IdentityRetrievalFailed - -from indico.core.auth import multipass from indico.core.db import db -from indico.modules.auth import Identity -from indico.modules.users import User +from indico.modules.users.models.emails import UserEmail +from indico.modules.users.models.users import User -authenticators_re = re.compile(r'\s*,\s*') +def find_enterprise_email(user): + """Find a user's first e-mail address which can be used by the Zoom API. - -def iter_user_identities(user): - """Iterates over all existing user identities that can be used with Zoom""" - from indico_vc_zoom.plugin import ZoomPlugin - providers = authenticators_re.split(ZoomPlugin.settings.get('authenticators')) - done = set() - for provider in providers: - for _, identifier in user.iter_identifiers(check_providers=True, providers={provider}): - if identifier in done: - continue - done.add(identifier) - yield identifier - - -def get_user_from_identifier(settings, identifier): - """Get an actual User object from an identifier""" - providers = list(auth.strip() for auth in settings.get('authenticators').split(',')) - identities = Identity.find_all(Identity.provider.in_(providers), Identity.identifier == identifier) - if identities: - return sorted(identities, key=lambda x: providers.index(x.provider))[0].user - for provider in providers: - try: - identity_info = multipass.get_identity(provider, identifier) - except IdentityRetrievalFailed: - continue - if identity_info is None: - continue - if not identity_info.provider.settings.get('trusted_email'): - continue - emails = {email.lower() for email in identity_info.data.getlist('email') if email} - if not emails: - continue - user = User.find_first(~User.is_deleted, User.all_emails.in_(list(emails))) - if user: - return user - - -def iter_extensions(prefix, event_id): - """Return extension (prefix + event_id) with an optional suffix which is - incremented step by step in case of collision + :param user: the `User` in question + :return: the e-mail address if it exists, otherwise `None` """ - extension = '{prefix}{event_id}'.format(prefix=prefix, event_id=event_id) - yield extension - suffix = 1 - while True: - yield '{extension}{suffix}'.format(extension=extension, suffix=suffix) - suffix += 1 - - -def update_room_from_obj(settings, vc_room, room_obj): - """Updates a VCRoom DB object using a SOAP room object returned by the API""" - vc_room.name = room_obj.name - if room_obj.ownerName != vc_room.data['owner_identity']: - owner = get_user_from_identifier(settings, room_obj.ownerName) or User.get_system_user() - vc_room.zoom_meeting.owned_by_user = owner - - vc_room.data.update({ - 'description': room_obj.description, - 'zoom_id': unicode(room_obj.roomID), - 'url': room_obj.RoomMode.roomURL, - 'owner_identity': room_obj.ownerName, - 'room_pin': room_obj.RoomMode.roomPIN if room_obj.RoomMode.hasPIN else "", - 'moderation_pin': room_obj.RoomMode.moderatorPIN if room_obj.RoomMode.hasModeratorPIN else "", - }) - vc_room.zoom_meeting.extension = int(room_obj.extension) + from indico_vc_zoom.plugin import ZoomPlugin + providers = [auth.strip() for auth in ZoomPlugin.settings.get('email_domains').split(',')] + result = UserEmail.query.filter( + UserEmail.user == user, + ~User.is_blocked, + ~User.is_deleted, + db.or_(UserEmail.email.ilike("%%@{}".format(provider)) for provider in providers) + ).join(User).first() + return result.email if result else None def retrieve_principal(principal): + """Retrieve a user using a "principal tuple". + + :param principal: a tuple in the form `('Avatar'|'User', )`. + :return: the corresponding `User`. + """ from indico.modules.users import User type_, id_ = principal if type_ in {'Avatar', 'User'}: diff --git a/setup.py b/setup.py index 7472b25..d09a0a6 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ setup( include_package_data=True, install_requires=[ 'indico>=2', - 'requests', 'PyJWT' ], classifiers=[ From cf059df6fd06e2555c1a74e05201434bf97f1761 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 19 Jun 2020 13:47:02 +0200 Subject: [PATCH 05/94] VC/Zoom: Bump version --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d09a0a6..62f4b20 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from setuptools import find_packages, setup setup( name='indico-plugin-vc-zoom', - version='0.2-dev', + version='0.3-dev', description='Zoom video-conferencing plugin for Indico', url='', license='MIT', From c060e4ed50b749e44a2993e2bc5114e2eb8ec276 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 1 Jul 2020 16:40:15 +0200 Subject: [PATCH 06/94] VC/Zoom: Remove plugin tasks, not needed --- indico_vc_zoom/__init__.py | 6 ---- indico_vc_zoom/task.py | 69 -------------------------------------- 2 files changed, 75 deletions(-) delete mode 100644 indico_vc_zoom/task.py diff --git a/indico_vc_zoom/__init__.py b/indico_vc_zoom/__init__.py index 6b83e11..823742f 100644 --- a/indico_vc_zoom/__init__.py +++ b/indico_vc_zoom/__init__.py @@ -1,12 +1,6 @@ from __future__ import unicode_literals -from indico.core import signals from indico.util.i18n import make_bound_gettext _ = make_bound_gettext('vc_zoom') - - -@signals.import_tasks.connect -def _import_tasks(sender, **kwargs): - import indico_vc_zoom.task # noqa: F401 diff --git a/indico_vc_zoom/task.py b/indico_vc_zoom/task.py deleted file mode 100644 index 78b4572..0000000 --- a/indico_vc_zoom/task.py +++ /dev/null @@ -1,69 +0,0 @@ - - -from __future__ import unicode_literals - -from datetime import timedelta - -from celery.schedules import crontab - -from indico.core.celery import celery -from indico.core.db import db -from indico.core.plugins import get_plugin_template_module -from indico.modules.events import Event -from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError -from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomStatus -from indico.modules.vc.notifications import _send -from indico.util.date_time import now_utc -from indico.util.struct.iterables import committing_iterator - - -def find_old_zoom_rooms(max_room_event_age): - """Finds all Zoom rooms that are: - - linked to no events - - linked only to events whose start date precedes today - max_room_event_age days - """ - recently_used = (db.session.query(VCRoom.id) - .filter(VCRoom.type == 'zoom', - Event.end_dt > (now_utc() - timedelta(days=max_room_event_age))) - .join(VCRoom.events) - .join(VCRoomEventAssociation.event) - .group_by(VCRoom.id)) - - # non-deleted rooms with no recent associations - return VCRoom.find_all(VCRoom.status != VCRoomStatus.deleted, ~VCRoom.id.in_(recently_used)) - - -def notify_owner(plugin, vc_room): - """Notifies about the deletion of a Zoom room from the Zoom server.""" - user = vc_room.zoom_meeting.owned_by_user - tpl = get_plugin_template_module('emails/remote_deleted.html', plugin=plugin, vc_room=vc_room, event=None, - vc_room_event=None, user=user) - _send('delete', user, plugin, None, vc_room, tpl) - - -@celery.periodic_task(run_every=crontab(minute='0', hour='3', day_of_week='monday'), plugin='vc_zoom') -def zoom_cleanup(dry_run=False): - from indico_vc_zoom.plugin import ZoomPlugin - max_room_event_age = ZoomPlugin.settings.get('num_days_old') - - ZoomPlugin.logger.info('Deleting Zoom rooms that are not used or linked to events all older than %d days', - max_room_event_age) - candidate_rooms = find_old_zoom_rooms(max_room_event_age) - ZoomPlugin.logger.info('%d rooms found', len(candidate_rooms)) - - if dry_run: - for vc_room in candidate_rooms: - ZoomPlugin.logger.info('Would delete Zoom room %s from server', vc_room) - return - - for vc_room in committing_iterator(candidate_rooms, n=20): - try: - ZoomPlugin.instance.delete_room(vc_room, None) - ZoomPlugin.logger.info('Room %s deleted from Zoom server', vc_room) - notify_owner(ZoomPlugin.instance, vc_room) - vc_room.status = VCRoomStatus.deleted - except VCRoomNotFoundError: - ZoomPlugin.logger.warning('Room %s had been already deleted from the Zoom server', vc_room) - vc_room.status = VCRoomStatus.deleted - except VCRoomError: - ZoomPlugin.logger.exception('Impossible to delete Zoom room %s', vc_room) From 66ef537486d7818cc8cdc8e44f5de8367431b756 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 1 Jul 2020 16:40:45 +0200 Subject: [PATCH 07/94] VC/Zoom: Add warning when times change --- indico_vc_zoom/plugin.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index 358bc43..ad660e4 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import random import string +from flask import flash from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified from werkzeug.exceptions import Forbidden, NotFound @@ -131,6 +132,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def init(self): super(ZoomPlugin, self).init() self.connect(signals.plugin.cli, self._extend_indico_cli) + self.connect(signals.event.times_changed, self._times_changed) self.inject_bundle('main.js', WPSimpleEventDisplay) self.inject_bundle('main.js', WPVCEventPage) self.inject_bundle('main.js', WPVCManageEvent) @@ -393,3 +395,26 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): email = make_email(to_list, template=template_module, html=True) send_email(email, None, 'Zoom') + + def _times_changed(self, sender, obj, **kwargs): + from indico.modules.events.models.events import Event + from indico.modules.events.contributions.models.contributions import Contribution + from indico.modules.events.sessions.models.blocks import SessionBlock + + if not hasattr(obj, 'vc_room_associations'): + return + + if any(assoc.vc_room.type == 'zoom' and len(assoc.vc_room.events) == 1 for assoc in obj.vc_room_associations): + if sender == Event: + message = _("There are one or more scheduled Zoom meetings associated with this event which were not " + "automatically updated.") + elif sender == Contribution: + message = _("There are one or more scheduled Zoom meetings associated with contribution '{}' which " + " were not automatically updated.").format(obj.title) + elif sender == SessionBlock: + message = _("There are one or more scheduled Zoom meetings associated with this session block which " + "were not automatically updated.") + else: + return + + flash(message, 'warning') From 4ace8576cb5c6bcb787238a7bf552fb57437bab9 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 3 Jul 2020 10:59:22 +0200 Subject: [PATCH 08/94] VC/Zoom: Add pytest config --- conftest.py | 1 + pytest.ini | 7 +++++++ 2 files changed, 8 insertions(+) create mode 100644 conftest.py create mode 100644 pytest.ini diff --git a/conftest.py b/conftest.py new file mode 100644 index 0000000..7c568e8 --- /dev/null +++ b/conftest.py @@ -0,0 +1 @@ +pytest_plugins = 'indico' diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..cba3f73 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +; more verbose summary (include skip/fail/error/warning), coverage +addopts = -rsfEw --cov . --cov-report html --no-cov-on-fail +; only check for tests in suffixed files +python_files = *_test.py +; we need the livesync plugin to be loaded +indico_plugins = vc_zoom From 39e066a163c62cc48e3a66c5dcd80ff9869b376f Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 3 Jul 2020 11:00:10 +0200 Subject: [PATCH 09/94] VC/Zoom: Ignore url_map file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index fc6d642..4a45354 100755 --- a/.gitignore +++ b/.gitignore @@ -81,4 +81,5 @@ target/ .ipynb_checkpoints -webpack-build-config.json \ No newline at end of file +webpack-build-config.json +url_map.json From 80214c2a57d743478d475a920866adb0e350c9ae Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 6 Jul 2020 10:20:10 +0200 Subject: [PATCH 10/94] VC/Zoom: Use JSONB store instead of a separate table --- indico_vc_zoom/cli.py | 5 +- indico_vc_zoom/controllers.py | 2 +- indico_vc_zoom/forms.py | 6 +- ...107_f0f5f81fefca_add_zoom_plugin_tables.py | 39 ----------- indico_vc_zoom/models/__init__.py | 0 indico_vc_zoom/models/zoom_meetings.py | 70 ------------------- indico_vc_zoom/plugin.py | 32 +++++---- indico_vc_zoom/templates/buttons.html | 2 +- indico_vc_zoom/templates/emails/created.html | 4 +- indico_vc_zoom/templates/info_box.html | 12 ++-- .../templates/manage_event_info_box.html | 14 ++-- indico_vc_zoom/util.py | 14 ---- tests/task_test.py | 2 - 13 files changed, 37 insertions(+), 165 deletions(-) delete mode 100644 indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py delete mode 100644 indico_vc_zoom/models/__init__.py delete mode 100644 indico_vc_zoom/models/zoom_meetings.py diff --git a/indico_vc_zoom/cli.py b/indico_vc_zoom/cli.py index c5f57c2..b414b30 100644 --- a/indico_vc_zoom/cli.py +++ b/indico_vc_zoom/cli.py @@ -20,14 +20,13 @@ def rooms(status=None): """Lists all Zoom rooms""" room_query = VCRoom.find(type='zoom') - table_data = [['ID', 'Name', 'Status', 'Zoom ID', 'Meeting']] + table_data = [['ID', 'Name', 'Status', 'Zoom ID']] if status: room_query = room_query.filter(VCRoom.status == VCRoomStatus.get(status)) for room in room_query: - table_data.append([unicode(room.id), room.name, room.status.name, - unicode(room.data['zoom_id']), unicode(room.zoom_meeting.meeting)]) + table_data.append([unicode(room.id), room.name, room.status.name, unicode(room.data['zoom_id'])]) table = AsciiTable(table_data) for col in (0, 3, 4): diff --git a/indico_vc_zoom/controllers.py b/indico_vc_zoom/controllers.py index 29e2dd2..959e71b 100644 --- a/indico_vc_zoom/controllers.py +++ b/indico_vc_zoom/controllers.py @@ -13,7 +13,7 @@ from indico.util.i18n import _ class RHRoomOwner(RHVCSystemEventBase): def _process(self): result = {} - self.vc_room.zoom_meeting.owned_by_user = session.user + self.vc_room.data['owner'] = session.user.identifier try: self.plugin.update_room(self.vc_room, self.event) except VCRoomError as err: diff --git a/indico_vc_zoom/forms.py b/indico_vc_zoom/forms.py index 1f17f97..3a3fa62 100644 --- a/indico_vc_zoom/forms.py +++ b/indico_vc_zoom/forms.py @@ -6,13 +6,13 @@ from wtforms.fields.simple import TextAreaField from wtforms.validators import DataRequired, ValidationError from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase +from indico.util.user import principal_from_identifier from indico.web.forms.base import generated_data from indico.web.forms.fields import IndicoRadioField, PrincipalField from indico.web.forms.validators import HiddenUnless from indico.web.forms.widgets import SwitchWidget from indico_vc_zoom import _ -from indico_vc_zoom.util import retrieve_principal class ZoomAdvancedFormMixin(object): @@ -65,14 +65,14 @@ class VCRoomForm(VCRoomFormBase, ZoomAdvancedFormMixin): def __init__(self, *args, **kwargs): defaults = kwargs['obj'] if defaults.owner_user is None and defaults.owner is not None: - owner = retrieve_principal(defaults.owner) + owner = principal_from_identifier(defaults.owner) defaults.owner_choice = 'myself' if owner == session.user else 'someone_else' defaults.owner_user = None if owner == session.user else owner super(VCRoomForm, self).__init__(*args, **kwargs) @generated_data def owner(self): - return session.user.as_principal if self.owner_choice.data == 'myself' else self.owner_user.data.as_principal + return session.user.identifier if self.owner_choice.data == 'myself' else self.owner_user.data.identifier def validate_owner_user(self, field): if not field.data: diff --git a/indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py b/indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py deleted file mode 100644 index 97108e0..0000000 --- a/indico_vc_zoom/migrations/20200610_1107_f0f5f81fefca_add_zoom_plugin_tables.py +++ /dev/null @@ -1,39 +0,0 @@ -"""Add Zoom plugin tables. - -Revision ID: f0f5f81fefca -Revises: -Create Date: 2020-06-10 11:07:58.821382 -""" - -import sqlalchemy as sa -from alembic import op - -from sqlalchemy.sql.ddl import CreateSchema, DropSchema - - -# revision identifiers, used by Alembic. -revision = 'f0f5f81fefca' -down_revision = None -branch_labels = None -depends_on = None - - -def upgrade(): - op.execute(CreateSchema('plugin_vc_zoom')) - op.create_table( - 'zoom_meetings', - sa.Column('vc_room_id', sa.Integer(), primary_key=True, nullable=False), - sa.Column('meeting', sa.BigInteger(), nullable=True, index=True), - sa.Column('url_zoom', sa.String(), nullable=False), - sa.Column('owned_by_id', sa.Integer(), nullable=False, index=True), - sa.ForeignKeyConstraint(['owned_by_id'], [u'users.users.id'], - name=op.f('fk_zoom_meetings_owned_by_id_users')), - sa.ForeignKeyConstraint(['vc_room_id'], [u'events.vc_rooms.id'], - name=op.f('fk_zoom_meetings_vc_room_id_vc_rooms')), - schema='plugin_vc_zoom' - ) - - -def downgrade(): - op.drop_table('zoom_meetings', schema='plugin_vc_zoom') - op.execute(DropSchema('plugin_vc_zoom')) diff --git a/indico_vc_zoom/models/__init__.py b/indico_vc_zoom/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/indico_vc_zoom/models/zoom_meetings.py b/indico_vc_zoom/models/zoom_meetings.py deleted file mode 100644 index c8124c2..0000000 --- a/indico_vc_zoom/models/zoom_meetings.py +++ /dev/null @@ -1,70 +0,0 @@ -from __future__ import unicode_literals - -from sqlalchemy.event import listens_for -from sqlalchemy.orm.attributes import flag_modified - -from indico.core.db.sqlalchemy import db -from indico.util.string import return_ascii - - -class ZoomMeeting(db.Model): - __tablename__ = 'zoom_meetings' - __table_args__ = {'schema': 'plugin_vc_zoom'} - - #: ID of the videoconference room - vc_room_id = db.Column( - db.Integer, - db.ForeignKey('events.vc_rooms.id'), - primary_key=True - ) - meeting = db.Column( - db.BigInteger, - index=True - ) - url_zoom = db.Column( - db.Text, - index=True, - nullable=False - ) - owned_by_id = db.Column( - db.Integer, - db.ForeignKey('users.users.id'), - index=True, - nullable=False - ) - vc_room = db.relationship( - 'VCRoom', - lazy=False, - backref=db.backref( - 'zoom_meeting', - cascade='all, delete-orphan', - uselist=False, - lazy=False - ) - ) - - #: The user who owns the Zoom room - owned_by_user = db.relationship( - 'User', - lazy=True, - backref=db.backref( - 'vc_rooms_zoom', - lazy='dynamic' - ) - ) - - @property - def join_url(self): - url = self.vc_room.data['url'] - return url - - @return_ascii - def __repr__(self): - return ''.format(self.vc_room, self.meeting, self.owned_by_user) - - -@listens_for(ZoomMeeting.owned_by_user, 'set') -def _owned_by_user_set(target, user, *unused): - if target.vc_room and user.as_principal != tuple(target.vc_room.data['owner']): - target.vc_room.data['owner'] = user.as_principal - flag_modified(target.vc_room, 'data') diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index ad660e4..d31b676 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -24,7 +24,9 @@ from indico.core.plugins import IndicoPlugin, url_for_plugin from indico.modules.events.views import WPSimpleEventDisplay from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError +from indico.modules.vc.models.vc_rooms import VCRoom from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent +from indico.util.user import principal_from_identifier from indico.web.forms.widgets import CKEditorWidget from indico.web.http_api.hooks.base import HTTPAPIHook @@ -34,8 +36,7 @@ from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.http_api import DeleteVCRoomAPI -from indico_vc_zoom.models.zoom_meetings import ZoomMeeting -from indico_vc_zoom.util import find_enterprise_email, retrieve_principal +from indico_vc_zoom.util import find_enterprise_email def _gen_random_password(): @@ -237,7 +238,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): :param event: the event to the Zoom room will be attached """ client = ZoomIndicoClient() - owner = retrieve_principal(vc_room.data['owner']) + owner = principal_from_identifier(vc_room.data['owner']) owner_id = find_enterprise_email(owner) # get the object that this booking is linked to @@ -272,12 +273,11 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'zoom_id': unicode(meeting_obj['id']), 'url': meeting_obj['join_url'], 'start_url': meeting_obj['start_url'], - 'password': meeting_obj['password'] + 'password': meeting_obj['password'], + 'owner': owner.identifier }) flag_modified(vc_room, 'data') - vc_room.zoom_meeting = ZoomMeeting(vc_room_id=vc_room.id, meeting=meeting_obj['id'], - owned_by_user=owner, url_zoom=meeting_obj['join_url']) self.notify_owner_start_url(vc_room) def update_room(self, vc_room, event): @@ -285,7 +285,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): zoom_meeting = _fetch_zoom_meeting(vc_room, client=client) changes = {} - owner = retrieve_principal(vc_room.data['owner']) + owner = principal_from_identifier(vc_room.data['owner']) host_id = zoom_meeting['host_id'] try: @@ -303,7 +303,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): changes['schedule_for'] = email self._check_indico_is_assistant(email) - vc_room.zoom_meeting.owned_by_user = owner if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name @@ -369,19 +368,24 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): return defaults def can_manage_vc_room(self, user, room): - return user == room.zoom_meeting.owned_by_user or super(ZoomPlugin, self).can_manage_vc_room(user, room) + return ( + user == principal_from_identifier(room.data['owner']) or + super(ZoomPlugin, self).can_manage_vc_room(user, room) + ) def _merge_users(self, target, source, **kwargs): super(ZoomPlugin, self)._merge_users(target, source, **kwargs) - for ext in ZoomMeeting.find(owned_by_user=source): - ext.owned_by_user = target - flag_modified(ext.vc_room, 'data') + for room in VCRoom.query.filter( + VCRoom.type == self.service_name, VCRoom.data.contains({'owner': source.identifier}) + ): + room.data['owner'] = target.id + flag_modified(room, 'data') def get_notification_cc_list(self, action, vc_room, event): - return {vc_room.zoom_meeting.owned_by_user.email} + return {principal_from_identifier(vc_room.data['owner']).email} def notify_owner_start_url(self, vc_room): - user = vc_room.zoom_meeting.owned_by_user + user = principal_from_identifier(vc_room.data['owner']) to_list = {user.email} template_module = get_template_module( diff --git a/indico_vc_zoom/templates/buttons.html b/indico_vc_zoom/templates/buttons.html index 3f0c1d9..2814528 100644 --- a/indico_vc_zoom/templates/buttons.html +++ b/indico_vc_zoom/templates/buttons.html @@ -1,6 +1,6 @@ {% macro render_join_button(vc_room, extra_classes="") %} + href="{{ vc_room.data.url }}" target="_blank"> {% trans %}Join{% endtrans %} {% endmacro %} diff --git a/indico_vc_zoom/templates/emails/created.html b/indico_vc_zoom/templates/emails/created.html index 6d4118d..b6473e6 100644 --- a/indico_vc_zoom/templates/emails/created.html +++ b/indico_vc_zoom/templates/emails/created.html @@ -3,9 +3,9 @@ {% block plugin_specific_info %}
  • Zoom URL: - {{ vc_room.zoom_meeting.join_url }} + {{ vc_room.data.url }}
  • - + {% endblock %} {% block custom_footer %} diff --git a/indico_vc_zoom/templates/info_box.html b/indico_vc_zoom/templates/info_box.html index 24a0fe2..72c7f7d 100644 --- a/indico_vc_zoom/templates/info_box.html +++ b/indico_vc_zoom/templates/info_box.html @@ -1,16 +1,14 @@ {% from '_clipboard_input.html' import clipboard_input %} -{% set owner = vc_room.zoom_meeting.owned_by_user %} +{% set owner = vc_room.data.owner %} {% set phone_link = settings.get('zoom_phone_link') %}
    {% trans %}Name{% endtrans %}
    {{ vc_room.name }}
    - {% if vc_room.zoom_meeting %} -
    {% trans %}Meeting ID{% endtrans %}
    -
    {{ vc_room.zoom_meeting.meeting }}
    - {% endif %} +
    {% trans %}Zoom Meeting ID{% endtrans %}
    +
    {{ vc_room.data.zoom_id }}
    {% if owner %}
    {% trans %}Owner{% endtrans %}
    -
    {{ owner.full_name }}
    +
    {{ (owner|decodeprincipal).full_name }}
    {% endif %} {% if vc_room.data.password %}
    {% trans %}Password{% endtrans %}
    @@ -23,7 +21,7 @@ {% if event_vc_room.data.show_autojoin %}
    {% trans %}Zoom URL{% endtrans %}
    - {{ clipboard_input(vc_room.zoom_meeting.join_url, name="vc-room-url-%s"|format(event_vc_room.id)) }} + {{ clipboard_input(vc_room.data.url, name="vc-room-url-%s"|format(event_vc_room.id)) }}
    {% endif %} {% if event_vc_room.data.show_phone_numbers and phone_link %} diff --git a/indico_vc_zoom/templates/manage_event_info_box.html b/indico_vc_zoom/templates/manage_event_info_box.html index bd720c9..42a5466 100644 --- a/indico_vc_zoom/templates/manage_event_info_box.html +++ b/indico_vc_zoom/templates/manage_event_info_box.html @@ -1,17 +1,13 @@ {% from '_password.html' import password %} {% from '_clipboard_input.html' import clipboard_input %} -{% set owner = vc_room.zoom_meeting.owned_by_user %} +{% set owner = vc_room.data.owner %} {% set phone_link = settings.get('zoom_phone_link') %}
    -
    {% trans %}Meeting ID{% endtrans %}
    -
    {{ vc_room.zoom_meeting.meeting }}
    +
    {% trans %}Zoom Meeting ID{% endtrans %}
    +
    {{ vc_room.data.zoom_id }}
    {% trans %}Owner{% endtrans %}
    - {% if owner %} - {{ owner.full_name }} - {% else %} - {{ vc_room.data.owner_account }} (deleted) - {% endif %} + {{ (owner|decodeprincipal).full_name }}
    {% trans %}Linked to{% endtrans %}
    @@ -30,7 +26,7 @@
    {{ vc_room.data.password }}
    {% trans %}Zoom URL{% endtrans %}
    - {{ clipboard_input(vc_room.zoom_meeting.join_url, name="vc-room-url") }} + {{ clipboard_input(vc_room.data.url, name="vc-room-url") }}
    {% trans %}Created on{% endtrans %}
    {{ vc_room.created_dt | format_datetime(timezone=event.tzinfo) }}
    diff --git a/indico_vc_zoom/util.py b/indico_vc_zoom/util.py index 5f2081d..cfb4ba5 100644 --- a/indico_vc_zoom/util.py +++ b/indico_vc_zoom/util.py @@ -21,17 +21,3 @@ def find_enterprise_email(user): db.or_(UserEmail.email.ilike("%%@{}".format(provider)) for provider in providers) ).join(User).first() return result.email if result else None - - -def retrieve_principal(principal): - """Retrieve a user using a "principal tuple". - - :param principal: a tuple in the form `('Avatar'|'User', )`. - :return: the corresponding `User`. - """ - from indico.modules.users import User - type_, id_ = principal - if type_ in {'Avatar', 'User'}: - return User.get(int(id_)) - else: - raise ValueError('Unexpected type: {}'.format(type_)) diff --git a/tests/task_test.py b/tests/task_test.py index 43714fa..06f10b4 100644 --- a/tests/task_test.py +++ b/tests/task_test.py @@ -6,8 +6,6 @@ from pytz import utc from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomStatus -from indico_vc_zoom.models.zoom_meetings import ZoomMeeting - @pytest.fixture def create_dummy_room(db, dummy_user): From ead1b7ce136e9116288698a2ee3364c80456fd2f Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 13 Jul 2020 09:47:03 +0200 Subject: [PATCH 11/94] VC/Zoom: Add proper password visibility option --- indico_vc_zoom/forms.py | 20 +++++++-------- indico_vc_zoom/plugin.py | 23 ++++++----------- indico_vc_zoom/templates/buttons.html | 25 +++++++++++++++---- indico_vc_zoom/templates/event_buttons.html | 2 +- indico_vc_zoom/templates/info_box.html | 11 +++----- .../templates/management_buttons.html | 2 +- .../templates/vc_room_timetable_buttons.html | 2 +- 7 files changed, 43 insertions(+), 42 deletions(-) diff --git a/indico_vc_zoom/forms.py b/indico_vc_zoom/forms.py index 3a3fa62..2e3934e 100644 --- a/indico_vc_zoom/forms.py +++ b/indico_vc_zoom/forms.py @@ -18,15 +18,13 @@ from indico_vc_zoom import _ class ZoomAdvancedFormMixin(object): # Advanced options (per event) - show_password = BooleanField(_('Show Password'), - widget=SwitchWidget(), - description=_("Show the Zoom Room Password on the event page")) - show_autojoin = BooleanField(_('Show Auto-join URL'), - widget=SwitchWidget(), - description=_("Show the auto-join URL on the event page")) - show_phone_numbers = BooleanField(_('Show Phone Access numbers'), - widget=SwitchWidget(), - description=_("Show a link to the list of phone access numbers")) + password_visibility = IndicoRadioField(_("Password visibility"), + description=_("Who should be able to know this meeting's password"), + orientation='horizontal', + choices=[ + ('everyone', _('Everyone')), + ('logged_in', _('Logged-in users')), + ('no_one', _("No one"))]) class VCRoomAttachForm(VCRoomAttachFormBase, ZoomAdvancedFormMixin): @@ -36,13 +34,15 @@ class VCRoomAttachForm(VCRoomAttachFormBase, ZoomAdvancedFormMixin): class VCRoomForm(VCRoomFormBase, ZoomAdvancedFormMixin): """Contains all information concerning a Zoom booking.""" - advanced_fields = {'show_password', 'show_autojoin', 'show_phone_numbers'} | VCRoomFormBase.advanced_fields + advanced_fields = {'mute_audio', 'mute_host_video', 'mute_participant_video'} | VCRoomFormBase.advanced_fields + skip_fields = advanced_fields | VCRoomFormBase.conditional_fields description = TextAreaField(_('Description'), description=_('The description of the room')) owner_choice = IndicoRadioField(_("Owner of Room"), [DataRequired()], choices=[('myself', _("Myself")), ('someone_else', _("Someone else"))]) + owner_user = PrincipalField(_("User"), [HiddenUnless('owner_choice', 'someone_else'), DataRequired()]) diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index d31b676..5ebda0b 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -194,12 +194,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if new_schedule_args != current_schedule_args: _update_zoom_meeting(vc_room.data['zoom_id'], new_schedule_args) - room_assoc.data.update({key: data.pop(key) for key in [ - 'show_password', - 'show_autojoin', - 'show_phone_numbers' - ]}) - + room_assoc.data['password_visibility'] = data.pop('password_visibility') flag_modified(room_assoc, 'data') def update_data_vc_room(self, vc_room, data): @@ -272,6 +267,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room.data.update({ 'zoom_id': unicode(meeting_obj['id']), 'url': meeting_obj['join_url'], + 'public_url': meeting_obj['join_url'].split('?')[0], 'start_url': meeting_obj['start_url'], 'password': meeting_obj['password'], 'owner': owner.identifier @@ -324,7 +320,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): zoom_meeting = _fetch_zoom_meeting(vc_room) vc_room.name = zoom_meeting['topic'] vc_room.data.update({ - 'url': zoom_meeting['start_url'], + 'url': zoom_meeting['join_url'], + 'public_url': zoom_meeting['join_url'].split('?')[0], 'zoom_id': zoom_meeting['id'] }) flag_modified(vc_room, 'data') @@ -350,21 +347,15 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'mute_host_video': self.settings.get('mute_host_video'), 'mute_participant_video': self.settings.get('mute_participant_video'), 'waiting_room': self.settings.get('waiting_room'), - 'show_autojoin': True, - 'show_phone_numbers': True, - 'show_password': True, 'owner_choice': 'myself', - 'owner_user': None + 'owner_user': None, + 'password_visibility': 'logged_in' }) return defaults def get_vc_room_attach_form_defaults(self, event): defaults = super(ZoomPlugin, self).get_vc_room_attach_form_defaults(event) - defaults.update({ - 'show_autojoin': True, - 'show_phone_numbers': True, - 'show_password': True - }) + defaults['password_visibility'] = 'logged_in' return defaults def can_manage_vc_room(self, user, room): diff --git a/indico_vc_zoom/templates/buttons.html b/indico_vc_zoom/templates/buttons.html index 2814528..c5cef9a 100644 --- a/indico_vc_zoom/templates/buttons.html +++ b/indico_vc_zoom/templates/buttons.html @@ -1,6 +1,21 @@ -{% macro render_join_button(vc_room, extra_classes="") %} - - {% trans %}Join{% endtrans %} - +{% macro render_join_button(vc_room, event_vc_room, extra_classes="", is_manager=false) %} + {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or + (session.user and event_vc_room.data.password_visibility == 'logged_in') %} + + {% trans %}Join{% endtrans %} + + {% elif event_vc_room.data.password_visibility == 'no_one' %} + + {% trans %}Join{% endtrans %} + + {% else %} + + {% trans %}Please log in{% endtrans %} + + {% endif %} {% endmacro %} diff --git a/indico_vc_zoom/templates/event_buttons.html b/indico_vc_zoom/templates/event_buttons.html index c30f4cc..fd9fcf1 100644 --- a/indico_vc_zoom/templates/event_buttons.html +++ b/indico_vc_zoom/templates/event_buttons.html @@ -2,5 +2,5 @@ {% from 'vc_zoom:buttons.html' import render_join_button %} {% block buttons %} - {{ render_join_button(vc_room, "i-button-small event-service-right-button join-button") }} + {{ render_join_button(vc_room, event_vc_room, "i-button-small event-service-right-button join-button") }} {% endblock %} diff --git a/indico_vc_zoom/templates/info_box.html b/indico_vc_zoom/templates/info_box.html index 72c7f7d..56df0d3 100644 --- a/indico_vc_zoom/templates/info_box.html +++ b/indico_vc_zoom/templates/info_box.html @@ -2,22 +2,17 @@ {% set owner = vc_room.data.owner %} {% set phone_link = settings.get('zoom_phone_link') %}
    -
    {% trans %}Name{% endtrans %}
    -
    {{ vc_room.name }}
    -
    {% trans %}Zoom Meeting ID{% endtrans %}
    +
    {% trans %}Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    {% if owner %}
    {% trans %}Owner{% endtrans %}
    {{ (owner|decodeprincipal).full_name }}
    {% endif %} - {% if vc_room.data.password %} + {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or + (session.user and event_vc_room.data.password_visibility == 'logged_in') %}
    {% trans %}Password{% endtrans %}
    {{ vc_room.data.password }}
    {% endif %} - {% if event_vc_room.data.show_pin and vc_room.data.room_pin %} -
    {% trans %}Room PIN{% endtrans %}
    -
    {{ vc_room.data.room_pin }}
    - {% endif %} {% if event_vc_room.data.show_autojoin %}
    {% trans %}Zoom URL{% endtrans %}
    diff --git a/indico_vc_zoom/templates/management_buttons.html b/indico_vc_zoom/templates/management_buttons.html index 93b9f5c..ac8a8b6 100644 --- a/indico_vc_zoom/templates/management_buttons.html +++ b/indico_vc_zoom/templates/management_buttons.html @@ -2,5 +2,5 @@ {% from 'vc_zoom:buttons.html' import render_join_button %} {% block buttons %} - {{ render_join_button(vc_room, extra_classes="icon-play") }} + {{ render_join_button(vc_room, event_vc_room, extra_classes="icon-play", is_manager=true) }} {% endblock %} diff --git a/indico_vc_zoom/templates/vc_room_timetable_buttons.html b/indico_vc_zoom/templates/vc_room_timetable_buttons.html index 8b70551..c1db6a8 100644 --- a/indico_vc_zoom/templates/vc_room_timetable_buttons.html +++ b/indico_vc_zoom/templates/vc_room_timetable_buttons.html @@ -3,5 +3,5 @@ {% set vc_room = event_vc_room.vc_room %} {% block buttons %} - {{ render_join_button(vc_room, "i-button-small event-service-right-button join-button") }} + {{ render_join_button(vc_room, event_vc_room, "i-button-small event-service-right-button join-button") }} {% endblock %} From 5e655558550032b59c964fd6c12a25468cff12ab Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 13 Jul 2020 10:20:42 +0200 Subject: [PATCH 12/94] VC/Zoom: Make host URL e-mail notification optional --- indico_vc_zoom/plugin.py | 13 +++++++++-- indico_vc_zoom/templates/emails/created.html | 4 ++++ .../templates/emails/notify_start_url.html | 22 ++++++++++--------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index 5ebda0b..7b2efb5 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -118,6 +118,11 @@ class PluginSettingsForm(VCPluginSettingsFormBase): creation_email_footer = TextAreaField(_('Creation email footer'), widget=CKEditorWidget(), description=_('Footer to append to emails sent upon creation of a VC room')) + send_host_url = BooleanField(_('Send host URL'), + widget=SwitchWidget(), + description=_('Whether to send an e-mail with the Host URL to the meeting host upon ' + 'creation of a meeting')) + class ZoomPlugin(VCPluginMixin, IndicoPlugin): """Zoom @@ -155,7 +160,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'num_days_old': 5, 'max_rooms_warning': 5000, 'zoom_phone_link': None, - 'creation_email_footer': None + 'creation_email_footer': None, + 'send_host_url': False }) @property @@ -274,7 +280,10 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): }) flag_modified(vc_room, 'data') - self.notify_owner_start_url(vc_room) + + # e-mail Host URL to meeting host + if self.settings.get('send_host_url'): + self.notify_owner_start_url(vc_room) def update_room(self, vc_room, event): client = ZoomIndicoClient() diff --git a/indico_vc_zoom/templates/emails/created.html b/indico_vc_zoom/templates/emails/created.html index b6473e6..d8a8d36 100644 --- a/indico_vc_zoom/templates/emails/created.html +++ b/indico_vc_zoom/templates/emails/created.html @@ -1,6 +1,10 @@ {% extends 'vc/emails/created.html' %} {% block plugin_specific_info %} +
  • + Host: + {{ (vc_room.data.owner|decodeprincipal).full_name }} +
  • Zoom URL: {{ vc_room.data.url }} diff --git a/indico_vc_zoom/templates/emails/notify_start_url.html b/indico_vc_zoom/templates/emails/notify_start_url.html index ee45670..269ddc7 100644 --- a/indico_vc_zoom/templates/emails/notify_start_url.html +++ b/indico_vc_zoom/templates/emails/notify_start_url.html @@ -1,18 +1,20 @@ {% extends 'emails/base.html' %} {% block subject -%} - [DON'T SHARE] Zoom Host URL - {{ vc_room.name }} + Zoom Host URL - {{ vc_room.name }} {%- endblock %} {% block header -%} +

    + ATTENTION: + You should not share this URL with anyone, since it will allow them to become meeting hosts! +

    + -
  • - HOST Zoom URL: - {{ vc_room.data.start_url }} -
  • - -Please don't share this link. - -{% block custom_footer %}{% endblock %} - + {% block custom_footer %}{% endblock %} {%- endblock %} From 6525135348ebad6c6f86880e90b0b2560f5f73a9 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 13 Jul 2020 16:31:35 +0200 Subject: [PATCH 13/94] VC/Zoom: Better notifications, rename owner -> host --- indico_vc_zoom/controllers.py | 6 +- indico_vc_zoom/forms.py | 42 ++++++------ indico_vc_zoom/notifications.py | 37 +++++++++++ indico_vc_zoom/plugin.py | 64 +++++++------------ indico_vc_zoom/templates/emails/created.html | 2 +- .../templates/emails/notify_new_host.html | 25 ++++++++ .../templates/emails/notify_start_url.html | 2 +- indico_vc_zoom/templates/info_box.html | 8 +-- .../templates/manage_event_info_box.html | 6 +- 9 files changed, 119 insertions(+), 73 deletions(-) create mode 100644 indico_vc_zoom/notifications.py create mode 100644 indico_vc_zoom/templates/emails/notify_new_host.html diff --git a/indico_vc_zoom/controllers.py b/indico_vc_zoom/controllers.py index 959e71b..0a0c8c1 100644 --- a/indico_vc_zoom/controllers.py +++ b/indico_vc_zoom/controllers.py @@ -10,10 +10,10 @@ from indico.modules.vc.exceptions import VCRoomError from indico.util.i18n import _ -class RHRoomOwner(RHVCSystemEventBase): +class RHRoomHost(RHVCSystemEventBase): def _process(self): result = {} - self.vc_room.data['owner'] = session.user.identifier + self.vc_room.data['host'] = session.user.identifier try: self.plugin.update_room(self.vc_room, self.event) except VCRoomError as err: @@ -21,6 +21,6 @@ class RHRoomOwner(RHVCSystemEventBase): result['success'] = False db.session.rollback() else: - flash(_("You are now the owner of the room '{room.name}'".format(room=self.vc_room)), 'success') + flash(_("You are now the host of room '{room.name}'".format(room=self.vc_room)), 'success') result['success'] = True return jsonify(result) diff --git a/indico_vc_zoom/forms.py b/indico_vc_zoom/forms.py index 2e3934e..1c19a0c 100644 --- a/indico_vc_zoom/forms.py +++ b/indico_vc_zoom/forms.py @@ -15,9 +15,7 @@ from indico.web.forms.widgets import SwitchWidget from indico_vc_zoom import _ -class ZoomAdvancedFormMixin(object): - # Advanced options (per event) - +class VCRoomAttachForm(VCRoomAttachFormBase): password_visibility = IndicoRadioField(_("Password visibility"), description=_("Who should be able to know this meeting's password"), orientation='horizontal', @@ -27,24 +25,26 @@ class ZoomAdvancedFormMixin(object): ('no_one', _("No one"))]) -class VCRoomAttachForm(VCRoomAttachFormBase, ZoomAdvancedFormMixin): - pass - - -class VCRoomForm(VCRoomFormBase, ZoomAdvancedFormMixin): +class VCRoomForm(VCRoomFormBase): """Contains all information concerning a Zoom booking.""" advanced_fields = {'mute_audio', 'mute_host_video', 'mute_participant_video'} | VCRoomFormBase.advanced_fields skip_fields = advanced_fields | VCRoomFormBase.conditional_fields - description = TextAreaField(_('Description'), description=_('The description of the room')) + host_choice = IndicoRadioField(_("Meeting Host"), [DataRequired()], + choices=[('myself', _("Myself")), ('someone_else', _("Someone else"))]) - owner_choice = IndicoRadioField(_("Owner of Room"), [DataRequired()], - choices=[('myself', _("Myself")), ('someone_else', _("Someone else"))]) + host_user = PrincipalField(_("User"), + [HiddenUnless('host_choice', 'someone_else'), DataRequired()]) - owner_user = PrincipalField(_("User"), - [HiddenUnless('owner_choice', 'someone_else'), DataRequired()]) + password_visibility = IndicoRadioField(_("Password visibility"), + description=_("Who should be able to know this meeting's password"), + orientation='horizontal', + choices=[ + ('everyone', _('Everyone')), + ('logged_in', _('Logged-in users')), + ('no_one', _("No one"))]) mute_audio = BooleanField(_('Mute audio'), widget=SwitchWidget(), @@ -62,18 +62,20 @@ class VCRoomForm(VCRoomFormBase, ZoomAdvancedFormMixin): widget=SwitchWidget(), description=_('Participants may be kept in a waiting room by the host')) + description = TextAreaField(_('Description'), description=_('The description of the room')) + def __init__(self, *args, **kwargs): defaults = kwargs['obj'] - if defaults.owner_user is None and defaults.owner is not None: - owner = principal_from_identifier(defaults.owner) - defaults.owner_choice = 'myself' if owner == session.user else 'someone_else' - defaults.owner_user = None if owner == session.user else owner + if defaults.host_user is None and defaults.host is not None: + host = principal_from_identifier(defaults.host) + defaults.host_choice = 'myself' if host == session.user else 'someone_else' + defaults.host_user = None if host == session.user else host super(VCRoomForm, self).__init__(*args, **kwargs) @generated_data - def owner(self): - return session.user.identifier if self.owner_choice.data == 'myself' else self.owner_user.data.identifier + def host(self): + return session.user.identifier if self.host_choice.data == 'myself' else self.host_user.data.identifier - def validate_owner_user(self, field): + def validate_host_user(self, field): if not field.data: raise ValidationError(_("Unable to find this user in Indico.")) diff --git a/indico_vc_zoom/notifications.py b/indico_vc_zoom/notifications.py new file mode 100644 index 0000000..f04885e --- /dev/null +++ b/indico_vc_zoom/notifications.py @@ -0,0 +1,37 @@ +from __future__ import unicode_literals + +from indico.web.flask.templating import get_template_module +from indico.core.notifications import make_email, send_email +from indico.util.user import principal_from_identifier + + +def notify_host_start_url(vc_room): + from indico_vc_zoom.plugin import ZoomPlugin + + user = principal_from_identifier(vc_room.data['host']) + to_list = {user.email} + + template_module = get_template_module( + 'vc_zoom:emails/notify_start_url.html', + plugin=ZoomPlugin.instance, + vc_room=vc_room, + user=user + ) + + email = make_email(to_list, template=template_module, html=True) + send_email(email, None, 'Zoom') + + +def notify_new_host(actor, vc_room): + from indico_vc_zoom.plugin import ZoomPlugin + + template_module = get_template_module( + 'vc_zoom:emails/notify_new_host.html', + plugin=ZoomPlugin.instance, + vc_room=vc_room, + actor=actor + ) + + new_host = principal_from_identifier(vc_room.data['host']) + email = make_email({new_host.email}, cc_list={actor.email}, template=template_module, html=True) + send_email(email, None, 'Zoom') diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index 7b2efb5..6af14be 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import random import string -from flask import flash +from flask import flash, session from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified from werkzeug.exceptions import Forbidden, NotFound @@ -11,13 +11,8 @@ from wtforms.fields.core import BooleanField from wtforms.fields import IntegerField, TextAreaField from wtforms.fields.html5 import EmailField, URLField from wtforms.fields.simple import StringField - -from indico.web.forms.fields.simple import IndicoPasswordField -from indico.web.forms.widgets import SwitchWidget - -from indico.web.flask.templating import get_template_module from wtforms.validators import DataRequired, NumberRange -from indico.core.notifications import make_email, send_email + from indico.core import signals from indico.core.config import config from indico.core.plugins import IndicoPlugin, url_for_plugin @@ -27,7 +22,8 @@ from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError from indico.modules.vc.models.vc_rooms import VCRoom from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent from indico.util.user import principal_from_identifier -from indico.web.forms.widgets import CKEditorWidget +from indico.web.forms.fields.simple import IndicoPasswordField +from indico.web.forms.widgets import CKEditorWidget, SwitchWidget from indico.web.http_api.hooks.base import HTTPAPIHook from indico_vc_zoom import _ @@ -36,6 +32,7 @@ from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.http_api import DeleteVCRoomAPI +from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url from indico_vc_zoom.util import find_enterprise_email @@ -206,7 +203,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def update_data_vc_room(self, vc_room, data): super(ZoomPlugin, self).update_data_vc_room(vc_room, data) - for key in {'description', 'owner', 'mute_audio', 'mute_participant_video', 'mute_host_video', + for key in {'description', 'host', 'mute_audio', 'mute_participant_video', 'mute_host_video', 'join_before_host', 'waiting_room'}: if key in data: vc_room.data[key] = data.pop(key) @@ -239,8 +236,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): :param event: the event to the Zoom room will be attached """ client = ZoomIndicoClient() - owner = principal_from_identifier(vc_room.data['owner']) - owner_id = find_enterprise_email(owner) + host = principal_from_identifier(vc_room.data['host']) + host_id = find_enterprise_email(host) # get the object that this booking is linked to vc_room_assoc = vc_room.events[0] @@ -248,7 +245,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): scheduling_args = _get_schedule_args(link_obj) if link_obj.start_dt else {} - self._check_indico_is_assistant(owner_id) + self._check_indico_is_assistant(host_id) try: settings = { @@ -262,7 +259,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): type=2 if scheduling_args else 3, # scheduled vs. recurring meeting topic=vc_room.name, password=_gen_random_password(), - schedule_for=owner_id, + schedule_for=host_id, timezone=event.timezone, settings=settings, **scheduling_args) @@ -276,21 +273,21 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'public_url': meeting_obj['join_url'].split('?')[0], 'start_url': meeting_obj['start_url'], 'password': meeting_obj['password'], - 'owner': owner.identifier + 'host': host.identifier }) flag_modified(vc_room, 'data') # e-mail Host URL to meeting host if self.settings.get('send_host_url'): - self.notify_owner_start_url(vc_room) + notify_host_start_url(vc_room) def update_room(self, vc_room, event): client = ZoomIndicoClient() zoom_meeting = _fetch_zoom_meeting(vc_room, client=client) changes = {} - owner = principal_from_identifier(vc_room.data['owner']) + host = principal_from_identifier(vc_room.data['host']) host_id = zoom_meeting['host_id'] try: @@ -299,15 +296,16 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): self.logger.exception("Error retrieving user '%s': %s", host_id, e.response.content) raise VCRoomError(_("Can't get information about user. Please contact support if the error persists.")) - # owner changed - if host_data['email'] not in owner.all_emails: - email = find_enterprise_email(owner) + # host changed + if host_data['email'] not in host.all_emails: + email = find_enterprise_email(host) if not email: raise Forbidden(_("This user doesn't seem to have an associated Zoom account")) changes['schedule_for'] = email self._check_indico_is_assistant(email) + notify_new_host(session.user, vc_room) if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name @@ -356,8 +354,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'mute_host_video': self.settings.get('mute_host_video'), 'mute_participant_video': self.settings.get('mute_participant_video'), 'waiting_room': self.settings.get('waiting_room'), - 'owner_choice': 'myself', - 'owner_user': None, + 'host_choice': 'myself', + 'host_user': None, 'password_visibility': 'logged_in' }) return defaults @@ -369,36 +367,20 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def can_manage_vc_room(self, user, room): return ( - user == principal_from_identifier(room.data['owner']) or + user == principal_from_identifier(room.data['host']) or super(ZoomPlugin, self).can_manage_vc_room(user, room) ) def _merge_users(self, target, source, **kwargs): super(ZoomPlugin, self)._merge_users(target, source, **kwargs) for room in VCRoom.query.filter( - VCRoom.type == self.service_name, VCRoom.data.contains({'owner': source.identifier}) + VCRoom.type == self.service_name, VCRoom.data.contains({'host': source.identifier}) ): - room.data['owner'] = target.id + room.data['host'] = target.id flag_modified(room, 'data') def get_notification_cc_list(self, action, vc_room, event): - return {principal_from_identifier(vc_room.data['owner']).email} - - def notify_owner_start_url(self, vc_room): - user = principal_from_identifier(vc_room.data['owner']) - to_list = {user.email} - - template_module = get_template_module( - 'vc_zoom:emails/notify_start_url.html', - plugin=ZoomPlugin.instance, - vc_room=vc_room, - event=None, - vc_room_event=None, - user=user - ) - - email = make_email(to_list, template=template_module, html=True) - send_email(email, None, 'Zoom') + return {principal_from_identifier(vc_room.data['host']).email} def _times_changed(self, sender, obj, **kwargs): from indico.modules.events.models.events import Event diff --git a/indico_vc_zoom/templates/emails/created.html b/indico_vc_zoom/templates/emails/created.html index d8a8d36..1dbafeb 100644 --- a/indico_vc_zoom/templates/emails/created.html +++ b/indico_vc_zoom/templates/emails/created.html @@ -3,7 +3,7 @@ {% block plugin_specific_info %}
  • Host: - {{ (vc_room.data.owner|decodeprincipal).full_name }} + {{ (vc_room.data.host|decodeprincipal).full_name }}
  • Zoom URL: diff --git a/indico_vc_zoom/templates/emails/notify_new_host.html b/indico_vc_zoom/templates/emails/notify_new_host.html new file mode 100644 index 0000000..225aa88 --- /dev/null +++ b/indico_vc_zoom/templates/emails/notify_new_host.html @@ -0,0 +1,25 @@ +{% extends 'emails/base.html' %} + +{% block subject -%} + [{{ plugin.friendly_name }}] You are now hosting '{{ vc_room.name }}' +{%- endblock %} + +{% block header -%} +

    + {{ actor.full_name }} has just made you the host of Zoom Meeting '{{ vc_room.name }}'. +

    + {% if plugin.settings.get('send_host_url') %} +

    + ATTENTION: + You should not share this URL with anyone, since it will allow them to become meeting hosts! +

    + + {% endif %} + + {% block custom_footer %}{% endblock %} +{%- endblock %} diff --git a/indico_vc_zoom/templates/emails/notify_start_url.html b/indico_vc_zoom/templates/emails/notify_start_url.html index 269ddc7..320a3af 100644 --- a/indico_vc_zoom/templates/emails/notify_start_url.html +++ b/indico_vc_zoom/templates/emails/notify_start_url.html @@ -1,7 +1,7 @@ {% extends 'emails/base.html' %} {% block subject -%} - Zoom Host URL - {{ vc_room.name }} + [{{ plugin.friendly_name }}] Host URL - {{ vc_room.name }} {%- endblock %} {% block header -%} diff --git a/indico_vc_zoom/templates/info_box.html b/indico_vc_zoom/templates/info_box.html index 56df0d3..acbb647 100644 --- a/indico_vc_zoom/templates/info_box.html +++ b/indico_vc_zoom/templates/info_box.html @@ -1,12 +1,12 @@ {% from '_clipboard_input.html' import clipboard_input %} -{% set owner = vc_room.data.owner %} +{% set host = vc_room.data.host %} {% set phone_link = settings.get('zoom_phone_link') %}
    {% trans %}Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    - {% if owner %} -
    {% trans %}Owner{% endtrans %}
    -
    {{ (owner|decodeprincipal).full_name }}
    + {% if host %} +
    {% trans %}Host{% endtrans %}
    +
    {{ (host|decodeprincipal).full_name }}
    {% endif %} {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or (session.user and event_vc_room.data.password_visibility == 'logged_in') %} diff --git a/indico_vc_zoom/templates/manage_event_info_box.html b/indico_vc_zoom/templates/manage_event_info_box.html index 42a5466..ebbffcf 100644 --- a/indico_vc_zoom/templates/manage_event_info_box.html +++ b/indico_vc_zoom/templates/manage_event_info_box.html @@ -1,13 +1,13 @@ {% from '_password.html' import password %} {% from '_clipboard_input.html' import clipboard_input %} -{% set owner = vc_room.data.owner %} +{% set host = vc_room.data.host %} {% set phone_link = settings.get('zoom_phone_link') %}
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    -
    {% trans %}Owner{% endtrans %}
    +
    {% trans %}Host{% endtrans %}
    - {{ (owner|decodeprincipal).full_name }} + {{ (host|decodeprincipal).full_name }}
    {% trans %}Linked to{% endtrans %}
    From 354df7b1d71ffde15399af96b4ca0b57696843bd Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 30 Sep 2020 09:24:13 +0200 Subject: [PATCH 14/94] VC/Zoom: Add webinar mode --- indico_vc_zoom/api/client.py | 49 +++++++- indico_vc_zoom/forms.py | 14 ++- indico_vc_zoom/plugin.py | 142 ++++++++++++++++------ indico_vc_zoom/templates/info_box.html | 2 +- indico_vc_zoom/templates/room_labels.html | 6 + 5 files changed, 170 insertions(+), 43 deletions(-) create mode 100644 indico_vc_zoom/templates/room_labels.html diff --git a/indico_vc_zoom/api/client.py b/indico_vc_zoom/api/client.py index 8dbc9e7..c8cf130 100644 --- a/indico_vc_zoom/api/client.py +++ b/indico_vc_zoom/api/client.py @@ -83,8 +83,35 @@ class MeetingComponent(BaseComponent): "{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs ) - def get_invitation(self, meeting_id, **kwargs): - return self.session.get("{}/meetings/{}/invitation".format(self.base_uri, meeting_id), json=kwargs) + +class WebinarComponent(BaseComponent): + def list(self, user_id, **kwargs): + return self.get( + "{}/users/{}/webinars".format(self.base_uri, user_id), params=kwargs + ) + + def create(self, user_id, **kwargs): + if kwargs.get("start_time"): + kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + return self.session.post( + "{}/users/{}/webinars".format(self.base_uri, user_id), + json=kwargs + ) + + def get(self, meeting_id, **kwargs): + return self.session.get("{}/webinars/{}".format(self.base_uri, meeting_id), json=kwargs) + + def update(self, meeting_id, **kwargs): + if kwargs.get("start_time"): + kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + return self.session.patch( + "{}/webinars/{}".format(self.base_uri, meeting_id), json=kwargs + ) + + def delete(self, meeting_id, **kwargs): + return self.session.delete( + "{}/webinars/{}".format(self.base_uri, meeting_id), json=kwargs + ) class UserComponent(BaseComponent): @@ -118,7 +145,8 @@ class ZoomClient(object): _components = { 'user': UserComponent, - 'meeting': MeetingComponent + 'meeting': MeetingComponent, + 'webinar': WebinarComponent } def __init__(self, api_key, api_secret, timeout=15): @@ -180,12 +208,21 @@ class ZoomIndicoClient(object): def update_meeting(self, meeting_id, data): return _handle_response(self.client.meeting.update(meeting_id, **data), 204, expects_json=False) - def get_meeting_invitation(self, meeting_id): - return _handle_response(self.client.meeting.get_invitation(meeting_id)) - def delete_meeting(self, meeting_id): return _handle_response(self.client.meeting.delete(meeting_id), 204, expects_json=False) + def create_webinar(self, user_id, **kwargs): + return _handle_response(self.client.webinar.create(user_id, **kwargs), 201) + + def get_webinar(self, webinar_id): + return _handle_response(self.client.webinar.get(webinar_id)) + + def update_webinar(self, webinar_id, data): + return _handle_response(self.client.webinar.update(webinar_id, **data), 204, expects_json=False) + + def delete_webinar(self, webinar_id): + return _handle_response(self.client.webinar.delete(webinar_id), 204, expects_json=False) + def check_user_meeting_time(self, user_id, start_dt, end_dt): pass diff --git a/indico_vc_zoom/forms.py b/indico_vc_zoom/forms.py index 1c19a0c..10ed183 100644 --- a/indico_vc_zoom/forms.py +++ b/indico_vc_zoom/forms.py @@ -32,6 +32,13 @@ class VCRoomForm(VCRoomFormBase): skip_fields = advanced_fields | VCRoomFormBase.conditional_fields + meeting_type = IndicoRadioField(_("Meeting Type"), + description=_("The type of Zoom meeting ot be created"), + orientation='horizontal', + choices=[ + ('regular', _('Regular Meeting')), + ('webinar', _('Webinar'))]) + host_choice = IndicoRadioField(_("Meeting Host"), [DataRequired()], choices=[('myself', _("Myself")), ('someone_else', _("Someone else"))]) @@ -47,6 +54,7 @@ class VCRoomForm(VCRoomFormBase): ('no_one', _("No one"))]) mute_audio = BooleanField(_('Mute audio'), + [HiddenUnless('meeting_type', 'regular')], widget=SwitchWidget(), description=_('Participants will join the VC room muted by default ')) @@ -55,14 +63,16 @@ class VCRoomForm(VCRoomFormBase): description=_('The host will join the VC room with video disabled')) mute_participant_video = BooleanField(_('Mute video (participants)'), + [HiddenUnless('meeting_type', 'regular')], widget=SwitchWidget(), description=_('Participants will join the VC room with video disabled')) waiting_room = BooleanField(_('Waiting room'), + [HiddenUnless('meeting_type', 'regular')], widget=SwitchWidget(), description=_('Participants may be kept in a waiting room by the host')) - description = TextAreaField(_('Description'), description=_('The description of the room')) + description = TextAreaField(_('Description'), description=_('Optional description for this room')) def __init__(self, *args, **kwargs): defaults = kwargs['obj'] @@ -74,6 +84,8 @@ class VCRoomForm(VCRoomFormBase): @generated_data def host(self): + if self.host_choice is None: + return None return session.user.identifier if self.host_choice.data == 'myself' else self.host_user.data.identifier def validate_host_user(self, field): diff --git a/indico_vc_zoom/plugin.py b/indico_vc_zoom/plugin.py index 6af14be..8cfbf62 100644 --- a/indico_vc_zoom/plugin.py +++ b/indico_vc_zoom/plugin.py @@ -15,12 +15,13 @@ from wtforms.validators import DataRequired, NumberRange from indico.core import signals from indico.core.config import config -from indico.core.plugins import IndicoPlugin, url_for_plugin +from indico.core.plugins import IndicoPlugin, render_plugin_template, url_for_plugin from indico.modules.events.views import WPSimpleEventDisplay from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError from indico.modules.vc.models.vc_rooms import VCRoom from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent +from indico.util.date_time import now_utc from indico.util.user import principal_from_identifier from indico.web.forms.fields.simple import IndicoPasswordField from indico.web.forms.widgets import CKEditorWidget, SwitchWidget @@ -40,12 +41,14 @@ def _gen_random_password(): return ''.join(random.sample(string.ascii_lowercase + string.ascii_uppercase + string.digits, 10)) -def _fetch_zoom_meeting(vc_room, client=None): +def _fetch_zoom_meeting(vc_room, client=None, is_webinar=False): try: client = client or ZoomIndicoClient() + if is_webinar: + return client.get_webinar(vc_room.data['zoom_id']) return client.get_meeting(vc_room.data['zoom_id']) except HTTPError as e: - if e.response.status_code == 404: + if e.response.status_code in {400, 404}: # Indico will automatically mark this room as deleted raise VCRoomNotFoundError(_("This room has been deleted from Zoom")) else: @@ -53,19 +56,27 @@ def _fetch_zoom_meeting(vc_room, client=None): raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) -def _update_zoom_meeting(zoom_id, changes): +def _update_zoom_meeting(zoom_id, changes, is_webinar=False): client = ZoomIndicoClient() try: - client.update_meeting(zoom_id, changes) + if is_webinar: + client.update_webinar(zoom_id, changes) + else: + client.update_meeting(zoom_id, changes) except HTTPError as e: ZoomPlugin.logger.exception("Error updating meeting '%s': %s", zoom_id, e.response.content) raise VCRoomError(_("Can't update meeting. Please contact support if the error persists.")) def _get_schedule_args(obj): + duration = obj.end_dt - obj.start_dt + + if obj.start_dt < now_utc(): + return {} + return { 'start_time': obj.start_dt, - 'duration': (obj.end_dt - obj.start_dt).total_seconds() / 60, + 'duration': duration.total_seconds() / 60, } @@ -136,6 +147,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): super(ZoomPlugin, self).init() self.connect(signals.plugin.cli, self._extend_indico_cli) self.connect(signals.event.times_changed, self._times_changed) + self.template_hook('event-vc-room-list-item-labels', self._render_vc_room_labels) self.inject_bundle('main.js', WPSimpleEventDisplay) self.inject_bundle('main.js', WPVCEventPage) self.inject_bundle('main.js', WPVCManageEvent) @@ -169,6 +181,25 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def icon_url(self): return url_for_plugin(self.name + '.static', filename='images/zoom_logo.png') + def create_form(self, event, existing_vc_room=None, existing_event_vc_room=None): + """Override the default room form creation mechanism.""" + form = super(ZoomPlugin, self).create_form( + event, + existing_vc_room=existing_vc_room, + existing_event_vc_room=existing_event_vc_room + ) + + if existing_vc_room: + # if we're editing a VC room, we will not allow the meeting type to be changed + form.meeting_type.render_kw = {'disabled': True} + + if form.data['meeting_type'] == 'webinar': + # webinar hosts cannot be changed through the API + form.host_choice.render_kw = {'disabled': True} + form.host_user.render_kw = {'disabled': True} + + return form + def _extend_indico_cli(self, sender, **kwargs): return cli @@ -200,11 +231,20 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): room_assoc.data['password_visibility'] = data.pop('password_visibility') flag_modified(room_assoc, 'data') - def update_data_vc_room(self, vc_room, data): + def update_data_vc_room(self, vc_room, data, is_new=False): super(ZoomPlugin, self).update_data_vc_room(vc_room, data) + fields = {'description'} + if data['meeting_type'] == 'webinar': + fields |= {'mute_host_video'} + if is_new: + fields |= {'host', 'meeting_type'} + else: + fields |= { + 'meeting_type', 'host', 'mute_audio', 'mute_participant_video', 'mute_host_video', 'join_before_host', + 'waiting_room' + } - for key in {'description', 'host', 'mute_audio', 'mute_participant_video', 'mute_host_video', - 'join_before_host', 'waiting_room'}: + for key in fields: if key in data: vc_room.data[key] = data.pop(key) @@ -237,32 +277,50 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): """ client = ZoomIndicoClient() host = principal_from_identifier(vc_room.data['host']) - host_id = find_enterprise_email(host) + host_email = find_enterprise_email(host) # get the object that this booking is linked to vc_room_assoc = vc_room.events[0] link_obj = vc_room_assoc.link_object - + is_webinar = vc_room.data['meeting_type'] == 'webinar' scheduling_args = _get_schedule_args(link_obj) if link_obj.start_dt else {} - self._check_indico_is_assistant(host_id) + self._check_indico_is_assistant(host_email) try: settings = { 'host_video': vc_room.data['mute_host_video'], - 'participant_video': not vc_room.data['mute_participant_video'], - 'join_before_host': self.settings.get('join_before_host'), - 'mute_upon_entry': vc_room.data['mute_audio'], - 'waiting_room': vc_room.data['waiting_room'] } - meeting_obj = client.create_meeting(self.settings.get('assistant_id'), - type=2 if scheduling_args else 3, # scheduled vs. recurring meeting - topic=vc_room.name, - password=_gen_random_password(), - schedule_for=host_id, - timezone=event.timezone, - settings=settings, - **scheduling_args) + + kwargs = {} + if is_webinar: + kwargs = { + 'type': 5 if scheduling_args else 6, + 'host_email': host_email + } + else: + kwargs = { + 'type': 2 if scheduling_args else 3, + 'schedule_for': host_email + } + settings.update({ + 'mute_upon_entry': vc_room.data['mute_audio'], + 'participant_video': not vc_room.data['mute_participant_video'], + 'waiting_room': vc_room.data['waiting_room'], + 'join_before_host': self.settings.get('join_before_host'), + }) + + kwargs.update({ + 'topic': vc_room.name, + 'password': _gen_random_password(), + 'timezone': event.timezone, + 'settings': settings + }) + kwargs.update(scheduling_args) + if is_webinar: + meeting_obj = client.create_webinar(self.settings.get('assistant_id'), **kwargs) + else: + meeting_obj = client.create_meeting(self.settings.get('assistant_id'), **kwargs) except HTTPError as e: self.logger.exception('Error creating Zoom Room: %s', e.response.content) raise VCRoomError(_("Could not create the room in Zoom. Please contact support if the error persists")) @@ -284,7 +342,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def update_room(self, vc_room, event): client = ZoomIndicoClient() - zoom_meeting = _fetch_zoom_meeting(vc_room, client=client) + is_webinar = vc_room.data['meeting_type'] == 'webinar' + zoom_meeting = _fetch_zoom_meeting(vc_room, client=client, is_webinar=is_webinar) changes = {} host = principal_from_identifier(vc_room.data['host']) @@ -303,7 +362,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if not email: raise Forbidden(_("This user doesn't seem to have an associated Zoom account")) - changes['schedule_for'] = email + changes['host_email' if is_webinar else 'schedule_for'] = email self._check_indico_is_assistant(email) notify_new_host(session.user, vc_room) @@ -311,20 +370,23 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): changes['topic'] = vc_room.name zoom_meeting_settings = zoom_meeting['settings'] - if vc_room.data['mute_audio'] != zoom_meeting_settings['mute_upon_entry']: - changes.setdefault('settings', {})['mute_upon_entry'] = vc_room.data['mute_audio'] - if vc_room.data['mute_participant_video'] == zoom_meeting_settings['participant_video']: - changes.setdefault('settings', {})['participant_video'] = not vc_room.data['mute_participant_video'] if vc_room.data['mute_host_video'] == zoom_meeting_settings['host_video']: changes.setdefault('settings', {})['host_video'] = not vc_room.data['mute_host_video'] - if vc_room.data['waiting_room'] != zoom_meeting_settings['waiting_room']: - changes.setdefault('settings', {})['waiting_room'] = vc_room.data['waiting_room'] + + if not is_webinar: + if vc_room.data['mute_audio'] != zoom_meeting_settings['mute_upon_entry']: + changes.setdefault('settings', {})['mute_upon_entry'] = vc_room.data['mute_audio'] + if vc_room.data['mute_participant_video'] == zoom_meeting_settings['participant_video']: + changes.setdefault('settings', {})['participant_video'] = not vc_room.data['mute_participant_video'] + if vc_room.data['waiting_room'] != zoom_meeting_settings['waiting_room']: + changes.setdefault('settings', {})['waiting_room'] = vc_room.data['waiting_room'] if changes: - _update_zoom_meeting(vc_room.data['zoom_id'], changes) + _update_zoom_meeting(vc_room.data['zoom_id'], changes, is_webinar=is_webinar) def refresh_room(self, vc_room, event): - zoom_meeting = _fetch_zoom_meeting(vc_room) + is_webinar = vc_room.data['meeting_type'] == 'webinar' + zoom_meeting = _fetch_zoom_meeting(vc_room, is_webinar=is_webinar) vc_room.name = zoom_meeting['topic'] vc_room.data.update({ 'url': zoom_meeting['join_url'], @@ -336,8 +398,12 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def delete_room(self, vc_room, event): client = ZoomIndicoClient() zoom_id = vc_room.data['zoom_id'] + is_webinar = vc_room.data['meeting_type'] == 'webinar' try: - client.delete_meeting(zoom_id) + if is_webinar: + client.delete_webinar(zoom_id) + else: + client.delete_meeting(zoom_id) except HTTPError as e: # if there's a 404, there is no problem, since the room is supposed to be gone anyway if not e.response.status_code == 404: @@ -350,6 +416,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def get_vc_room_form_defaults(self, event): defaults = super(ZoomPlugin, self).get_vc_room_form_defaults(event) defaults.update({ + 'meeting_type': 'regular', 'mute_audio': self.settings.get('mute_audio'), 'mute_host_video': self.settings.get('mute_host_video'), 'mute_participant_video': self.settings.get('mute_participant_video'), @@ -382,6 +449,11 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def get_notification_cc_list(self, action, vc_room, event): return {principal_from_identifier(vc_room.data['host']).email} + def _render_vc_room_labels(self, event, vc_room, **kwargs): + if vc_room.plugin != self: + return + return render_plugin_template('room_labels.html', vc_room=vc_room) + def _times_changed(self, sender, obj, **kwargs): from indico.modules.events.models.events import Event from indico.modules.events.contributions.models.contributions import Contribution diff --git a/indico_vc_zoom/templates/info_box.html b/indico_vc_zoom/templates/info_box.html index acbb647..376b442 100644 --- a/indico_vc_zoom/templates/info_box.html +++ b/indico_vc_zoom/templates/info_box.html @@ -2,7 +2,7 @@ {% set host = vc_room.data.host %} {% set phone_link = settings.get('zoom_phone_link') %}
    -
    {% trans %}Meeting ID{% endtrans %}
    +
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    {% if host %}
    {% trans %}Host{% endtrans %}
    diff --git a/indico_vc_zoom/templates/room_labels.html b/indico_vc_zoom/templates/room_labels.html new file mode 100644 index 0000000..36d0865 --- /dev/null +++ b/indico_vc_zoom/templates/room_labels.html @@ -0,0 +1,6 @@ +{% if vc_room.data.meeting_type == 'webinar' %} +
    + {% trans %}Webinar{% endtrans %} +
    +{% endif %} From b881c133c6b5f8f0be8e6fe83dc563439e76c529 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 11:24:26 +0100 Subject: [PATCH 15/94] VC/Zoom: Move everything to vc_zoom dir --- .flake8 => vc_zoom/.flake8 | 0 .gitignore => vc_zoom/.gitignore | 0 MANIFEST.in => vc_zoom/MANIFEST.in | 0 README.md => vc_zoom/README.md | 0 conftest.py => vc_zoom/conftest.py | 0 .../indico_vc_zoom}/__init__.py | 0 .../indico_vc_zoom}/api/__init__.py | 0 .../indico_vc_zoom}/api/client.py | 0 .../indico_vc_zoom}/blueprint.py | 0 {indico_vc_zoom => vc_zoom/indico_vc_zoom}/cli.py | 0 .../indico_vc_zoom}/client/index.js | 0 .../indico_vc_zoom}/controllers.py | 0 {indico_vc_zoom => vc_zoom/indico_vc_zoom}/forms.py | 0 .../indico_vc_zoom}/http_api.py | 0 .../indico_vc_zoom}/notifications.py | 0 .../indico_vc_zoom}/plugin.py | 0 .../indico_vc_zoom}/static/images/zoom_logo.png | Bin .../indico_vc_zoom}/templates/buttons.html | 0 .../indico_vc_zoom}/templates/emails/created.html | 0 .../indico_vc_zoom}/templates/emails/deleted.html | 0 .../templates/emails/notify_new_host.html | 0 .../templates/emails/notify_start_url.html | 0 .../templates/emails/remote_deleted.html | 0 .../indico_vc_zoom}/templates/event_buttons.html | 0 .../indico_vc_zoom}/templates/info_box.html | 0 .../templates/manage_event_info_box.html | 0 .../templates/management_buttons.html | 0 .../indico_vc_zoom}/templates/room_labels.html | 0 .../templates/vc_room_timetable_buttons.html | 0 .../translations/fr_FR/LC_MESSAGES/messages-js.po | 0 .../translations/fr_FR/LC_MESSAGES/messages.po | 0 {indico_vc_zoom => vc_zoom/indico_vc_zoom}/util.py | 0 pytest.ini => vc_zoom/pytest.ini | 0 setup.cfg => vc_zoom/setup.cfg | 0 setup.py => vc_zoom/setup.py | 0 {tests => vc_zoom/tests}/task_test.py | 0 .../webpack-bundles.json | 0 37 files changed, 0 insertions(+), 0 deletions(-) rename .flake8 => vc_zoom/.flake8 (100%) rename .gitignore => vc_zoom/.gitignore (100%) rename MANIFEST.in => vc_zoom/MANIFEST.in (100%) rename README.md => vc_zoom/README.md (100%) rename conftest.py => vc_zoom/conftest.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/__init__.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/api/__init__.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/api/client.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/blueprint.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/cli.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/client/index.js (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/controllers.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/forms.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/http_api.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/notifications.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/plugin.py (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/static/images/zoom_logo.png (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/buttons.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/emails/created.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/emails/deleted.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/emails/notify_new_host.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/emails/notify_start_url.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/emails/remote_deleted.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/event_buttons.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/info_box.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/manage_event_info_box.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/management_buttons.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/room_labels.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/templates/vc_room_timetable_buttons.html (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/translations/fr_FR/LC_MESSAGES/messages-js.po (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/translations/fr_FR/LC_MESSAGES/messages.po (100%) rename {indico_vc_zoom => vc_zoom/indico_vc_zoom}/util.py (100%) rename pytest.ini => vc_zoom/pytest.ini (100%) rename setup.cfg => vc_zoom/setup.cfg (100%) rename setup.py => vc_zoom/setup.py (100%) rename {tests => vc_zoom/tests}/task_test.py (100%) rename webpack-bundles.json => vc_zoom/webpack-bundles.json (100%) diff --git a/.flake8 b/vc_zoom/.flake8 similarity index 100% rename from .flake8 rename to vc_zoom/.flake8 diff --git a/.gitignore b/vc_zoom/.gitignore similarity index 100% rename from .gitignore rename to vc_zoom/.gitignore diff --git a/MANIFEST.in b/vc_zoom/MANIFEST.in similarity index 100% rename from MANIFEST.in rename to vc_zoom/MANIFEST.in diff --git a/README.md b/vc_zoom/README.md similarity index 100% rename from README.md rename to vc_zoom/README.md diff --git a/conftest.py b/vc_zoom/conftest.py similarity index 100% rename from conftest.py rename to vc_zoom/conftest.py diff --git a/indico_vc_zoom/__init__.py b/vc_zoom/indico_vc_zoom/__init__.py similarity index 100% rename from indico_vc_zoom/__init__.py rename to vc_zoom/indico_vc_zoom/__init__.py diff --git a/indico_vc_zoom/api/__init__.py b/vc_zoom/indico_vc_zoom/api/__init__.py similarity index 100% rename from indico_vc_zoom/api/__init__.py rename to vc_zoom/indico_vc_zoom/api/__init__.py diff --git a/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py similarity index 100% rename from indico_vc_zoom/api/client.py rename to vc_zoom/indico_vc_zoom/api/client.py diff --git a/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py similarity index 100% rename from indico_vc_zoom/blueprint.py rename to vc_zoom/indico_vc_zoom/blueprint.py diff --git a/indico_vc_zoom/cli.py b/vc_zoom/indico_vc_zoom/cli.py similarity index 100% rename from indico_vc_zoom/cli.py rename to vc_zoom/indico_vc_zoom/cli.py diff --git a/indico_vc_zoom/client/index.js b/vc_zoom/indico_vc_zoom/client/index.js similarity index 100% rename from indico_vc_zoom/client/index.js rename to vc_zoom/indico_vc_zoom/client/index.js diff --git a/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py similarity index 100% rename from indico_vc_zoom/controllers.py rename to vc_zoom/indico_vc_zoom/controllers.py diff --git a/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py similarity index 100% rename from indico_vc_zoom/forms.py rename to vc_zoom/indico_vc_zoom/forms.py diff --git a/indico_vc_zoom/http_api.py b/vc_zoom/indico_vc_zoom/http_api.py similarity index 100% rename from indico_vc_zoom/http_api.py rename to vc_zoom/indico_vc_zoom/http_api.py diff --git a/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py similarity index 100% rename from indico_vc_zoom/notifications.py rename to vc_zoom/indico_vc_zoom/notifications.py diff --git a/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py similarity index 100% rename from indico_vc_zoom/plugin.py rename to vc_zoom/indico_vc_zoom/plugin.py diff --git a/indico_vc_zoom/static/images/zoom_logo.png b/vc_zoom/indico_vc_zoom/static/images/zoom_logo.png similarity index 100% rename from indico_vc_zoom/static/images/zoom_logo.png rename to vc_zoom/indico_vc_zoom/static/images/zoom_logo.png diff --git a/indico_vc_zoom/templates/buttons.html b/vc_zoom/indico_vc_zoom/templates/buttons.html similarity index 100% rename from indico_vc_zoom/templates/buttons.html rename to vc_zoom/indico_vc_zoom/templates/buttons.html diff --git a/indico_vc_zoom/templates/emails/created.html b/vc_zoom/indico_vc_zoom/templates/emails/created.html similarity index 100% rename from indico_vc_zoom/templates/emails/created.html rename to vc_zoom/indico_vc_zoom/templates/emails/created.html diff --git a/indico_vc_zoom/templates/emails/deleted.html b/vc_zoom/indico_vc_zoom/templates/emails/deleted.html similarity index 100% rename from indico_vc_zoom/templates/emails/deleted.html rename to vc_zoom/indico_vc_zoom/templates/emails/deleted.html diff --git a/indico_vc_zoom/templates/emails/notify_new_host.html b/vc_zoom/indico_vc_zoom/templates/emails/notify_new_host.html similarity index 100% rename from indico_vc_zoom/templates/emails/notify_new_host.html rename to vc_zoom/indico_vc_zoom/templates/emails/notify_new_host.html diff --git a/indico_vc_zoom/templates/emails/notify_start_url.html b/vc_zoom/indico_vc_zoom/templates/emails/notify_start_url.html similarity index 100% rename from indico_vc_zoom/templates/emails/notify_start_url.html rename to vc_zoom/indico_vc_zoom/templates/emails/notify_start_url.html diff --git a/indico_vc_zoom/templates/emails/remote_deleted.html b/vc_zoom/indico_vc_zoom/templates/emails/remote_deleted.html similarity index 100% rename from indico_vc_zoom/templates/emails/remote_deleted.html rename to vc_zoom/indico_vc_zoom/templates/emails/remote_deleted.html diff --git a/indico_vc_zoom/templates/event_buttons.html b/vc_zoom/indico_vc_zoom/templates/event_buttons.html similarity index 100% rename from indico_vc_zoom/templates/event_buttons.html rename to vc_zoom/indico_vc_zoom/templates/event_buttons.html diff --git a/indico_vc_zoom/templates/info_box.html b/vc_zoom/indico_vc_zoom/templates/info_box.html similarity index 100% rename from indico_vc_zoom/templates/info_box.html rename to vc_zoom/indico_vc_zoom/templates/info_box.html diff --git a/indico_vc_zoom/templates/manage_event_info_box.html b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html similarity index 100% rename from indico_vc_zoom/templates/manage_event_info_box.html rename to vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html diff --git a/indico_vc_zoom/templates/management_buttons.html b/vc_zoom/indico_vc_zoom/templates/management_buttons.html similarity index 100% rename from indico_vc_zoom/templates/management_buttons.html rename to vc_zoom/indico_vc_zoom/templates/management_buttons.html diff --git a/indico_vc_zoom/templates/room_labels.html b/vc_zoom/indico_vc_zoom/templates/room_labels.html similarity index 100% rename from indico_vc_zoom/templates/room_labels.html rename to vc_zoom/indico_vc_zoom/templates/room_labels.html diff --git a/indico_vc_zoom/templates/vc_room_timetable_buttons.html b/vc_zoom/indico_vc_zoom/templates/vc_room_timetable_buttons.html similarity index 100% rename from indico_vc_zoom/templates/vc_room_timetable_buttons.html rename to vc_zoom/indico_vc_zoom/templates/vc_room_timetable_buttons.html diff --git a/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po similarity index 100% rename from indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po rename to vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po diff --git a/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po similarity index 100% rename from indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po rename to vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po diff --git a/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py similarity index 100% rename from indico_vc_zoom/util.py rename to vc_zoom/indico_vc_zoom/util.py diff --git a/pytest.ini b/vc_zoom/pytest.ini similarity index 100% rename from pytest.ini rename to vc_zoom/pytest.ini diff --git a/setup.cfg b/vc_zoom/setup.cfg similarity index 100% rename from setup.cfg rename to vc_zoom/setup.cfg diff --git a/setup.py b/vc_zoom/setup.py similarity index 100% rename from setup.py rename to vc_zoom/setup.py diff --git a/tests/task_test.py b/vc_zoom/tests/task_test.py similarity index 100% rename from tests/task_test.py rename to vc_zoom/tests/task_test.py diff --git a/webpack-bundles.json b/vc_zoom/webpack-bundles.json similarity index 100% rename from webpack-bundles.json rename to vc_zoom/webpack-bundles.json From 00c9529828a6e6f1b376dc2ecc82311ae9042bb0 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 11:58:14 +0100 Subject: [PATCH 16/94] VC/Zoom: Delete plugin-specific files --- vc_zoom/.flake8 | 37 -------------------- vc_zoom/.gitignore | 85 ---------------------------------------------- 2 files changed, 122 deletions(-) delete mode 100644 vc_zoom/.flake8 delete mode 100755 vc_zoom/.gitignore diff --git a/vc_zoom/.flake8 b/vc_zoom/.flake8 deleted file mode 100644 index aff3b92..0000000 --- a/vc_zoom/.flake8 +++ /dev/null @@ -1,37 +0,0 @@ -[flake8] -max-line-length = 120 - -# colored output -format = ${cyan}%(path)s${reset}:${yellow_bold}%(row)d${reset}:${green_bold}%(col)d${reset}: ${red_bold}%(code)s${reset} %(text)s - -# decent quote styles -inline-quotes = single -multiline-quotes = single -docstring-quotes = double -avoid-escape = true - -exclude = - build - dist - docs - ext_modules - htmlcov - indico.egg-info - node_modules - .*/ - # TODO: remove the next two entries and use extend-exclude once flake8 3.8.0 is out - .git - __pycache__ - -ignore = - # allow omitting whitespace around arithmetic operators - E226 - # don't require specific wrapping before/after binary operators - W503 - W504 - # allow assigning lambdas (it's useful for single-line functions defined inside other functions) - E731 - # while single quotes are nicer, we have double quotes in way too many places - Q000 - # for non-docstring multiline strings we don't really enforce a quote style - Q001 diff --git a/vc_zoom/.gitignore b/vc_zoom/.gitignore deleted file mode 100755 index 4a45354..0000000 --- a/vc_zoom/.gitignore +++ /dev/null @@ -1,85 +0,0 @@ -.vscode/ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -env/ -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -venv/ -*.egg-info/ -.installed.cfg -*.egg - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*,cover -.hypothesis/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log - -# Sphinx documentation -docs/build/ -docs/source/generated/ - -# pytest -.pytest_cache/ - -# PyBuilder -target/ - -# Editor files -#mac -.DS_Store -*~ - -#vim -*.swp -*.swo - -#pycharm -.idea/* - - -#Ipython Notebook -.ipynb_checkpoints - - -webpack-build-config.json -url_map.json From 4c23e59b546b0d3cc12e135255ab423098c355a1 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 15:17:18 +0100 Subject: [PATCH 17/94] VC/Zoom: remove unused configuration options --- vc_zoom/indico_vc_zoom/plugin.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 8cfbf62..f072fde 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -81,8 +81,6 @@ def _get_schedule_args(obj): class PluginSettingsForm(VCPluginSettingsFormBase): - support_email = EmailField(_('Zoom email support')) - api_key = StringField(_('API Key'), [DataRequired()]) api_secret = IndicoPasswordField(_('API Secret'), [DataRequired()], toggle=True) @@ -115,11 +113,6 @@ class PluginSettingsForm(VCPluginSettingsFormBase): widget=SwitchWidget(), description=_('Participants may be kept in a waiting room by the host')) - num_days_old = IntegerField(_('VC room age threshold'), [NumberRange(min=1), DataRequired()], - description=_('Number of days after an Indico event when a videoconference room is ' - 'considered old')) - max_rooms_warning = IntegerField(_('Max. num. VC rooms before warning'), [NumberRange(min=1), DataRequired()], - description=_('Maximum number of rooms until a warning is sent to the managers')) zoom_phone_link = URLField(_('ZoomVoice phone number'), description=_('Link to the list of ZoomVoice phone numbers')) @@ -156,7 +149,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): @property def default_settings(self): return dict(VCPluginMixin.default_settings, **{ - 'support_email': config.SUPPORT_EMAIL, 'assistant_id': config.SUPPORT_EMAIL, 'api_key': '', 'api_secret': '', @@ -166,8 +158,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'mute_participant_video': True, 'join_before_host': True, 'waiting_room': False, - 'num_days_old': 5, - 'max_rooms_warning': 5000, 'zoom_phone_link': None, 'creation_email_footer': None, 'send_host_url': False From 7a4f628f4051024b6548b46f276c3a5f7a6ea7df Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 15:17:32 +0100 Subject: [PATCH 18/94] VC/Zoom: make README nicer --- vc_zoom/README.md | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index 4b220a0..f3e3e6e 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -1,7 +1,41 @@ -Indico Plugin for Zoom based on Vidyo plugin. +# Indico Plugin for Zoom -To obtain Api key and api secret, please visit [https://marketplace.zoom.us/docs/guides/auth/jwt](https://marketplace.zoom.us/docs/guides/auth/jwt) +## Features -Not ready for production. + * Creating Zoom meetings from Indico; + * Sharing Zoom meetings between more than one Indico event; + * Creating meetings on behalf of others; + * Changes of host possible after creation; + * Protection of Zoom link (only logged in, everyone or no one) + * Webinar mode; -Developed by Giovanni Mariano @ ENEA Frascati +## Implementation details + +Rooms are created under the account of an *assistant user* which can be set using the **Assistant Zoom ID** +configuration setting. This account will also be added automatically as an assistant to every meeting host. +This is needed in order to allow for the host to be changed ([`scheduled_for`]( +https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate#request-body +) property in the Zoom API). The *assistant user* owns every Zoom meeting, with the `scheduled_for` property being +used to grant the required privileges to the desired hosts. + +## Configuration + +These are the most relevant configuration options: + + * **Notification email addresses** - Additional e-mails which will receive notifications + * **E-mail domains** - Comma-separated list of e-mail domains which can be used for the Zoom API (e.g. `cern.ch`) + * **Asistant Zoom ID** - Zoom ID (or e-mail) of the account which shall be used as an assistant to all hosts and +shall own all meetings + +### Zoom API key/secret +To obtain API key and API secret, please visit [https://marketplace.zoom.us/docs/guides/auth/jwt](https://marketplace.zoom.us/docs/guides/auth/jwt). + + +## Intellectual Property + +Developed by Giovanni Mariano @ **ENEA Frascati**, based on the Vidyo Plugin by the Indico Team at **CERN**. Further +improvements and modifications added by the Indico Team. + +This package is Open Source Software licensed under the [MIT License](https://opensource.org/licenses/MIT). + +**© Copyright 2020 CERN and ENEA** From 55334e9190857ad5794813490a7f4e6c0a3e6478 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 15:17:55 +0100 Subject: [PATCH 19/94] Add .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a31a519..7f92601 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.vscode .coverage htmlcov/ .idea/ From 4f86a1e2cfca6b8b2a92457729bbb56d28989205 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 15:35:00 +0100 Subject: [PATCH 20/94] VC/Zoom: Move util functions to util file --- vc_zoom/indico_vc_zoom/plugin.py | 76 +++++++------------------------- vc_zoom/indico_vc_zoom/util.py | 71 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 61 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index f072fde..14f1f4c 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -1,27 +1,23 @@ from __future__ import unicode_literals -import random -import string - from flask import flash, session from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified from werkzeug.exceptions import Forbidden, NotFound from wtforms.fields.core import BooleanField -from wtforms.fields import IntegerField, TextAreaField -from wtforms.fields.html5 import EmailField, URLField +from wtforms.fields import TextAreaField +from wtforms.fields.html5 import URLField from wtforms.fields.simple import StringField -from wtforms.validators import DataRequired, NumberRange +from wtforms.validators import DataRequired from indico.core import signals from indico.core.config import config from indico.core.plugins import IndicoPlugin, render_plugin_template, url_for_plugin from indico.modules.events.views import WPSimpleEventDisplay from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase -from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError +from indico.modules.vc.exceptions import VCRoomError from indico.modules.vc.models.vc_rooms import VCRoom from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent -from indico.util.date_time import now_utc from indico.util.user import principal_from_identifier from indico.web.forms.fields.simple import IndicoPasswordField from indico.web.forms.widgets import CKEditorWidget, SwitchWidget @@ -34,50 +30,8 @@ from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.http_api import DeleteVCRoomAPI from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url -from indico_vc_zoom.util import find_enterprise_email - - -def _gen_random_password(): - return ''.join(random.sample(string.ascii_lowercase + string.ascii_uppercase + string.digits, 10)) - - -def _fetch_zoom_meeting(vc_room, client=None, is_webinar=False): - try: - client = client or ZoomIndicoClient() - if is_webinar: - return client.get_webinar(vc_room.data['zoom_id']) - return client.get_meeting(vc_room.data['zoom_id']) - except HTTPError as e: - if e.response.status_code in {400, 404}: - # Indico will automatically mark this room as deleted - raise VCRoomNotFoundError(_("This room has been deleted from Zoom")) - else: - ZoomPlugin.logger.exception('Error getting Zoom Room: %s', e.response.content) - raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) - - -def _update_zoom_meeting(zoom_id, changes, is_webinar=False): - client = ZoomIndicoClient() - try: - if is_webinar: - client.update_webinar(zoom_id, changes) - else: - client.update_meeting(zoom_id, changes) - except HTTPError as e: - ZoomPlugin.logger.exception("Error updating meeting '%s': %s", zoom_id, e.response.content) - raise VCRoomError(_("Can't update meeting. Please contact support if the error persists.")) - - -def _get_schedule_args(obj): - duration = obj.end_dt - obj.start_dt - - if obj.start_dt < now_utc(): - return {} - - return { - 'start_time': obj.start_dt, - 'duration': duration.total_seconds() / 60, - } +from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_random_password, get_schedule_args, + update_zoom_meeting) class PluginSettingsForm(VCPluginSettingsFormBase): @@ -203,20 +157,20 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # this is not a new room if association_is_new: # this means we are updating an existing meeting with a new vc_room-event association - _update_zoom_meeting(vc_room.data['zoom_id'], { + update_zoom_meeting(vc_room.data['zoom_id'], { 'start_time': None, 'duration': None, 'type': 3 }) elif room_assoc.link_object != old_link: # the booking should now be linked to something else - new_schedule_args = _get_schedule_args(room_assoc.link_object) - meeting = _fetch_zoom_meeting(vc_room) + new_schedule_args = get_schedule_args(room_assoc.link_object) + meeting = fetch_zoom_meeting(vc_room) current_schedule_args = {k: meeting[k] for k in {'start_time', 'duration'}} # check whether the start time / duration of the scheduled meeting differs if new_schedule_args != current_schedule_args: - _update_zoom_meeting(vc_room.data['zoom_id'], new_schedule_args) + update_zoom_meeting(vc_room.data['zoom_id'], new_schedule_args) room_assoc.data['password_visibility'] = data.pop('password_visibility') flag_modified(room_assoc, 'data') @@ -273,7 +227,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room_assoc = vc_room.events[0] link_obj = vc_room_assoc.link_object is_webinar = vc_room.data['meeting_type'] == 'webinar' - scheduling_args = _get_schedule_args(link_obj) if link_obj.start_dt else {} + scheduling_args = get_schedule_args(link_obj) if link_obj.start_dt else {} self._check_indico_is_assistant(host_email) @@ -302,7 +256,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): kwargs.update({ 'topic': vc_room.name, - 'password': _gen_random_password(), + 'password': gen_random_password(), 'timezone': event.timezone, 'settings': settings }) @@ -333,7 +287,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def update_room(self, vc_room, event): client = ZoomIndicoClient() is_webinar = vc_room.data['meeting_type'] == 'webinar' - zoom_meeting = _fetch_zoom_meeting(vc_room, client=client, is_webinar=is_webinar) + zoom_meeting = fetch_zoom_meeting(vc_room, client=client, is_webinar=is_webinar) changes = {} host = principal_from_identifier(vc_room.data['host']) @@ -372,11 +326,11 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): changes.setdefault('settings', {})['waiting_room'] = vc_room.data['waiting_room'] if changes: - _update_zoom_meeting(vc_room.data['zoom_id'], changes, is_webinar=is_webinar) + update_zoom_meeting(vc_room.data['zoom_id'], changes, is_webinar=is_webinar) def refresh_room(self, vc_room, event): is_webinar = vc_room.data['meeting_type'] == 'webinar' - zoom_meeting = _fetch_zoom_meeting(vc_room, is_webinar=is_webinar) + zoom_meeting = fetch_zoom_meeting(vc_room, is_webinar=is_webinar) vc_room.name = zoom_meeting['topic'] vc_room.data.update({ 'url': zoom_meeting['join_url'], diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index cfb4ba5..087f35c 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -1,9 +1,18 @@ from __future__ import unicode_literals +import random +import string + +from requests.exceptions import HTTPError from indico.core.db import db from indico.modules.users.models.emails import UserEmail from indico.modules.users.models.users import User +from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError +from indico.util.date_time import now_utc + +from indico_vc_zoom import _ +from indico_vc_zoom.api import ZoomIndicoClient def find_enterprise_email(user): @@ -21,3 +30,65 @@ def find_enterprise_email(user): db.or_(UserEmail.email.ilike("%%@{}".format(provider)) for provider in providers) ).join(User).first() return result.email if result else None + + +def gen_random_password(): + """Generate a random 10-character-long alphanumeric string.""" + return ''.join(random.sample(string.ascii_lowercase + string.ascii_uppercase + string.digits, 10)) + + +def fetch_zoom_meeting(vc_room, client=None, is_webinar=False): + """Fetch a Zoom meeting from the Zoom API. + + :param vc_room: The `VCRoom` object + :param client: a `ZoomIndicoClient` object, otherwise a fresh one will be created + :param is_webinar: whether the call concerns a webinar (used to call the correct endpoint) + """ + try: + client = client or ZoomIndicoClient() + if is_webinar: + return client.get_webinar(vc_room.data['zoom_id']) + return client.get_meeting(vc_room.data['zoom_id']) + except HTTPError as e: + if e.response.status_code in {400, 404}: + # Indico will automatically mark this room as deleted + raise VCRoomNotFoundError(_("This room has been deleted from Zoom")) + else: + from indico_vc_zoom.plugin import ZoomPlugin + ZoomPlugin.logger.exception('Error getting Zoom Room: %s', e.response.content) + raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) + + +def update_zoom_meeting(zoom_id, changes, is_webinar=False): + """Update a meeting which already exists in the Zoom API. + + :param zoom_id: ID of the meeting + :param changes: dictionary with new attribute values + :param is_webinar: whether the call concerns a webinar (used to call the correct endpoint) + """ + client = ZoomIndicoClient() + try: + if is_webinar: + client.update_webinar(zoom_id, changes) + else: + client.update_meeting(zoom_id, changes) + except HTTPError as e: + from indico_vc_zoom.plugin import ZoomPlugin + ZoomPlugin.logger.exception("Error updating meeting '%s': %s", zoom_id, e.response.content) + raise VCRoomError(_("Can't update meeting. Please contact support if the error persists.")) + + +def get_schedule_args(obj): + """Create a dictionary with scheduling information from an Event/Contribution/SessionBlock. + + :param obj: An `Event`, `Contribution` or `SessionBlock` + """ + duration = obj.end_dt - obj.start_dt + + if obj.start_dt < now_utc(): + return {} + + return { + 'start_time': obj.start_dt, + 'duration': duration.total_seconds() / 60, + } From 9cda4f715c96fe7813567c3248f5ef42b70f8cab Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 16:36:12 +0100 Subject: [PATCH 21/94] VC/Zoom: Add simple operational tests for creation/update --- vc_zoom/tests/operation_test.py | 124 ++++++++++++++++++++++++++++++++ vc_zoom/tests/task_test.py | 22 ------ 2 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 vc_zoom/tests/operation_test.py delete mode 100644 vc_zoom/tests/task_test.py diff --git a/vc_zoom/tests/operation_test.py b/vc_zoom/tests/operation_test.py new file mode 100644 index 0000000..7e809a7 --- /dev/null +++ b/vc_zoom/tests/operation_test.py @@ -0,0 +1,124 @@ + +import pytest + +from indico.core.plugins import plugin_engine +from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomLinkType, VCRoomStatus + +from indico_vc_zoom.plugin import ZoomPlugin + + +@pytest.fixture +def zoom_plugin(app): + """Return a callable which lets you create dummy Zoom room occurrences.""" + plugin = ZoomPlugin(plugin_engine, app) + plugin.settings.set('email_domains', 'megacorp.xyz') + plugin.settings.set('assistant_id', 'zoom.master@megacorp.xyz') + return plugin + + +@pytest.fixture +def create_meeting(create_user, dummy_event, db, zoom_plugin): + def _create_meeting(name='New Room'): + user_joe = create_user(1, email='don.orange@megacorp.xyz') + + vc_room = VCRoom( + type='zoom', + status=VCRoomStatus.created, + name=name, + created_by_id=0, + data={ + 'description': 'something something', + 'password': '1234', + 'host': user_joe.identifier, + 'meeting_type': 'meeting', + 'mute_host_video': False, + 'mute_audio': False, + 'mute_participant_video': False, + 'waiting_room': False + } + ) + VCRoomEventAssociation(linked_event=dummy_event, vc_room=vc_room, link_type=VCRoomLinkType.event, data={}) + db.session.flush() + zoom_plugin.create_room(vc_room, dummy_event) + return vc_room + return _create_meeting + + +@pytest.fixture +def zoom_api(create_user, mocker): + """Mock some Zoom API endpoints.""" + api_create_meeting = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.create_meeting') + api_create_meeting.return_value = { + 'id': '12345abc', + 'join_url': 'https://example.com/kitties', + 'start_url': 'https://example.com/puppies', + 'password': '1234', + 'host_id': 'don.orange@megacorp.xyz', + 'topic': 'New Room', + 'agenda': 'something something', + 'settings': { + 'host_video': True, + 'mute_upon_entry': False, + 'participant_video': True, + 'waiting_room': False + } + } + + api_update_meeting = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.update_meeting') + api_update_meeting.return_value = { + + } + + create_user(1, email='don.orange@megacorp.xyz') + + api_get_user = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.get_user') + api_get_user.return_value = { + 'id': '7890abcd', + 'email': 'don.orange@megacorp.xyz' + } + + api_get_meeting = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.get_meeting') + api_get_meeting.return_value = api_create_meeting.return_value + + api_get_assistants = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.get_assistants_for_user') + api_get_assistants.return_value = { + 'assistants': [{'email': 'zoom.master@megacorp.xyz'}] + } + + return { + 'create_meeting': api_create_meeting, + 'get_meeting': api_get_meeting, + 'update_meeting': api_update_meeting, + 'get_user': api_get_user, + 'get_assistants': api_get_assistants + } + + +def test_room_creation(create_meeting, zoom_api): + vc_room = create_meeting() + assert vc_room.data['url'] == 'https://example.com/kitties' + assert vc_room.data['host'] == 'User:1' + assert zoom_api['create_meeting'].called + assert zoom_api['get_assistants'].called + + +def test_host_change(create_user, mocker, create_meeting, zoom_plugin, zoom_api, request_context): + notify_new_host = mocker.patch('indico_vc_zoom.plugin.notify_new_host') + + create_user(2, email='joe.bidon@megacorp.xyz') + vc_room = create_meeting() + + assert vc_room.data['host'] == 'User:1' + assert not vc_room.data['mute_participant_video'] + assert zoom_api['create_meeting'].called + assert zoom_api['get_assistants'].called + + vc_room.data['host'] = 'User:2' + vc_room.data['description'] = 'something else' + zoom_plugin.update_room(vc_room, vc_room.events[0].event) + + assert notify_new_host.called + assert zoom_api['update_meeting'].call_args == (('12345abc', { + 'schedule_for': 'joe.bidon@megacorp.xyz', + 'agenda': 'something else' + }),) diff --git a/vc_zoom/tests/task_test.py b/vc_zoom/tests/task_test.py deleted file mode 100644 index 06f10b4..0000000 --- a/vc_zoom/tests/task_test.py +++ /dev/null @@ -1,22 +0,0 @@ - -from datetime import datetime - -import pytest -from pytz import utc - -from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomStatus - - -@pytest.fixture -def create_dummy_room(db, dummy_user): - """Returns a callable which lets you create dummy Zoom room occurrences""" - pass - - -def test_room_cleanup(create_event, create_dummy_room, freeze_time, db): - """Test that 'old' Zoom rooms are correctly detected""" - freeze_time(datetime(2015, 2, 1)) - - pass - - assert {r.id for r in find_old_zoom_rooms(180)} == {2, 3, 5} From 17b07e39d3e6ea8784d65eb45a4c176611ccf1af Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 16:46:52 +0100 Subject: [PATCH 22/94] VC/Zoom: Add missing license headers --- vc_zoom/indico_vc_zoom/__init__.py | 7 +++++++ vc_zoom/indico_vc_zoom/api/__init__.py | 7 +++++++ vc_zoom/indico_vc_zoom/api/client.py | 7 +++++++ vc_zoom/indico_vc_zoom/blueprint.py | 7 +++++++ vc_zoom/indico_vc_zoom/cli.py | 7 ++++++- vc_zoom/indico_vc_zoom/client/index.js | 2 +- vc_zoom/indico_vc_zoom/controllers.py | 7 ++++++- vc_zoom/indico_vc_zoom/forms.py | 7 +++++++ vc_zoom/indico_vc_zoom/http_api.py | 2 -- vc_zoom/indico_vc_zoom/notifications.py | 7 +++++++ vc_zoom/indico_vc_zoom/plugin.py | 7 +++++++ vc_zoom/indico_vc_zoom/util.py | 7 +++++++ 12 files changed, 69 insertions(+), 5 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/__init__.py b/vc_zoom/indico_vc_zoom/__init__.py index 823742f..c99356c 100644 --- a/vc_zoom/indico_vc_zoom/__init__.py +++ b/vc_zoom/indico_vc_zoom/__init__.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals from indico.util.i18n import make_bound_gettext diff --git a/vc_zoom/indico_vc_zoom/api/__init__.py b/vc_zoom/indico_vc_zoom/api/__init__.py index bd7f914..b040413 100644 --- a/vc_zoom/indico_vc_zoom/api/__init__.py +++ b/vc_zoom/indico_vc_zoom/api/__init__.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from .client import ZoomIndicoClient, ZoomClient diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index c8cf130..cd358b1 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import absolute_import, unicode_literals import time diff --git a/vc_zoom/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py index bcb7103..15f8ac6 100644 --- a/vc_zoom/indico_vc_zoom/blueprint.py +++ b/vc_zoom/indico_vc_zoom/blueprint.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals from indico.core.plugins import IndicoPluginBlueprint diff --git a/vc_zoom/indico_vc_zoom/cli.py b/vc_zoom/indico_vc_zoom/cli.py index b414b30..3f6a73a 100644 --- a/vc_zoom/indico_vc_zoom/cli.py +++ b/vc_zoom/indico_vc_zoom/cli.py @@ -1,4 +1,9 @@ - +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. from __future__ import unicode_literals diff --git a/vc_zoom/indico_vc_zoom/client/index.js b/vc_zoom/indico_vc_zoom/client/index.js index 361049b..d773b3b 100644 --- a/vc_zoom/indico_vc_zoom/client/index.js +++ b/vc_zoom/indico_vc_zoom/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2019 CERN +// Copyright (C) 2020 CERN and ENEA // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index 0a0c8c1..d95bb87 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -1,4 +1,9 @@ - +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. from __future__ import unicode_literals diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 10ed183..f4e6ebe 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals from flask import session diff --git a/vc_zoom/indico_vc_zoom/http_api.py b/vc_zoom/indico_vc_zoom/http_api.py index 7c53d69..d730699 100644 --- a/vc_zoom/indico_vc_zoom/http_api.py +++ b/vc_zoom/indico_vc_zoom/http_api.py @@ -1,5 +1,3 @@ - - from flask import request from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomStatus diff --git a/vc_zoom/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py index f04885e..0a544aa 100644 --- a/vc_zoom/indico_vc_zoom/notifications.py +++ b/vc_zoom/indico_vc_zoom/notifications.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals from indico.web.flask.templating import get_template_module diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 14f1f4c..a706133 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals from flask import flash, session diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 087f35c..b4d0ac8 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals import random From 33c154807e349fdae5031e3c04271e3e928de194 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 10 Nov 2020 16:48:08 +0100 Subject: [PATCH 23/94] VC/Zoom: Remove unnecessary HTTP API hook --- vc_zoom/indico_vc_zoom/http_api.py | 49 ------------------------------ vc_zoom/indico_vc_zoom/plugin.py | 3 -- 2 files changed, 52 deletions(-) delete mode 100644 vc_zoom/indico_vc_zoom/http_api.py diff --git a/vc_zoom/indico_vc_zoom/http_api.py b/vc_zoom/indico_vc_zoom/http_api.py deleted file mode 100644 index d730699..0000000 --- a/vc_zoom/indico_vc_zoom/http_api.py +++ /dev/null @@ -1,49 +0,0 @@ -from flask import request - -from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomStatus -from indico.web.http_api.hooks.base import HTTPAPIHook - - -class DeleteVCRoomAPI(HTTPAPIHook): - PREFIX = 'api' - TYPES = ('deletevcroom',) - RE = r'zoom' - GUEST_ALLOWED = False - VALID_FORMATS = ('json',) - COMMIT = True - HTTP_POST = True - - def _has_access(self, user): - from indico_vc_zoom.plugin import ZoomPlugin - return user in ZoomPlugin.settings.acls.get('managers') - - def _getParams(self): - super(DeleteVCRoomAPI, self)._getParams() - self._room_ids = map(int, request.form.getlist('rid')) - - def api_deletevcroom(self, user): - from indico_vc_zoom.plugin import ZoomPlugin - from indico_vc_zoom.api import APIException - - success = [] - failed = [] - not_in_db = [] - - for rid in self._room_ids: - room = VCRoom.query.filter(VCRoom.type == 'zoom', - VCRoom.status == VCRoomStatus.created, - VCRoom.data.contains({'zoom_id': str(rid)})).first() - if not room: - not_in_db.append(rid) - continue - try: - room.plugin.delete_meeting(room, None) - except APIException: - failed.append(rid) - ZoomPlugin.logger.exception('Could not delete VC room %s', room) - else: - room.status = VCRoomStatus.deleted - success.append(rid) - ZoomPlugin.logger.info('%s deleted', room) - - return {'success': success, 'failed': failed, 'missing': not_in_db} diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index a706133..3d83ab7 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -28,14 +28,12 @@ from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent from indico.util.user import principal_from_identifier from indico.web.forms.fields.simple import IndicoPasswordField from indico.web.forms.widgets import CKEditorWidget, SwitchWidget -from indico.web.http_api.hooks.base import HTTPAPIHook from indico_vc_zoom import _ from indico_vc_zoom.api import ZoomIndicoClient from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm -from indico_vc_zoom.http_api import DeleteVCRoomAPI from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_random_password, get_schedule_args, update_zoom_meeting) @@ -105,7 +103,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): self.inject_bundle('main.js', WPSimpleEventDisplay) self.inject_bundle('main.js', WPVCEventPage) self.inject_bundle('main.js', WPVCManageEvent) - HTTPAPIHook.register(DeleteVCRoomAPI) @property def default_settings(self): From dac1ba02b94e0fb176a2d52960a8588888e33a17 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 12 Nov 2020 20:43:23 +0100 Subject: [PATCH 24/94] VC/Zoom: add webhook to update meetings --- vc_zoom/indico_vc_zoom/blueprint.py | 3 ++- vc_zoom/indico_vc_zoom/controllers.py | 35 ++++++++++++++++++++++++++- vc_zoom/indico_vc_zoom/plugin.py | 4 +++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py index 15f8ac6..93eb4d9 100644 --- a/vc_zoom/indico_vc_zoom/blueprint.py +++ b/vc_zoom/indico_vc_zoom/blueprint.py @@ -9,7 +9,7 @@ from __future__ import unicode_literals from indico.core.plugins import IndicoPluginBlueprint -from indico_vc_zoom.controllers import RHRoomHost +from indico_vc_zoom.controllers import RHRoomHost, RHWebhook blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') @@ -19,3 +19,4 @@ blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') # includes the service and normalization skips values provided in 'defaults' blueprint.add_url_rule('/event//manage/videoconference/zoom//room-host', 'set_room_host', RHRoomHost, methods=('POST',)) +blueprint.add_url_rule('/api/plugin/zoom/webhook', 'webhook', RHWebhook, methods=('POST',)) diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index d95bb87..57586dc 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -7,12 +7,18 @@ from __future__ import unicode_literals -from flask import flash, jsonify, session +from flask import flash, jsonify, request, session +from flask_pluginengine import current_plugin +from webargs import fields +from webargs.flaskparser import use_kwargs from indico.core.db import db from indico.modules.vc.controllers import RHVCSystemEventBase from indico.modules.vc.exceptions import VCRoomError +from indico.modules.vc.models.vc_rooms import VCRoom +from indico.web.rh import RH from indico.util.i18n import _ +from werkzeug.exceptions import Forbidden class RHRoomHost(RHVCSystemEventBase): @@ -29,3 +35,30 @@ class RHRoomHost(RHVCSystemEventBase): flash(_("You are now the host of room '{room.name}'".format(room=self.vc_room)), 'success') result['success'] = True return jsonify(result) + + +class RHWebhook(RH): + CSRF_ENABLED = False + + def _check_access(self): + token = request.headers.get('Authorization') + expected_token = current_plugin.settings.get('webhook_token') + if not expected_token or not token or token != expected_token: + raise Forbidden + + @use_kwargs({ + 'event': fields.String(), + 'payload': fields.Dict() + }) + def _process(self, event, payload): + meeting_id = payload['object']['id'] + vc_room = VCRoom.query.filter(VCRoom.data.contains({'zoom_id': meeting_id})).first() + + if not vc_room: + current_plugin.logger.warning('Action for unhandled Zoom room: %s', meeting_id) + return + + if event in {'meeting.updated', 'webinar.updated', 'meeting.deleted', 'webinar.deleted'}: + current_plugin.refresh_room(vc_room, None) + else: + current_plugin.logger.warning('Unhandled Zoom webhook payload: %s', event) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 3d83ab7..64b6e7a 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -44,6 +44,9 @@ class PluginSettingsForm(VCPluginSettingsFormBase): api_secret = IndicoPasswordField(_('API Secret'), [DataRequired()], toggle=True) + webhook_token = IndicoPasswordField(_('Webhook Token'), toggle=True, + description=_("Specify Zoom's webhook token if you want live updates")) + email_domains = StringField(_('E-mail domains'), [DataRequired()], description=_("Comma-separated list of e-mail domains which can use the Zoom API.")) @@ -110,6 +113,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'assistant_id': config.SUPPORT_EMAIL, 'api_key': '', 'api_secret': '', + 'webhook_token': '', 'email_domains': '', 'mute_host_video': True, 'mute_audio': True, From 5fca92553d25b87cfc8b39a657685f7c4dad83fb Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 12 Nov 2020 20:45:10 +0100 Subject: [PATCH 25/94] VC/Zoom: update missing fields --- vc_zoom/indico_vc_zoom/plugin.py | 14 +++++++++++++- vc_zoom/indico_vc_zoom/templates/info_box.html | 2 ++ .../templates/manage_event_info_box.html | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 64b6e7a..c2f6ec2 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -264,6 +264,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): kwargs.update({ 'topic': vc_room.name, + 'agenda': vc_room.data['description'], 'password': gen_random_password(), 'timezone': event.timezone, 'settings': settings @@ -321,6 +322,9 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name + if vc_room.data['description'] != zoom_meeting['agenda']: + changes['agenda'] = vc_room.data['description'] + zoom_meeting_settings = zoom_meeting['settings'] if vc_room.data['mute_host_video'] == zoom_meeting_settings['host_video']: changes.setdefault('settings', {})['host_video'] = not vc_room.data['mute_host_video'] @@ -341,9 +345,17 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): zoom_meeting = fetch_zoom_meeting(vc_room, is_webinar=is_webinar) vc_room.name = zoom_meeting['topic'] vc_room.data.update({ + 'description': zoom_meeting['agenda'], 'url': zoom_meeting['join_url'], 'public_url': zoom_meeting['join_url'].split('?')[0], - 'zoom_id': zoom_meeting['id'] + 'zoom_id': zoom_meeting['id'], + 'password': zoom_meeting['password'], + 'mute_host_video': zoom_meeting['settings']['host_video'], + + # these options will be empty for webinars + 'mute_audio': zoom_meeting['settings'].get('mute_upon_entry'), + 'mute_participant_video': not zoom_meeting['settings'].get('participant_video'), + 'waiting_room': zoom_meeting['settings'].get('waiting_room') }) flag_modified(vc_room, 'data') diff --git a/vc_zoom/indico_vc_zoom/templates/info_box.html b/vc_zoom/indico_vc_zoom/templates/info_box.html index 376b442..a60d9cd 100644 --- a/vc_zoom/indico_vc_zoom/templates/info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/info_box.html @@ -4,6 +4,8 @@
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    +
    {% trans %}Description{% endtrans %}
    +
    {{ vc_room.data.description }}
    {% if host %}
    {% trans %}Host{% endtrans %}
    {{ (host|decodeprincipal).full_name }}
    diff --git a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html index ebbffcf..ef6bab5 100644 --- a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html @@ -5,6 +5,8 @@
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    +
    {% trans %}Description{% endtrans %}
    +
    {{ vc_room.data.description }}
    {% trans %}Host{% endtrans %}
    {{ (host|decodeprincipal).full_name }} From de775861a6f47e35763b17b313bda3970291a357 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 12 Nov 2020 20:45:23 +0100 Subject: [PATCH 26/94] VC/Zoom: generate number-only passwords --- vc_zoom/indico_vc_zoom/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index b4d0ac8..cb4ef21 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -40,8 +40,8 @@ def find_enterprise_email(user): def gen_random_password(): - """Generate a random 10-character-long alphanumeric string.""" - return ''.join(random.sample(string.ascii_lowercase + string.ascii_uppercase + string.digits, 10)) + """Generate a random 8-character-long numeric string.""" + return ''.join(random.choice(string.digits) for _ in range(8)) def fetch_zoom_meeting(vc_room, client=None, is_webinar=False): From 9f850cc65964ba554fee63df3bbc2675c898fd2c Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 10:05:35 +0100 Subject: [PATCH 27/94] VC/Zoom: set dependency versions --- vc_zoom/setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index 62f4b20..0075ed7 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -15,8 +15,8 @@ setup( zip_safe=False, include_package_data=True, install_requires=[ - 'indico>=2', - 'PyJWT' + 'indico>=2.3.2.dev0', + 'PyJWT<2' ], classifiers=[ 'Environment :: Plugins', From edb155ead8c95d8e1bbd2e3a07bdbbef217d15dc Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 10:12:51 +0100 Subject: [PATCH 28/94] VC/Vidyo: remove leftover import --- vc_vidyo/indico_vc_vidyo/util.py | 1 - 1 file changed, 1 deletion(-) diff --git a/vc_vidyo/indico_vc_vidyo/util.py b/vc_vidyo/indico_vc_vidyo/util.py index 882b4f1..450083e 100644 --- a/vc_vidyo/indico_vc_vidyo/util.py +++ b/vc_vidyo/indico_vc_vidyo/util.py @@ -12,7 +12,6 @@ import re from flask_multipass import IdentityRetrievalFailed from indico.core.auth import multipass -from indico.core.db import db from indico.modules.auth import Identity from indico.modules.users import User From 5436b29767cfafd77f66c8791f4857de61eba71c Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 10:23:17 +0100 Subject: [PATCH 29/94] VC/Zoom: set correct version, setup.py improvements --- vc_zoom/setup.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index 0075ed7..58af122 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -5,14 +5,15 @@ from setuptools import find_packages, setup setup( name='indico-plugin-vc-zoom', - version='0.3-dev', + version='2.3-dev', description='Zoom video-conferencing plugin for Indico', - url='', + url='https://github.com/indico/indico-plugins', license='MIT', - author='Giovanni Mariano - ENEA', - author_email='giovanni.mariano@enea.it', + author='Giovanni Mariano (ENEA) and Indico Team (CERN)', + author_email='indico-team@cern.ch', packages=find_packages(), zip_safe=False, + platforms='any', include_package_data=True, install_requires=[ 'indico>=2.3.2.dev0', From 4f058327ca8b0766ad4780a9131db21b7ce1a65d Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 10:38:53 +0100 Subject: [PATCH 30/94] VC/Zoom: update pytest.ini --- vc_zoom/pytest.ini | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vc_zoom/pytest.ini b/vc_zoom/pytest.ini index cba3f73..b7ae65f 100644 --- a/vc_zoom/pytest.ini +++ b/vc_zoom/pytest.ini @@ -3,5 +3,10 @@ addopts = -rsfEw --cov . --cov-report html --no-cov-on-fail ; only check for tests in suffixed files python_files = *_test.py -; we need the livesync plugin to be loaded +; we need the vc_zoom plugin to be loaded indico_plugins = vc_zoom +; fail if there are warnings, but ignore ones that are likely just noise +filterwarnings = + error + ignore::sqlalchemy.exc.SAWarning + ignore::UserWarning From efc71c9fbf47d5c51339359919cbe7b092ad0ce8 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 11:02:21 +0100 Subject: [PATCH 31/94] VC/Zoom: add instructions for webhook configuration --- vc_zoom/README.md | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index f3e3e6e..c785dea 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -18,7 +18,22 @@ https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate#r ) property in the Zoom API). The *assistant user* owns every Zoom meeting, with the `scheduled_for` property being used to grant the required privileges to the desired hosts. -## Configuration +## Zoom App Configuration + +### Webhook (optional) + +**URL:** `https://yourserver/api/plugin/zoom/webhook` + +(write down the "Verification Token", as you will need it in the plugin configuration below) + +Select the following "Event types": + * `Meeting has been updated` + * `Meeting has been deleted` + * `Webinar has been updated` + * `Webinar has been deleted` + + +## Plugin Configuration These are the most relevant configuration options: @@ -26,8 +41,10 @@ These are the most relevant configuration options: * **E-mail domains** - Comma-separated list of e-mail domains which can be used for the Zoom API (e.g. `cern.ch`) * **Asistant Zoom ID** - Zoom ID (or e-mail) of the account which shall be used as an assistant to all hosts and shall own all meetings + * **Webhook token** (optional) - the token which Zoom requests will authenticate with (get it from Zoom Marketplace) -### Zoom API key/secret + +### Zoom API key/secret (JWT) To obtain API key and API secret, please visit [https://marketplace.zoom.us/docs/guides/auth/jwt](https://marketplace.zoom.us/docs/guides/auth/jwt). From d208f622de2ad3f6aaa0df211b63ca8caf31850e Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 15:34:11 +0100 Subject: [PATCH 32/94] VC/Zoom: password -> passcode, make it editable --- vc_zoom/indico_vc_zoom/forms.py | 16 ++++++++++------ vc_zoom/indico_vc_zoom/plugin.py | 11 +++++++---- vc_zoom/indico_vc_zoom/templates/buttons.html | 2 +- vc_zoom/indico_vc_zoom/templates/info_box.html | 2 +- .../templates/manage_event_info_box.html | 2 +- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index f4e6ebe..4834e93 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -8,7 +8,7 @@ from __future__ import unicode_literals from flask import session -from wtforms.fields.core import BooleanField +from wtforms.fields.core import BooleanField, StringField from wtforms.fields.simple import TextAreaField from wtforms.validators import DataRequired, ValidationError @@ -16,15 +16,15 @@ from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase from indico.util.user import principal_from_identifier from indico.web.forms.base import generated_data from indico.web.forms.fields import IndicoRadioField, PrincipalField -from indico.web.forms.validators import HiddenUnless +from indico.web.forms.validators import HiddenUnless, IndicoRegexp from indico.web.forms.widgets import SwitchWidget from indico_vc_zoom import _ class VCRoomAttachForm(VCRoomAttachFormBase): - password_visibility = IndicoRadioField(_("Password visibility"), - description=_("Who should be able to know this meeting's password"), + password_visibility = IndicoRadioField(_("Passcode visibility"), + description=_("Who should be able to know this meeting's passcode"), orientation='horizontal', choices=[ ('everyone', _('Everyone')), @@ -52,8 +52,12 @@ class VCRoomForm(VCRoomFormBase): host_user = PrincipalField(_("User"), [HiddenUnless('host_choice', 'someone_else'), DataRequired()]) - password_visibility = IndicoRadioField(_("Password visibility"), - description=_("Who should be able to know this meeting's password"), + password = StringField(_("Passcode"), + [DataRequired(), IndicoRegexp(r'^\d{8,}$')], + description=_("Meeting passcode (min. 8 digits)")) + + password_visibility = IndicoRadioField(_("Passcode visibility"), + description=_("Who should be able to know this meeting's passcode"), orientation='horizontal', choices=[ ('everyone', _('Everyone')), diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index c2f6ec2..47d1af5 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -149,7 +149,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # webinar hosts cannot be changed through the API form.host_choice.render_kw = {'disabled': True} form.host_user.render_kw = {'disabled': True} - + else: + form.password.data = gen_random_password() return form def _extend_indico_cli(self, sender, **kwargs): @@ -185,7 +186,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def update_data_vc_room(self, vc_room, data, is_new=False): super(ZoomPlugin, self).update_data_vc_room(vc_room, data) - fields = {'description'} + fields = {'description', 'password'} if data['meeting_type'] == 'webinar': fields |= {'mute_host_video'} if is_new: @@ -265,7 +266,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): kwargs.update({ 'topic': vc_room.name, 'agenda': vc_room.data['description'], - 'password': gen_random_password(), + 'password': vc_room.data['password'], 'timezone': event.timezone, 'settings': settings }) @@ -283,7 +284,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'url': meeting_obj['join_url'], 'public_url': meeting_obj['join_url'].split('?')[0], 'start_url': meeting_obj['start_url'], - 'password': meeting_obj['password'], 'host': host.identifier }) @@ -325,6 +325,9 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if vc_room.data['description'] != zoom_meeting['agenda']: changes['agenda'] = vc_room.data['description'] + if vc_room.data['password'] != zoom_meeting['password']: + changes['password'] = vc_room.data['password'] + zoom_meeting_settings = zoom_meeting['settings'] if vc_room.data['mute_host_video'] == zoom_meeting_settings['host_video']: changes.setdefault('settings', {})['host_video'] = not vc_room.data['mute_host_video'] diff --git a/vc_zoom/indico_vc_zoom/templates/buttons.html b/vc_zoom/indico_vc_zoom/templates/buttons.html index c5cef9a..7a10064 100644 --- a/vc_zoom/indico_vc_zoom/templates/buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/buttons.html @@ -7,7 +7,7 @@ {% elif event_vc_room.data.password_visibility == 'no_one' %} {% trans %}Join{% endtrans %} diff --git a/vc_zoom/indico_vc_zoom/templates/info_box.html b/vc_zoom/indico_vc_zoom/templates/info_box.html index a60d9cd..c4627eb 100644 --- a/vc_zoom/indico_vc_zoom/templates/info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/info_box.html @@ -12,7 +12,7 @@ {% endif %} {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or (session.user and event_vc_room.data.password_visibility == 'logged_in') %} -
    {% trans %}Password{% endtrans %}
    +
    {% trans %}Passcode{% endtrans %}
    {{ vc_room.data.password }}
    {% endif %} {% if event_vc_room.data.show_autojoin %} diff --git a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html index ef6bab5..d1a0d71 100644 --- a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html @@ -24,7 +24,7 @@ {% trans %}Session{% endtrans %}: {{ obj.full_title }} {% endif %}
    -
    {% trans %}Password{% endtrans %}
    +
    {% trans %}Passcode{% endtrans %}
    {{ vc_room.data.password }}
    {% trans %}Zoom URL{% endtrans %}
    From 24bde98bcf56f44f16691aad22db4fe6d17c1c40 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 15:36:54 +0100 Subject: [PATCH 33/94] VC/Zoom: fix indentation in e-mail text --- .../templates/emails/remote_deleted.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/templates/emails/remote_deleted.html b/vc_zoom/indico_vc_zoom/templates/emails/remote_deleted.html index 1c0c580..31904df 100644 --- a/vc_zoom/indico_vc_zoom/templates/emails/remote_deleted.html +++ b/vc_zoom/indico_vc_zoom/templates/emails/remote_deleted.html @@ -5,12 +5,12 @@ {%- endblock %} {% block header -%} -

    - The Zoom room "{{ vc_room.name }}" has been deleted from the Zoom server since it has not been used by any recent event. -

    -

    - You won't be able to attach it to any future events. If you need to do so, please create a new room. -

    +

    + The Zoom room "{{ vc_room.name }}" has been deleted from the Zoom server since it has not been used by any recent event. +

    +

    + You won't be able to attach it to any future events. If you need to do so, please create a new room. +

    {% block custom_footer %}{% endblock %} {%- endblock %} From ced6c9ec67eeeaf255a2817c1c0c75fe8e8d8a10 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 15:42:43 +0100 Subject: [PATCH 34/94] VC/Zoom: deleted unnecessary template --- vc_zoom/indico_vc_zoom/templates/emails/deleted.html | 1 - 1 file changed, 1 deletion(-) delete mode 100644 vc_zoom/indico_vc_zoom/templates/emails/deleted.html diff --git a/vc_zoom/indico_vc_zoom/templates/emails/deleted.html b/vc_zoom/indico_vc_zoom/templates/emails/deleted.html deleted file mode 100644 index a67c1f1..0000000 --- a/vc_zoom/indico_vc_zoom/templates/emails/deleted.html +++ /dev/null @@ -1 +0,0 @@ -{% extends 'vc/emails/deleted.html' %} From c536f742eb9b45d430285373ea15548cc4257f31 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 15:45:55 +0100 Subject: [PATCH 35/94] VC/Zoom: fix docstring --- vc_zoom/indico_vc_zoom/api/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index cd358b1..0f93962 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -16,7 +16,7 @@ from pytz import utc def format_iso_dt(d): - """Convertdatetime objects to a UTC-based string. + """Convert a datetime objects to a UTC-based string. :param d: The :class:`datetime.datetime` to convert to a string :returns: The string representation of the date From 4b00c737177565f02295f884a930a85c774241ac Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 15:55:39 +0100 Subject: [PATCH 36/94] VC/Zoom: hide description if there's none --- vc_zoom/indico_vc_zoom/templates/info_box.html | 6 ++++-- vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/templates/info_box.html b/vc_zoom/indico_vc_zoom/templates/info_box.html index c4627eb..e05b398 100644 --- a/vc_zoom/indico_vc_zoom/templates/info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/info_box.html @@ -4,8 +4,10 @@
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    -
    {% trans %}Description{% endtrans %}
    -
    {{ vc_room.data.description }}
    + {% if vc_room.data.description %} +
    {% trans %}Description{% endtrans %}
    +
    {{ vc_room.data.description }}
    + {% endif %} {% if host %}
    {% trans %}Host{% endtrans %}
    {{ (host|decodeprincipal).full_name }}
    diff --git a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html index d1a0d71..add3d5a 100644 --- a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html @@ -5,8 +5,10 @@
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    -
    {% trans %}Description{% endtrans %}
    -
    {{ vc_room.data.description }}
    + {% if vc_room.data.description %} +
    {% trans %}Description{% endtrans %}
    +
    {{ vc_room.data.description }}
    + {% endif %}
    {% trans %}Host{% endtrans %}
    {{ (host|decodeprincipal).full_name }} From dd8908763eeb17f24b2b149622428b032886ca19 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 16:30:24 +0100 Subject: [PATCH 37/94] VC/Zoom: reinstate "make me host" feature --- vc_zoom/indico_vc_zoom/blueprint.py | 8 +++-- vc_zoom/indico_vc_zoom/client/index.js | 33 ++++++++----------- vc_zoom/indico_vc_zoom/controllers.py | 7 ++-- vc_zoom/indico_vc_zoom/templates/buttons.html | 16 +++++++++ .../templates/event_buttons.html | 3 +- 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py index 93eb4d9..93d723d 100644 --- a/vc_zoom/indico_vc_zoom/blueprint.py +++ b/vc_zoom/indico_vc_zoom/blueprint.py @@ -17,6 +17,10 @@ blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') # Room management # using any(zoom) instead of defaults since the event vc room locator # includes the service and normalization skips values provided in 'defaults' -blueprint.add_url_rule('/event//manage/videoconference/zoom//room-host', - 'set_room_host', RHRoomHost, methods=('POST',)) +blueprint.add_url_rule( + '/event//manage/videoconference///make-me-host', + 'make_me_host', + RHRoomHost, + methods=('POST',) +) blueprint.add_url_rule('/api/plugin/zoom/webhook', 'webhook', RHWebhook, methods=('POST',)) diff --git a/vc_zoom/indico_vc_zoom/client/index.js b/vc_zoom/indico_vc_zoom/client/index.js index d773b3b..60c2f37 100644 --- a/vc_zoom/indico_vc_zoom/client/index.js +++ b/vc_zoom/indico_vc_zoom/client/index.js @@ -5,30 +5,25 @@ // them and/or modify them under the terms of the MIT License; // see the LICENSE file for more details. -$(function() { +import {handleAxiosError, indicoAxios} from 'indico/utils/axios'; + +document.addEventListener('DOMContentLoaded', async () => { $('.vc-toolbar').dropdown({ positioning: { level1: {my: 'right top', at: 'right bottom', offset: '0px 0px'}, }, }); - $('.vc-toolbar .action-make-owner').click(function() { - const $this = $(this); - - $.ajax({ - url: $this.data('href'), - method: 'POST', - complete: IndicoUI.Dialogs.Util.progress(), + document.querySelectorAll('.vc-toolbar .action-make-host').forEach(elem => { + elem.addEventListener('click', async () => { + const killProgress = IndicoUI.Dialogs.Util.progress(); + try { + await indicoAxios.post(elem.dataset.href); + window.location.reload(); + } catch (error) { + handleAxiosError(error); + killProgress(); + } }) - .done(function(result) { - if (handleAjaxError(result)) { - return; - } else { - location.reload(); - } - }) - .fail(function(error) { - handleAjaxError(error); - }); - }); + }) }); diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index 57586dc..43993b3 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals from flask import flash, jsonify, request, session from flask_pluginengine import current_plugin +from sqlalchemy.orm.attributes import flag_modified from webargs import fields from webargs.flaskparser import use_kwargs @@ -25,12 +26,12 @@ class RHRoomHost(RHVCSystemEventBase): def _process(self): result = {} self.vc_room.data['host'] = session.user.identifier + flag_modified(self.vc_room, 'data') try: self.plugin.update_room(self.vc_room, self.event) - except VCRoomError as err: - result['error'] = {'message': err.message} - result['success'] = False + except VCRoomError: db.session.rollback() + raise else: flash(_("You are now the host of room '{room.name}'".format(room=self.vc_room)), 'success') result['success'] = True diff --git a/vc_zoom/indico_vc_zoom/templates/buttons.html b/vc_zoom/indico_vc_zoom/templates/buttons.html index 7a10064..f64fcc5 100644 --- a/vc_zoom/indico_vc_zoom/templates/buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/buttons.html @@ -1,3 +1,19 @@ +{% macro render_make_me_owner(event, vc_room, event_vc_room, extra_classes='') %} + {% if session.user.identifier != vc_room.data['host'] and event.can_manage(session.user) %} + + + {% endif %} +{% endmacro %} + {% macro render_join_button(vc_room, event_vc_room, extra_classes="", is_manager=false) %} {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or (session.user and event_vc_room.data.password_visibility == 'logged_in') %} diff --git a/vc_zoom/indico_vc_zoom/templates/event_buttons.html b/vc_zoom/indico_vc_zoom/templates/event_buttons.html index fd9fcf1..401ef93 100644 --- a/vc_zoom/indico_vc_zoom/templates/event_buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/event_buttons.html @@ -1,6 +1,7 @@ {% extends 'vc/event_buttons.html' %} -{% from 'vc_zoom:buttons.html' import render_join_button %} +{% from 'vc_zoom:buttons.html' import render_join_button, render_make_me_owner %} {% block buttons %} {{ render_join_button(vc_room, event_vc_room, "i-button-small event-service-right-button join-button") }} + {{ render_make_me_owner(event, vc_room, event_vc_room, extra_classes="i-button-small") }} {% endblock %} From 56eeb2e85ba47885ea85027275410438dfe8f696 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 16:47:18 +0100 Subject: [PATCH 38/94] VC/Zoom: use correct SQLAlchemy API --- vc_zoom/indico_vc_zoom/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/cli.py b/vc_zoom/indico_vc_zoom/cli.py index 3f6a73a..f2907b7 100644 --- a/vc_zoom/indico_vc_zoom/cli.py +++ b/vc_zoom/indico_vc_zoom/cli.py @@ -24,7 +24,7 @@ def cli(): def rooms(status=None): """Lists all Zoom rooms""" - room_query = VCRoom.find(type='zoom') + room_query = VCRoom.query.filter_by(type='zoom') table_data = [['ID', 'Name', 'Status', 'Zoom ID']] if status: From a2c76a55f6dd29ab941d8adbebca3337a9711af3 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 13 Nov 2020 16:54:15 +0100 Subject: [PATCH 39/94] VC/Zoom: fix bug with merging --- vc_zoom/indico_vc_zoom/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 47d1af5..3682cb6 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -410,7 +410,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): for room in VCRoom.query.filter( VCRoom.type == self.service_name, VCRoom.data.contains({'host': source.identifier}) ): - room.data['host'] = target.id + room.data['host'] = target.identifier flag_modified(room, 'data') def get_notification_cc_list(self, action, vc_room, event): From 650ff3d3c7867f8d201879aceaa2ca8a3028b67b Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 17 Nov 2020 11:59:58 +0100 Subject: [PATCH 40/94] VC/Zoom: split config in sections --- vc_zoom/indico_vc_zoom/plugin.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 3682cb6..7b82199 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -40,6 +40,14 @@ from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_ class PluginSettingsForm(VCPluginSettingsFormBase): + _fieldsets = [ + ('API Credentials', ['api_key', 'api_secret', 'webhook_token']), + ('Zoom Account', ['email_domains', 'assistant_id']), + ('Room Settings', ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host', + 'waiting_room']), + ('Notifications', ['zoom_phone_link', 'creation_email_footer', 'send_host_url']) + ] + api_key = StringField(_('API Key'), [DataRequired()]) api_secret = IndicoPasswordField(_('API Secret'), [DataRequired()], toggle=True) From 717310d367539fa92a859d79f6716bfcb9fcead0 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 17 Nov 2020 20:34:56 +0100 Subject: [PATCH 41/94] VC/Zoom: add option to enable/disable webinars overall --- vc_zoom/indico_vc_zoom/forms.py | 11 +++++++---- vc_zoom/indico_vc_zoom/plugin.py | 17 ++++++++++++++--- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 4834e93..bc0e5ec 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -9,7 +9,7 @@ from __future__ import unicode_literals from flask import session from wtforms.fields.core import BooleanField, StringField -from wtforms.fields.simple import TextAreaField +from wtforms.fields.simple import HiddenField, TextAreaField from wtforms.validators import DataRequired, ValidationError from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase @@ -65,7 +65,6 @@ class VCRoomForm(VCRoomFormBase): ('no_one', _("No one"))]) mute_audio = BooleanField(_('Mute audio'), - [HiddenUnless('meeting_type', 'regular')], widget=SwitchWidget(), description=_('Participants will join the VC room muted by default ')) @@ -74,12 +73,10 @@ class VCRoomForm(VCRoomFormBase): description=_('The host will join the VC room with video disabled')) mute_participant_video = BooleanField(_('Mute video (participants)'), - [HiddenUnless('meeting_type', 'regular')], widget=SwitchWidget(), description=_('Participants will join the VC room with video disabled')) waiting_room = BooleanField(_('Waiting room'), - [HiddenUnless('meeting_type', 'regular')], widget=SwitchWidget(), description=_('Participants may be kept in a waiting room by the host')) @@ -93,6 +90,12 @@ class VCRoomForm(VCRoomFormBase): defaults.host_user = None if host == session.user else host super(VCRoomForm, self).__init__(*args, **kwargs) + if defaults.meeting_type is None: + del self.meeting_type + else: + for f in {self.mute_audio, self.mute_participant_video, self.waiting_room}: + f.validators = [HiddenUnless('meeting_type', 'regular')] + @generated_data def host(self): if self.host_choice is None: diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 7b82199..bd19ed8 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -42,7 +42,7 @@ from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_ class PluginSettingsForm(VCPluginSettingsFormBase): _fieldsets = [ ('API Credentials', ['api_key', 'api_secret', 'webhook_token']), - ('Zoom Account', ['email_domains', 'assistant_id']), + ('Zoom Account', ['email_domains', 'assistant_id', 'allow_webinars']), ('Room Settings', ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host', 'waiting_room']), ('Notifications', ['zoom_phone_link', 'creation_email_footer', 'send_host_url']) @@ -62,6 +62,10 @@ class PluginSettingsForm(VCPluginSettingsFormBase): description=_('Account to be used as owner of all rooms. It will get "assistant" ' 'privileges on all accounts for which it books rooms')) + allow_webinars = BooleanField(_('Allow Webinars'), + widget=SwitchWidget(), + description=_('Allow webinars to be created through Indico')) + mute_audio = BooleanField(_('Mute audio'), widget=SwitchWidget(), description=_('Participants will join the VC room muted by default ')) @@ -123,6 +127,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'api_secret': '', 'webhook_token': '', 'email_domains': '', + 'allow_webinars': True, 'mute_host_video': True, 'mute_audio': True, 'mute_participant_video': True, @@ -195,6 +200,12 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def update_data_vc_room(self, vc_room, data, is_new=False): super(ZoomPlugin, self).update_data_vc_room(vc_room, data) fields = {'description', 'password'} + + if is_new: + # in a freshly-created VCRoom, we may end up not getting a meeting_type from the form + # (i.e. webinars are disabled) + data.setdefault('meeting_type', 'regular') + if data['meeting_type'] == 'webinar': fields |= {'mute_host_video'} if is_new: @@ -243,7 +254,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # get the object that this booking is linked to vc_room_assoc = vc_room.events[0] link_obj = vc_room_assoc.link_object - is_webinar = vc_room.data['meeting_type'] == 'webinar' + is_webinar = vc_room.data.setdefault('meeting_type', 'regular') == 'webinar' scheduling_args = get_schedule_args(link_obj) if link_obj.start_dt else {} self._check_indico_is_assistant(host_email) @@ -391,7 +402,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): def get_vc_room_form_defaults(self, event): defaults = super(ZoomPlugin, self).get_vc_room_form_defaults(event) defaults.update({ - 'meeting_type': 'regular', + 'meeting_type': 'regular' if self.settings.get('allow_webinars') else None, 'mute_audio': self.settings.get('mute_audio'), 'mute_host_video': self.settings.get('mute_host_video'), 'mute_participant_video': self.settings.get('mute_participant_video'), From 8cc8267e0e318f7278a80659c2aaf84800a07272 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 17 Nov 2020 20:35:16 +0100 Subject: [PATCH 42/94] VC/Zoom: fix initial value of host muting flag --- vc_zoom/indico_vc_zoom/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index bd19ed8..cf6a6b7 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -261,7 +261,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): try: settings = { - 'host_video': vc_room.data['mute_host_video'], + 'host_video': not vc_room.data['mute_host_video'], } kwargs = {} From 716fc30ac7c9d71dd701789fd25a55a08ee85425 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 18 Nov 2020 09:32:42 +0100 Subject: [PATCH 43/94] VC/Zoom: fix corner case in host user selection --- vc_zoom/indico_vc_zoom/forms.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index bc0e5ec..100cac9 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -100,7 +100,10 @@ class VCRoomForm(VCRoomFormBase): def host(self): if self.host_choice is None: return None - return session.user.identifier if self.host_choice.data == 'myself' else self.host_user.data.identifier + elif self.host_choice.data == 'myself': + return session.user.identifier + else: + return self.host_user.data.identifier if self.host_user.data else None def validate_host_user(self, field): if not field.data: From e56fed04bc65da804e5f99511ced20e2b144187f Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 18 Nov 2020 10:37:36 +0100 Subject: [PATCH 44/94] VC/Zoom: fix typo --- vc_zoom/indico_vc_zoom/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 100cac9..abc71e2 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -40,7 +40,7 @@ class VCRoomForm(VCRoomFormBase): skip_fields = advanced_fields | VCRoomFormBase.conditional_fields meeting_type = IndicoRadioField(_("Meeting Type"), - description=_("The type of Zoom meeting ot be created"), + description=_("The type of Zoom meeting to be created"), orientation='horizontal', choices=[ ('regular', _('Regular Meeting')), From f22d545dbc7bd07a84d6e1ed4dc2d64688c40e32 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 18 Nov 2020 14:53:46 +0100 Subject: [PATCH 45/94] VC/Zoom: code style improvements (review) Co-authored-by: Adrian Moennich --- vc_zoom/indico_vc_zoom/api/client.py | 31 ++++++++----------------- vc_zoom/indico_vc_zoom/cli.py | 4 ++-- vc_zoom/indico_vc_zoom/forms.py | 2 +- vc_zoom/indico_vc_zoom/notifications.py | 4 ++-- vc_zoom/indico_vc_zoom/util.py | 4 ++-- 5 files changed, 17 insertions(+), 28 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index 0f93962..9a9dba5 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -28,10 +28,7 @@ def _handle_response(resp, expected_code=200, expects_json=True): resp.raise_for_status() if resp.status_code != expected_code: raise HTTPError("Unexpected status code {}".format(resp.status_code), response=resp) - if expects_json: - return resp.json() - else: - return resp + return resp.json() if expects_json else resp class APIException(Exception): @@ -150,6 +147,8 @@ class UserComponent(BaseComponent): class ZoomClient(object): """Zoom REST API Python Client.""" + BASE_URI = "https://api.zoom.us/v2" + _components = { 'user': UserComponent, 'meeting': MeetingComponent, @@ -163,8 +162,6 @@ class ZoomClient(object): :param api_secret: the Zoom JWT API Secret :param timeout: the time out to use for API requests """ - BASE_URI = "https://api.zoom.us/v2" - # Setup the config details config = { "api_key": api_key, @@ -172,38 +169,33 @@ class ZoomClient(object): } # Instantiate the components - self.components = { - key: component(base_uri=BASE_URI, config=config, timeout=timeout) + key: component(base_uri=self.BASE_URI, config=config, timeout=timeout) for key, component in self._components.viewitems() } @property def meeting(self): """Get the meeting component.""" - return self.components.get("meeting") + return self.components['meeting'] @property def user(self): """Get the user component.""" - return self.components.get("user") + return self.components['user'] @property def webinar(self): - """Get the user component.""" - return self.components.get("webinar") + """Get the webinar component.""" + return self.components['webinar'] class ZoomIndicoClient(object): def __init__(self): - self._refresh_client() - - def _refresh_client(self): from indico_vc_zoom.plugin import ZoomPlugin - settings = ZoomPlugin.settings self.client = ZoomClient( - settings.get('api_key'), - settings.get('api_secret') + ZoomPlugin.settings.get('api_key'), + ZoomPlugin.settings.get('api_secret') ) def create_meeting(self, user_id, **kwargs): @@ -230,9 +222,6 @@ class ZoomIndicoClient(object): def delete_webinar(self, webinar_id): return _handle_response(self.client.webinar.delete(webinar_id), 204, expects_json=False) - def check_user_meeting_time(self, user_id, start_dt, end_dt): - pass - def get_user(self, user_id): return _handle_response(self.client.user.get(user_id)) diff --git a/vc_zoom/indico_vc_zoom/cli.py b/vc_zoom/indico_vc_zoom/cli.py index f2907b7..48c65e2 100644 --- a/vc_zoom/indico_vc_zoom/cli.py +++ b/vc_zoom/indico_vc_zoom/cli.py @@ -5,7 +5,7 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from __future__ import unicode_literals +from __future__ import print_function, unicode_literals import click from terminaltables import AsciiTable @@ -36,4 +36,4 @@ def rooms(status=None): table = AsciiTable(table_data) for col in (0, 3, 4): table.justify_columns[col] = 'right' - print table.table + print(table.table) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index abc71e2..704e4ee 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -9,7 +9,7 @@ from __future__ import unicode_literals from flask import session from wtforms.fields.core import BooleanField, StringField -from wtforms.fields.simple import HiddenField, TextAreaField +from wtforms.fields.simple import TextAreaField from wtforms.validators import DataRequired, ValidationError from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase diff --git a/vc_zoom/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py index 0a544aa..da45dc3 100644 --- a/vc_zoom/indico_vc_zoom/notifications.py +++ b/vc_zoom/indico_vc_zoom/notifications.py @@ -26,7 +26,7 @@ def notify_host_start_url(vc_room): ) email = make_email(to_list, template=template_module, html=True) - send_email(email, None, 'Zoom') + send_email(email) def notify_new_host(actor, vc_room): @@ -41,4 +41,4 @@ def notify_new_host(actor, vc_room): new_host = principal_from_identifier(vc_room.data['host']) email = make_email({new_host.email}, cc_list={actor.email}, template=template_module, html=True) - send_email(email, None, 'Zoom') + send_email(email) diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index cb4ef21..253d19b 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -29,12 +29,12 @@ def find_enterprise_email(user): :return: the e-mail address if it exists, otherwise `None` """ from indico_vc_zoom.plugin import ZoomPlugin - providers = [auth.strip() for auth in ZoomPlugin.settings.get('email_domains').split(',')] + domains = [auth.strip() for auth in ZoomPlugin.settings.get('email_domains').split(',')] result = UserEmail.query.filter( UserEmail.user == user, ~User.is_blocked, ~User.is_deleted, - db.or_(UserEmail.email.ilike("%%@{}".format(provider)) for provider in providers) + db.or_(UserEmail.email.ilike('%@{}'.format(domain)) for domain in domains) ).join(User).first() return result.email if result else None From ce9b1984d19512c378b82215e6567b8892c697b1 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 19 Nov 2020 09:54:48 +0100 Subject: [PATCH 46/94] VC/Zoom: get rid of possibly misleading default --- vc_zoom/indico_vc_zoom/plugin.py | 36 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index cf6a6b7..46d7726 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -18,7 +18,6 @@ from wtforms.fields.simple import StringField from wtforms.validators import DataRequired from indico.core import signals -from indico.core.config import config from indico.core.plugins import IndicoPlugin, render_plugin_template, url_for_plugin from indico.modules.events.views import WPSimpleEventDisplay from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase @@ -109,6 +108,22 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room_form = VCRoomForm vc_room_attach_form = VCRoomAttachForm friendly_name = 'Zoom' + default_settings = dict(VCPluginMixin.default_settings, **{ + 'assistant_id': '', + 'api_key': '', + 'api_secret': '', + 'webhook_token': '', + 'email_domains': '', + 'allow_webinars': True, + 'mute_host_video': True, + 'mute_audio': True, + 'mute_participant_video': True, + 'join_before_host': True, + 'waiting_room': False, + 'zoom_phone_link': None, + 'creation_email_footer': None, + 'send_host_url': False + }) def init(self): super(ZoomPlugin, self).init() @@ -119,25 +134,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): self.inject_bundle('main.js', WPVCEventPage) self.inject_bundle('main.js', WPVCManageEvent) - @property - def default_settings(self): - return dict(VCPluginMixin.default_settings, **{ - 'assistant_id': config.SUPPORT_EMAIL, - 'api_key': '', - 'api_secret': '', - 'webhook_token': '', - 'email_domains': '', - 'allow_webinars': True, - 'mute_host_video': True, - 'mute_audio': True, - 'mute_participant_video': True, - 'join_before_host': True, - 'waiting_room': False, - 'zoom_phone_link': None, - 'creation_email_footer': None, - 'send_host_url': False - }) - @property def logo_url(self): return url_for_plugin(self.name + '.static', filename='images/zoom_logo.png') From b110bbb4bcfb1a8b7cee7cce4f9380d76eba724b Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 19 Nov 2020 11:11:00 +0100 Subject: [PATCH 47/94] VC/Zoom: get rid of phone link --- vc_zoom/indico_vc_zoom/plugin.py | 7 +------ vc_zoom/indico_vc_zoom/templates/info_box.html | 11 ----------- .../templates/manage_event_info_box.html | 1 - 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 46d7726..4646910 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -13,7 +13,6 @@ from sqlalchemy.orm.attributes import flag_modified from werkzeug.exceptions import Forbidden, NotFound from wtforms.fields.core import BooleanField from wtforms.fields import TextAreaField -from wtforms.fields.html5 import URLField from wtforms.fields.simple import StringField from wtforms.validators import DataRequired @@ -44,7 +43,7 @@ class PluginSettingsForm(VCPluginSettingsFormBase): ('Zoom Account', ['email_domains', 'assistant_id', 'allow_webinars']), ('Room Settings', ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host', 'waiting_room']), - ('Notifications', ['zoom_phone_link', 'creation_email_footer', 'send_host_url']) + ('Notifications', ['creation_email_footer', 'send_host_url']) ] api_key = StringField(_('API Key'), [DataRequired()]) @@ -86,9 +85,6 @@ class PluginSettingsForm(VCPluginSettingsFormBase): widget=SwitchWidget(), description=_('Participants may be kept in a waiting room by the host')) - zoom_phone_link = URLField(_('ZoomVoice phone number'), - description=_('Link to the list of ZoomVoice phone numbers')) - creation_email_footer = TextAreaField(_('Creation email footer'), widget=CKEditorWidget(), description=_('Footer to append to emails sent upon creation of a VC room')) @@ -120,7 +116,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'mute_participant_video': True, 'join_before_host': True, 'waiting_room': False, - 'zoom_phone_link': None, 'creation_email_footer': None, 'send_host_url': False }) diff --git a/vc_zoom/indico_vc_zoom/templates/info_box.html b/vc_zoom/indico_vc_zoom/templates/info_box.html index e05b398..c6002a2 100644 --- a/vc_zoom/indico_vc_zoom/templates/info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/info_box.html @@ -1,6 +1,5 @@ {% from '_clipboard_input.html' import clipboard_input %} {% set host = vc_room.data.host %} -{% set phone_link = settings.get('zoom_phone_link') %}
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    @@ -23,14 +22,4 @@ {{ clipboard_input(vc_room.data.url, name="vc-room-url-%s"|format(event_vc_room.id)) }}
    {% endif %} - {% if event_vc_room.data.show_phone_numbers and phone_link %} -
    - {% trans %}Useful links{% endtrans %} -
    -
    - - {% trans %}Phone numbers{% endtrans %} - -
    - {% endif %}
    diff --git a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html index add3d5a..34943ae 100644 --- a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html @@ -1,7 +1,6 @@ {% from '_password.html' import password %} {% from '_clipboard_input.html' import clipboard_input %} {% set host = vc_room.data.host %} -{% set phone_link = settings.get('zoom_phone_link') %}
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    From 52d98fa64bad3c062fd8b35f08f1d9d0e314314d Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 19 Nov 2020 11:46:26 +0100 Subject: [PATCH 48/94] VC/Zoom: improve DB query --- vc_zoom/indico_vc_zoom/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 253d19b..5cdab31 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -30,12 +30,13 @@ def find_enterprise_email(user): """ from indico_vc_zoom.plugin import ZoomPlugin domains = [auth.strip() for auth in ZoomPlugin.settings.get('email_domains').split(',')] + # get all matching e-mails, primary first result = UserEmail.query.filter( UserEmail.user == user, ~User.is_blocked, ~User.is_deleted, - db.or_(UserEmail.email.ilike('%@{}'.format(domain)) for domain in domains) - ).join(User).first() + db.or_(UserEmail.email.endswith(domain) for domain in domains) + ).join(User).order_by(UserEmail.is_primary.desc()).first() return result.email if result else None From e745614726ccc9f4f7918a6893a9ce4daadbf709 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 19 Nov 2020 15:38:11 +0100 Subject: [PATCH 49/94] VC/Zoom: several fixes in data handling/updates --- vc_zoom/indico_vc_zoom/forms.py | 14 ++++++++++---- vc_zoom/indico_vc_zoom/plugin.py | 22 +++++++++++----------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 704e4ee..c1f04c9 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -7,6 +7,7 @@ from __future__ import unicode_literals from flask import session +from flask_pluginengine import current_plugin from wtforms.fields.core import BooleanField, StringField from wtforms.fields.simple import TextAreaField @@ -16,6 +17,7 @@ from indico.modules.vc.forms import VCRoomAttachFormBase, VCRoomFormBase from indico.util.user import principal_from_identifier from indico.web.forms.base import generated_data from indico.web.forms.fields import IndicoRadioField, PrincipalField +from indico.web.forms.util import inject_validators from indico.web.forms.validators import HiddenUnless, IndicoRegexp from indico.web.forms.widgets import SwitchWidget @@ -88,13 +90,17 @@ class VCRoomForm(VCRoomFormBase): host = principal_from_identifier(defaults.host) defaults.host_choice = 'myself' if host == session.user else 'someone_else' defaults.host_user = None if host == session.user else host + + allow_webinars = current_plugin.settings.get('allow_webinars') + + if allow_webinars: + for field_name in {'mute_audio', 'mute_participant_video', 'waiting_room'}: + inject_validators(self, field_name, [HiddenUnless('meeting_type', 'regular')]) + super(VCRoomForm, self).__init__(*args, **kwargs) - if defaults.meeting_type is None: + if not allow_webinars: del self.meeting_type - else: - for f in {self.mute_audio, self.mute_participant_video, self.waiting_room}: - f.validators = [HiddenUnless('meeting_type', 'regular')] @generated_data def host(self): diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 4646910..c794b31 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -146,13 +146,14 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): ) if existing_vc_room: - # if we're editing a VC room, we will not allow the meeting type to be changed - form.meeting_type.render_kw = {'disabled': True} + if self.settings.get('allow_webinars'): + # if we're editing a VC room, we will not allow the meeting type to be changed + form.meeting_type.render_kw = {'disabled': True} - if form.data['meeting_type'] == 'webinar': - # webinar hosts cannot be changed through the API - form.host_choice.render_kw = {'disabled': True} - form.host_user.render_kw = {'disabled': True} + if form.data['meeting_type'] == 'webinar': + # webinar hosts cannot be changed through the API + form.host_choice.render_kw = {'disabled': True} + form.host_user.render_kw = {'disabled': True} else: form.password.data = gen_random_password() return form @@ -192,10 +193,9 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): super(ZoomPlugin, self).update_data_vc_room(vc_room, data) fields = {'description', 'password'} - if is_new: - # in a freshly-created VCRoom, we may end up not getting a meeting_type from the form - # (i.e. webinars are disabled) - data.setdefault('meeting_type', 'regular') + # we may end up not getting a meeting_type from the form + # (i.e. webinars are disabled) + data.setdefault('meeting_type', 'regular' if is_new else vc_room.data['meeting_type']) if data['meeting_type'] == 'webinar': fields |= {'mute_host_video'} @@ -332,7 +332,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name - if vc_room.data['description'] != zoom_meeting['agenda']: + if vc_room.data['description'] != zoom_meeting.get('agenda'): changes['agenda'] = vc_room.data['description'] if vc_room.data['password'] != zoom_meeting['password']: From 21cdd5a4310f876f6d6d036b6714bc039eb649f7 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 19 Nov 2020 16:09:30 +0100 Subject: [PATCH 50/94] VC/Zoom: remove useless validation --- vc_zoom/indico_vc_zoom/forms.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index c1f04c9..8aa33d9 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -110,7 +110,3 @@ class VCRoomForm(VCRoomFormBase): return session.user.identifier else: return self.host_user.data.identifier if self.host_user.data else None - - def validate_host_user(self, field): - if not field.data: - raise ValidationError(_("Unable to find this user in Indico.")) From 13e8ba08f09e5bd362aab0ae51c55242a1fdbd53 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 25 Nov 2020 15:39:53 +0100 Subject: [PATCH 51/94] VC/Zoom: fixes in webinar management and style --- vc_zoom/indico_vc_zoom/plugin.py | 45 ++++++++++++++++++++++---------- vc_zoom/indico_vc_zoom/util.py | 11 ++++++++ 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index c794b31..82cac96 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -34,7 +34,7 @@ from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_random_password, get_schedule_args, - update_zoom_meeting) + update_zoom_meeting, ZoomMeetingType) class PluginSettingsForm(VCPluginSettingsFormBase): @@ -60,9 +60,9 @@ class PluginSettingsForm(VCPluginSettingsFormBase): description=_('Account to be used as owner of all rooms. It will get "assistant" ' 'privileges on all accounts for which it books rooms')) - allow_webinars = BooleanField(_('Allow Webinars'), + allow_webinars = BooleanField(_('Allow Webinars (Experimental)'), widget=SwitchWidget(), - description=_('Allow webinars to be created through Indico')) + description=_('Allow webinars to be created through Indico. Use at your own risk.')) mute_audio = BooleanField(_('Mute audio'), widget=SwitchWidget(), @@ -110,7 +110,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'api_secret': '', 'webhook_token': '', 'email_domains': '', - 'allow_webinars': True, + 'allow_webinars': False, 'mute_host_video': True, 'mute_audio': True, 'mute_participant_video': True, @@ -165,6 +165,10 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # XXX: This feels slightly hacky. Maybe we should change the API on the core? association_is_new = room_assoc.vc_room is None old_link = room_assoc.link_object + + # in a new room, `meeting_type` comes in `data`, otherwise it's already in the VCRoom + is_webinar = data.get('meeting_type', vc_room.data and vc_room.data.get('meeting_type')) == 'webinar' + super(ZoomPlugin, self).update_data_association(event, vc_room, room_assoc, data) if vc_room.data: @@ -174,7 +178,11 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): update_zoom_meeting(vc_room.data['zoom_id'], { 'start_time': None, 'duration': None, - 'type': 3 + 'type': ( + ZoomMeetingType.recurring_webinar_no_time + if is_webinar + else ZoomMeetingType.recurring_meeting_no_time + ) }) elif room_assoc.link_object != old_link: # the booking should now be linked to something else @@ -257,13 +265,17 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): kwargs = {} if is_webinar: - kwargs = { - 'type': 5 if scheduling_args else 6, - 'host_email': host_email - } + kwargs['type'] = (ZoomMeetingType.webinar + if scheduling_args + else ZoomMeetingType.recurring_webinar_no_time) + settings['alternative_hosts'] = host_email else: kwargs = { - 'type': 2 if scheduling_args else 3, + 'type': ( + ZoomMeetingType.scheduled_meeting + if scheduling_args + else ZoomMeetingType.recurring_meeting_no_time + ), 'schedule_for': host_email } settings.update({ @@ -325,7 +337,10 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if not email: raise Forbidden(_("This user doesn't seem to have an associated Zoom account")) - changes['host_email' if is_webinar else 'schedule_for'] = email + if is_webinar: + changes.setdefault('settings', {})['alternative_hosts'] = email + else: + changes['schedule_for'] = email self._check_indico_is_assistant(email) notify_new_host(session.user, vc_room) @@ -383,9 +398,11 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): client.delete_meeting(zoom_id) except HTTPError as e: # if there's a 404, there is no problem, since the room is supposed to be gone anyway - if not e.response.status_code == 404: - self.logger.exception('Error getting Zoom Room: %s', e.response.content) - raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) + if e.response.status_code == 404: + flash(_("Room didn't existing in Zoom anymore"), 'warning') + else: + self.logger.error("Can't delete room") + raise VCRoomError(_("Problem deleting room")) def get_blueprints(self): return blueprint diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 5cdab31..3200264 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -17,11 +17,22 @@ from indico.modules.users.models.emails import UserEmail from indico.modules.users.models.users import User from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError from indico.util.date_time import now_utc +from indico.util.struct.enum import RichIntEnum from indico_vc_zoom import _ from indico_vc_zoom.api import ZoomIndicoClient +class ZoomMeetingType(RichIntEnum): + instant_meeting = 1 + scheduled_meeting = 2 + recurring_meeting_no_time = 3 + recurring_meeting_fixed_time = 4 + webinar = 5 + recurring_webinar_no_time = 6 + recurring_meeting_fixed_time = 9 + + def find_enterprise_email(user): """Find a user's first e-mail address which can be used by the Zoom API. From 145d2e55c3aae469c798b75e62bf12d770202971 Mon Sep 17 00:00:00 2001 From: Indico Team Date: Wed, 25 Nov 2020 16:00:08 +0100 Subject: [PATCH 52/94] VC/Zoom: set up i18n dictionary --- .tx/config | 6 + .../fr_FR/LC_MESSAGES/messages-js.po | 23 - .../fr_FR/LC_MESSAGES/messages.po | 453 ++++++++++-------- .../indico_vc_zoom/translations/messages.pot | 327 +++++++++++++ 4 files changed, 579 insertions(+), 230 deletions(-) delete mode 100644 vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po create mode 100644 vc_zoom/indico_vc_zoom/translations/messages.pot diff --git a/.tx/config b/.tx/config index 4cfe34a..b6902e0 100644 --- a/.tx/config +++ b/.tx/config @@ -7,6 +7,12 @@ source_file = vc_vidyo/indico_vc_vidyo/translations/messages.pot source_lang = en type = PO +[indico.vc-zoom-messages] +file_filter = vc_zoom/indico_vc_zoom/translations//LC_MESSAGES/messages.po +source_file = vc_zoom/indico_vc_zoom/translations/messages.pot +source_lang = en +type = PO + [indico.search-messages] file_filter = search/indico_search/translations//LC_MESSAGES/messages.po source_file = search/indico_search/translations/messages.pot diff --git a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po deleted file mode 100644 index fe16c6c..0000000 --- a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages-js.po +++ /dev/null @@ -1,23 +0,0 @@ -# Translations template for PROJECT. -# Copyright (C) 2015 ORGANIZATION -# This file is distributed under the same license as the PROJECT project. -# -# Translators: -# Thomas Baron , 2015 -msgid "" -msgstr "" -"Project-Id-Version: Indico\n" -"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2015-03-11 16:21+0100\n" -"PO-Revision-Date: 2015-03-12 12:52+0000\n" -"Last-Translator: Thomas Baron \n" -"Language-Team: French (France) (http://www.transifex.com/projects/p/indico/language/fr_FR/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 1.3\n" -"Language: fr_FR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -msgid "Indico" -msgstr "Indico" diff --git a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po index 652e3e6..ebb8a69 100644 --- a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po +++ b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po @@ -1,289 +1,328 @@ -# Translations template for PROJECT. -# Copyright (C) 2017 ORGANIZATION +# French (France) translations for PROJECT. +# Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the PROJECT project. -# -# Translators: -# Thomas Baron , 2015,2017 +# FIRST AUTHOR , 2020. +# msgid "" msgstr "" -"Project-Id-Version: Indico\n" +"Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-10-18 11:55+0200\n" -"PO-Revision-Date: 2017-10-30 11:04+0000\n" -"Last-Translator: Thomas Baron \n" -"Language-Team: French (France) (http://www.transifex.com/indico/indico/language/fr_FR/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.1\n" +"POT-Creation-Date: 2020-11-25 15:55+0100\n" +"PO-Revision-Date: 2020-11-25 15:57+0100\n" +"Last-Translator: FULL NAME \n" "Language: fr_FR\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"Language-Team: fr_FR \n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.8.0\n" -#: indico_vc_zoom/controllers.py:38 -msgid "You are now the owner of the room '{room.name}'" -msgstr "Vous êtes maintenant responsable de la salle '{room.name}'" +#: indico_vc_zoom/controllers.py:36 +msgid "You are now the host of room '{room.name}'" +msgstr "" -#: indico_vc_zoom/forms.py:32 -msgid "The PIN must be a number" -msgstr "Le code confidentiel doit être un nombre entier" +#: indico_vc_zoom/forms.py:28 indico_vc_zoom/forms.py:61 +msgid "Passcode visibility" +msgstr "" -#: indico_vc_zoom/forms.py:37 -msgid "Show PIN" -msgstr "Afficher le code confidentiel" +#: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:62 +msgid "Who should be able to know this meeting's passcode" +msgstr "" -#: indico_vc_zoom/forms.py:39 -msgid "Show the VC Room PIN on the event page (insecure!)" -msgstr "Afficher le code confidentiel de la salle Vidyo sur la page de l'événement (peu sûr!)" +#: indico_vc_zoom/forms.py:32 indico_vc_zoom/forms.py:65 +msgid "Everyone" +msgstr "" -#: indico_vc_zoom/forms.py:40 -msgid "Show Auto-join URL" -msgstr "Afficher l'URL de connexion" +#: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:66 +msgid "Logged-in users" +msgstr "" -#: indico_vc_zoom/forms.py:42 -msgid "Show the auto-join URL on the event page" -msgstr "Afficher l'URL de connexion sur la page de l'événement" +#: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:67 +msgid "No one" +msgstr "" -#: indico_vc_zoom/forms.py:43 -msgid "Show Phone Access numbers" -msgstr "Afficher les numéros d'accès téléphonique" +#: indico_vc_zoom/forms.py:44 +msgid "Meeting Type" +msgstr "" #: indico_vc_zoom/forms.py:45 -msgid "Show a link to the list of phone access numbers" -msgstr "Afficher un lien vers la liste des numéros d'accès téléphonique" +msgid "The type of Zoom meeting to be created" +msgstr "" -#: indico_vc_zoom/forms.py:58 indico_vc_zoom/templates/info_box.html:7 -#: indico_vc_zoom/templates/manage_event_info_box.html:6 -msgid "Description" -msgstr "Description" +#: indico_vc_zoom/forms.py:48 +msgid "Regular Meeting" +msgstr "" -#: indico_vc_zoom/forms.py:58 -msgid "The description of the room" -msgstr "La description de la salle" +#: indico_vc_zoom/forms.py:49 indico_vc_zoom/templates/room_labels.html:4 +msgid "Webinar" +msgstr "" -#: indico_vc_zoom/forms.py:59 indico_vc_zoom/templates/info_box.html:14 -#: indico_vc_zoom/templates/manage_event_info_box.html:10 -msgid "Owner" -msgstr "Responsable" +#: indico_vc_zoom/forms.py:51 +msgid "Meeting Host" +msgstr "" + +#: indico_vc_zoom/forms.py:52 +msgid "Myself" +msgstr "" + +#: indico_vc_zoom/forms.py:52 +msgid "Someone else" +msgstr "" + +#: indico_vc_zoom/forms.py:54 +msgid "User" +msgstr "" + +#: indico_vc_zoom/forms.py:57 indico_vc_zoom/templates/info_box.html:16 +#: indico_vc_zoom/templates/manage_event_info_box.html:28 +msgid "Passcode" +msgstr "" #: indico_vc_zoom/forms.py:59 -msgid "The owner of the room" -msgstr "Le responsable de la salle" +msgid "Meeting passcode (min. 8 digits)" +msgstr "" -#: indico_vc_zoom/forms.py:60 -#: indico_vc_zoom/templates/manage_event_info_box.html:39 -msgid "Moderation PIN" -msgstr "Code confidentiel de modération" +#: indico_vc_zoom/forms.py:69 indico_vc_zoom/plugin.py:67 +msgid "Mute audio" +msgstr "" -#: indico_vc_zoom/forms.py:61 -msgid "Used to moderate the VC Room. Only digits allowed." -msgstr "Utilisé pour modérer la salle de VC. Seuls les chiffres sont autorisés." +#: indico_vc_zoom/forms.py:71 indico_vc_zoom/plugin.py:69 +msgid "Participants will join the VC room muted by default " +msgstr "" -#: indico_vc_zoom/forms.py:62 indico_vc_zoom/templates/info_box.html:18 -#: indico_vc_zoom/templates/manage_event_info_box.html:32 -msgid "Room PIN" -msgstr "Code confidentiel de la salle" +#: indico_vc_zoom/forms.py:73 indico_vc_zoom/plugin.py:71 +msgid "Mute video (host)" +msgstr "" -#: indico_vc_zoom/forms.py:63 -msgid "" -"Used to protect the access to the VC Room (leave blank for open access). " -"Only digits allowed." -msgstr "Utilisé pour protéger l'accès à la salle de VC (laisser vide pour un accès ouvert). Seuls les chiffres sont autorisés." +#: indico_vc_zoom/forms.py:75 indico_vc_zoom/plugin.py:73 +msgid "The host will join the VC room with video disabled" +msgstr "" -#: indico_vc_zoom/forms.py:65 -msgid "Auto mute" -msgstr "Coupure automatique des périphériques d'entrée" +#: indico_vc_zoom/forms.py:77 indico_vc_zoom/plugin.py:75 +msgid "Mute video (participants)" +msgstr "" -#: indico_vc_zoom/forms.py:66 -msgid "On" -msgstr "Activé" +#: indico_vc_zoom/forms.py:79 indico_vc_zoom/plugin.py:77 +msgid "Participants will join the VC room with video disabled" +msgstr "" -#: indico_vc_zoom/forms.py:66 -msgid "Off" -msgstr "Désactivé" +#: indico_vc_zoom/forms.py:81 indico_vc_zoom/plugin.py:84 +msgid "Waiting room" +msgstr "" -#: indico_vc_zoom/forms.py:67 -msgid "" -"The VidyoDesktop clients will join the VC room muted by default (audio and " -"video)" -msgstr "Les clients VidyoDesktop rejoindront la salle Vidyo avec le micro et la caméra coupés par défaut" +#: indico_vc_zoom/forms.py:83 indico_vc_zoom/plugin.py:86 +msgid "Participants may be kept in a waiting room by the host" +msgstr "" -#: indico_vc_zoom/forms.py:82 -msgid "Unable to find this user in Indico." -msgstr "Impossible de trouver cet utilisateur dans Indico." +#: indico_vc_zoom/forms.py:85 indico_vc_zoom/templates/info_box.html:7 +#: indico_vc_zoom/templates/manage_event_info_box.html:8 +msgid "Description" +msgstr "" -#: indico_vc_zoom/forms.py:84 -msgid "This user does not have a suitable account to use Vidyo." -msgstr "Cet utilisateur n'a pas de compte qui lui permet d'utiliser Vidyo." +#: indico_vc_zoom/forms.py:85 +msgid "Optional description for this room" +msgstr "" #: indico_vc_zoom/plugin.py:49 -msgid "Vidyo email support" -msgstr "Adresse électronique de l'assistance Vidyo" - -#: indico_vc_zoom/plugin.py:50 -msgid "Username" -msgstr "Identifiant" - -#: indico_vc_zoom/plugin.py:50 -msgid "Indico username for Vidyo" -msgstr "Identifiant Indico pour Vidyo" +msgid "API Key" +msgstr "" #: indico_vc_zoom/plugin.py:51 -msgid "Password" -msgstr "Mot de passe" - -#: indico_vc_zoom/plugin.py:52 -msgid "Indico password for Vidyo" -msgstr "Mot de passe utilisateur pour Vidyo" +msgid "API Secret" +msgstr "" #: indico_vc_zoom/plugin.py:53 -msgid "Admin API WSDL URL" -msgstr "URL WSDL pour l'API admin" +msgid "Webhook Token" +msgstr "" #: indico_vc_zoom/plugin.py:54 -msgid "User API WSDL URL" -msgstr "URL WSDL pour l'API utilisateur" - -#: indico_vc_zoom/plugin.py:55 -msgid "Indico tenant prefix" -msgstr "Préfixe de tenant pour Indico" +msgid "Specify Zoom's webhook token if you want live updates" +msgstr "" #: indico_vc_zoom/plugin.py:56 -msgid "The tenant prefix for Indico rooms created on this server" -msgstr "Le préfixe de tenant pour les salles Vidyo créées sur ce serveur Indico" +msgid "E-mail domains" +msgstr "" #: indico_vc_zoom/plugin.py:57 -msgid "Public rooms' group name" -msgstr "Nom du groupe Vidyo pour les salles Vidyo" - -#: indico_vc_zoom/plugin.py:58 -msgid "Group name for public videoconference rooms created by Indico" -msgstr "Nom du groupe pour les salles publiques de visioconférence créées par Indico" +msgid "Comma-separated list of e-mail domains which can use the Zoom API." +msgstr "" #: indico_vc_zoom/plugin.py:59 -msgid "Authenticators" -msgstr "Services d'authentification" +msgid "Assistant Zoom ID" +msgstr "" #: indico_vc_zoom/plugin.py:60 -msgid "Identity providers to convert Indico users to Vidyo accounts" -msgstr "Fournisseurs d'identité pour convertir des utilisateurs Indico en comptes Vidyo" - -#: indico_vc_zoom/plugin.py:61 -msgid "VC room age threshold" -msgstr "Limite d'âge pour les salles Vidyo" - -#: indico_vc_zoom/plugin.py:62 msgid "" -"Number of days after an Indico event when a videoconference room is " -"considered old" -msgstr "Nombre de jours à partir de la fin d'un événement dans Indico après lesquels une salle de visioconférence est considérée comme agée" +"Account to be used as owner of all rooms. It will get \"assistant\" " +"privileges on all accounts for which it books rooms" +msgstr "" -#: indico_vc_zoom/plugin.py:64 -msgid "Max. num. VC rooms before warning" -msgstr "Nombre maximum de salles Vidyo avant un message d'alerte" +#: indico_vc_zoom/plugin.py:63 +msgid "Allow Webinars (Experimental)" +msgstr "" #: indico_vc_zoom/plugin.py:65 -msgid "Maximum number of rooms until a warning is sent to the managers" -msgstr "Nombre maximum de salles Vidyo créées sur ce serveur avant qu'un message d'alerte soit envoyé aux administrateurs" +msgid "Allow webinars to be created through Indico. Use at your own risk." +msgstr "" -#: indico_vc_zoom/plugin.py:66 -msgid "VidyoVoice phone number" -msgstr "Numéros de téléphone VidyoVoice" +#: indico_vc_zoom/plugin.py:79 +msgid "Join Before Host" +msgstr "" -#: indico_vc_zoom/plugin.py:67 -msgid "Link to the list of VidyoVoice phone numbers" -msgstr "Lien vers la liste des numéros de téléphones VidyoVoice" - -#: indico_vc_zoom/plugin.py:68 -msgid "Client Chooser URL" -msgstr "URL de sélection du client" - -#: indico_vc_zoom/plugin.py:69 +#: indico_vc_zoom/plugin.py:81 msgid "" -"URL for client chooser interface. The room key will be passed as a 'url' GET" -" query argument" -msgstr "L'URL pour l'interface de sélection du client. Le code de la salle sera passé comme argument de requête GET." +"Allow participants to join the meeting before the host starts the " +"meeting. Only used for scheduled or recurring meetings." +msgstr "" -#: indico_vc_zoom/plugin.py:71 +#: indico_vc_zoom/plugin.py:88 msgid "Creation email footer" -msgstr "Pied de page du courriel de création" +msgstr "" -#: indico_vc_zoom/plugin.py:72 +#: indico_vc_zoom/plugin.py:89 msgid "Footer to append to emails sent upon creation of a VC room" -msgstr "Pied de page ajouté au courriel envoyé à la création d'une nouvelle salle Vidyo" +msgstr "" -#: indico_vc_zoom/plugin.py:162 indico_vc_zoom/plugin.py:202 -#: indico_vc_zoom/plugin.py:240 indico_vc_zoom/plugin.py:269 -msgid "No valid Vidyo account found for this user" -msgstr "Pas de compte Vidyo valide pour cet utilisateur" +#: indico_vc_zoom/plugin.py:91 +msgid "Send host URL" +msgstr "" -#: indico_vc_zoom/plugin.py:198 indico_vc_zoom/plugin.py:263 -msgid "Room name already in use" -msgstr "Ce nom de salle est déjà utilisé" +#: indico_vc_zoom/plugin.py:93 +msgid "" +"Whether to send an e-mail with the Host URL to the meeting host upon " +"creation of a meeting" +msgstr "" -#: indico_vc_zoom/plugin.py:213 -msgid "Could not find newly created room in Vidyo" -msgstr "Impossible de trouver la nouvelle salle dans Vidyo" +#: indico_vc_zoom/plugin.py:233 +msgid "No Zoom account found for this user" +msgstr "" -#: indico_vc_zoom/plugin.py:232 indico_vc_zoom/plugin.py:259 -#: indico_vc_zoom/plugin.py:288 -msgid "This room has been deleted from Vidyo" -msgstr "Cette salle a été supprimée de Vidyo" +#: indico_vc_zoom/plugin.py:235 +msgid "Problem getting information about Zoom account" +msgstr "" + +#: indico_vc_zoom/plugin.py:302 +msgid "" +"Could not create the room in Zoom. Please contact support if the error " +"persists" +msgstr "" + +#: indico_vc_zoom/plugin.py:331 +msgid "" +"Can't get information about user. Please contact support if the error " +"persists." +msgstr "" + +#: indico_vc_zoom/plugin.py:338 +msgid "This user doesn't seem to have an associated Zoom account" +msgstr "" + +#: indico_vc_zoom/plugin.py:402 +msgid "Room didn't existing in Zoom anymore" +msgstr "" + +#: indico_vc_zoom/plugin.py:405 +msgid "Problem deleting room" +msgstr "" + +#: indico_vc_zoom/plugin.py:461 +msgid "" +"There are one or more scheduled Zoom meetings associated with this event " +"which were not automatically updated." +msgstr "" + +#: indico_vc_zoom/plugin.py:464 +msgid "" +"There are one or more scheduled Zoom meetings associated with " +"contribution '{}' which were not automatically updated." +msgstr "" + +#: indico_vc_zoom/plugin.py:467 +msgid "" +"There are one or more scheduled Zoom meetings associated with this " +"session block which were not automatically updated." +msgstr "" + +#: indico_vc_zoom/util.py:74 +msgid "This room has been deleted from Zoom" +msgstr "" + +#: indico_vc_zoom/util.py:78 +msgid "" +"Problem fetching room from Zoom. Please contact support if the error " +"persists." +msgstr "" + +#: indico_vc_zoom/util.py:97 +msgid "Can't update meeting. Please contact support if the error persists." +msgstr "" #: indico_vc_zoom/templates/buttons.html:7 -#, python-format -msgid "You will be the owner of this Vidyo room, replacing %(name)s." -msgstr "Vous deviendrez le responsable de cette salle Vidyo, à la place de %(name)s." +msgid "You will become the host of this Zoom meeting" +msgstr "" -#: indico_vc_zoom/templates/buttons.html:9 -msgid "Make me owner" -msgstr "Nommez moi responsable" +#: indico_vc_zoom/templates/buttons.html:10 +msgid "Make me host" +msgstr "" -#: indico_vc_zoom/templates/buttons.html:19 +#: indico_vc_zoom/templates/buttons.html:22 +#: indico_vc_zoom/templates/buttons.html:28 msgid "Join" -msgstr "Rejoindre" +msgstr "" -#: indico_vc_zoom/templates/info_box.html:5 -msgid "Name" -msgstr "Nom" +#: indico_vc_zoom/templates/buttons.html:26 +msgid "You will need a passcode to join this Zoom meeting" +msgstr "" -#: indico_vc_zoom/templates/info_box.html:10 -#: indico_vc_zoom/templates/manage_event_info_box.html:8 -msgid "Extension" -msgstr "Extension" +#: indico_vc_zoom/templates/buttons.html:32 +msgid "This Zoom Meeting can only be seen by logged in users" +msgstr "" -#: indico_vc_zoom/templates/info_box.html:22 -#: indico_vc_zoom/templates/manage_event_info_box.html:45 -msgid "Auto-join URL" -msgstr "URL pour connexion à la salle" +#: indico_vc_zoom/templates/buttons.html:34 +msgid "Please log in" +msgstr "" -#: indico_vc_zoom/templates/info_box.html:29 -msgid "Useful links" -msgstr "Liens utiles" +#: indico_vc_zoom/templates/info_box.html:4 +#: indico_vc_zoom/templates/manage_event_info_box.html:5 +msgid "Zoom Meeting ID" +msgstr "" -#: indico_vc_zoom/templates/info_box.html:33 -msgid "Phone numbers" -msgstr "Numéros de téléphone" +#: indico_vc_zoom/templates/info_box.html:11 +#: indico_vc_zoom/templates/manage_event_info_box.html:11 +msgid "Host" +msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:18 +#: indico_vc_zoom/templates/info_box.html:20 +#: indico_vc_zoom/templates/manage_event_info_box.html:30 +msgid "Zoom URL" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:15 msgid "Linked to" -msgstr "attachée à" +msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:24 +#: indico_vc_zoom/templates/manage_event_info_box.html:21 msgid "the whole event" -msgstr "l'événement entier" +msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:26 +#: indico_vc_zoom/templates/manage_event_info_box.html:23 msgid "Contribution" -msgstr "La contribution" +msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:28 +#: indico_vc_zoom/templates/manage_event_info_box.html:25 msgid "Session" -msgstr "La session" +msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:49 +#: indico_vc_zoom/templates/manage_event_info_box.html:34 msgid "Created on" -msgstr "Créée le " +msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:52 +#: indico_vc_zoom/templates/manage_event_info_box.html:37 msgid "Modified on" -msgstr "Modifiée le " +msgstr "" + +#: indico_vc_zoom/templates/room_labels.html:3 +msgid "This is a Zoom webinar" +msgstr "" + diff --git a/vc_zoom/indico_vc_zoom/translations/messages.pot b/vc_zoom/indico_vc_zoom/translations/messages.pot new file mode 100644 index 0000000..b3ad8ad --- /dev/null +++ b/vc_zoom/indico_vc_zoom/translations/messages.pot @@ -0,0 +1,327 @@ +# Translations template for PROJECT. +# Copyright (C) 2020 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2020. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2020-11-25 15:55+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: Babel 2.8.0\n" + +#: indico_vc_zoom/controllers.py:36 +msgid "You are now the host of room '{room.name}'" +msgstr "" + +#: indico_vc_zoom/forms.py:28 indico_vc_zoom/forms.py:61 +msgid "Passcode visibility" +msgstr "" + +#: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:62 +msgid "Who should be able to know this meeting's passcode" +msgstr "" + +#: indico_vc_zoom/forms.py:32 indico_vc_zoom/forms.py:65 +msgid "Everyone" +msgstr "" + +#: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:66 +msgid "Logged-in users" +msgstr "" + +#: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:67 +msgid "No one" +msgstr "" + +#: indico_vc_zoom/forms.py:44 +msgid "Meeting Type" +msgstr "" + +#: indico_vc_zoom/forms.py:45 +msgid "The type of Zoom meeting to be created" +msgstr "" + +#: indico_vc_zoom/forms.py:48 +msgid "Regular Meeting" +msgstr "" + +#: indico_vc_zoom/forms.py:49 indico_vc_zoom/templates/room_labels.html:4 +msgid "Webinar" +msgstr "" + +#: indico_vc_zoom/forms.py:51 +msgid "Meeting Host" +msgstr "" + +#: indico_vc_zoom/forms.py:52 +msgid "Myself" +msgstr "" + +#: indico_vc_zoom/forms.py:52 +msgid "Someone else" +msgstr "" + +#: indico_vc_zoom/forms.py:54 +msgid "User" +msgstr "" + +#: indico_vc_zoom/forms.py:57 indico_vc_zoom/templates/info_box.html:16 +#: indico_vc_zoom/templates/manage_event_info_box.html:28 +msgid "Passcode" +msgstr "" + +#: indico_vc_zoom/forms.py:59 +msgid "Meeting passcode (min. 8 digits)" +msgstr "" + +#: indico_vc_zoom/forms.py:69 indico_vc_zoom/plugin.py:67 +msgid "Mute audio" +msgstr "" + +#: indico_vc_zoom/forms.py:71 indico_vc_zoom/plugin.py:69 +msgid "Participants will join the VC room muted by default " +msgstr "" + +#: indico_vc_zoom/forms.py:73 indico_vc_zoom/plugin.py:71 +msgid "Mute video (host)" +msgstr "" + +#: indico_vc_zoom/forms.py:75 indico_vc_zoom/plugin.py:73 +msgid "The host will join the VC room with video disabled" +msgstr "" + +#: indico_vc_zoom/forms.py:77 indico_vc_zoom/plugin.py:75 +msgid "Mute video (participants)" +msgstr "" + +#: indico_vc_zoom/forms.py:79 indico_vc_zoom/plugin.py:77 +msgid "Participants will join the VC room with video disabled" +msgstr "" + +#: indico_vc_zoom/forms.py:81 indico_vc_zoom/plugin.py:84 +msgid "Waiting room" +msgstr "" + +#: indico_vc_zoom/forms.py:83 indico_vc_zoom/plugin.py:86 +msgid "Participants may be kept in a waiting room by the host" +msgstr "" + +#: indico_vc_zoom/forms.py:85 indico_vc_zoom/templates/info_box.html:7 +#: indico_vc_zoom/templates/manage_event_info_box.html:8 +msgid "Description" +msgstr "" + +#: indico_vc_zoom/forms.py:85 +msgid "Optional description for this room" +msgstr "" + +#: indico_vc_zoom/plugin.py:49 +msgid "API Key" +msgstr "" + +#: indico_vc_zoom/plugin.py:51 +msgid "API Secret" +msgstr "" + +#: indico_vc_zoom/plugin.py:53 +msgid "Webhook Token" +msgstr "" + +#: indico_vc_zoom/plugin.py:54 +msgid "Specify Zoom's webhook token if you want live updates" +msgstr "" + +#: indico_vc_zoom/plugin.py:56 +msgid "E-mail domains" +msgstr "" + +#: indico_vc_zoom/plugin.py:57 +msgid "Comma-separated list of e-mail domains which can use the Zoom API." +msgstr "" + +#: indico_vc_zoom/plugin.py:59 +msgid "Assistant Zoom ID" +msgstr "" + +#: indico_vc_zoom/plugin.py:60 +msgid "" +"Account to be used as owner of all rooms. It will get \"assistant\" " +"privileges on all accounts for which it books rooms" +msgstr "" + +#: indico_vc_zoom/plugin.py:63 +msgid "Allow Webinars (Experimental)" +msgstr "" + +#: indico_vc_zoom/plugin.py:65 +msgid "Allow webinars to be created through Indico. Use at your own risk." +msgstr "" + +#: indico_vc_zoom/plugin.py:79 +msgid "Join Before Host" +msgstr "" + +#: indico_vc_zoom/plugin.py:81 +msgid "" +"Allow participants to join the meeting before the host starts the " +"meeting. Only used for scheduled or recurring meetings." +msgstr "" + +#: indico_vc_zoom/plugin.py:88 +msgid "Creation email footer" +msgstr "" + +#: indico_vc_zoom/plugin.py:89 +msgid "Footer to append to emails sent upon creation of a VC room" +msgstr "" + +#: indico_vc_zoom/plugin.py:91 +msgid "Send host URL" +msgstr "" + +#: indico_vc_zoom/plugin.py:93 +msgid "" +"Whether to send an e-mail with the Host URL to the meeting host upon " +"creation of a meeting" +msgstr "" + +#: indico_vc_zoom/plugin.py:233 +msgid "No Zoom account found for this user" +msgstr "" + +#: indico_vc_zoom/plugin.py:235 +msgid "Problem getting information about Zoom account" +msgstr "" + +#: indico_vc_zoom/plugin.py:302 +msgid "" +"Could not create the room in Zoom. Please contact support if the error " +"persists" +msgstr "" + +#: indico_vc_zoom/plugin.py:331 +msgid "" +"Can't get information about user. Please contact support if the error " +"persists." +msgstr "" + +#: indico_vc_zoom/plugin.py:338 +msgid "This user doesn't seem to have an associated Zoom account" +msgstr "" + +#: indico_vc_zoom/plugin.py:402 +msgid "Room didn't existing in Zoom anymore" +msgstr "" + +#: indico_vc_zoom/plugin.py:405 +msgid "Problem deleting room" +msgstr "" + +#: indico_vc_zoom/plugin.py:461 +msgid "" +"There are one or more scheduled Zoom meetings associated with this event " +"which were not automatically updated." +msgstr "" + +#: indico_vc_zoom/plugin.py:464 +msgid "" +"There are one or more scheduled Zoom meetings associated with " +"contribution '{}' which were not automatically updated." +msgstr "" + +#: indico_vc_zoom/plugin.py:467 +msgid "" +"There are one or more scheduled Zoom meetings associated with this " +"session block which were not automatically updated." +msgstr "" + +#: indico_vc_zoom/util.py:74 +msgid "This room has been deleted from Zoom" +msgstr "" + +#: indico_vc_zoom/util.py:78 +msgid "" +"Problem fetching room from Zoom. Please contact support if the error " +"persists." +msgstr "" + +#: indico_vc_zoom/util.py:97 +msgid "Can't update meeting. Please contact support if the error persists." +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:7 +msgid "You will become the host of this Zoom meeting" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:10 +msgid "Make me host" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:22 +#: indico_vc_zoom/templates/buttons.html:28 +msgid "Join" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:26 +msgid "You will need a passcode to join this Zoom meeting" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:32 +msgid "This Zoom Meeting can only be seen by logged in users" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:34 +msgid "Please log in" +msgstr "" + +#: indico_vc_zoom/templates/info_box.html:4 +#: indico_vc_zoom/templates/manage_event_info_box.html:5 +msgid "Zoom Meeting ID" +msgstr "" + +#: indico_vc_zoom/templates/info_box.html:11 +#: indico_vc_zoom/templates/manage_event_info_box.html:11 +msgid "Host" +msgstr "" + +#: indico_vc_zoom/templates/info_box.html:20 +#: indico_vc_zoom/templates/manage_event_info_box.html:30 +msgid "Zoom URL" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:15 +msgid "Linked to" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:21 +msgid "the whole event" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:23 +msgid "Contribution" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:25 +msgid "Session" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:34 +msgid "Created on" +msgstr "" + +#: indico_vc_zoom/templates/manage_event_info_box.html:37 +msgid "Modified on" +msgstr "" + +#: indico_vc_zoom/templates/room_labels.html:3 +msgid "This is a Zoom webinar" +msgstr "" + From f524884e74807f6bf57e24d36766b292610c713b Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Fri, 27 Nov 2020 18:28:39 +0100 Subject: [PATCH 53/94] VC/Zoom: Add config for special copyright headers --- vc_zoom/copyright.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 vc_zoom/copyright.yml diff --git a/vc_zoom/copyright.yml b/vc_zoom/copyright.yml new file mode 100644 index 0000000..5d9d81e --- /dev/null +++ b/vc_zoom/copyright.yml @@ -0,0 +1,2 @@ +name: CERN and ENEA +start_year: 2020 From 457075d22ac0803bf6c7f5d890fd70c0c1cf93cc Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 10:52:33 +0100 Subject: [PATCH 54/94] VC/Zoom: Add missing file headers --- vc_zoom/conftest.py | 7 +++++++ vc_zoom/setup.py | 7 +++++++ vc_zoom/tests/operation_test.py | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/vc_zoom/conftest.py b/vc_zoom/conftest.py index 7c568e8..2dba5e3 100644 --- a/vc_zoom/conftest.py +++ b/vc_zoom/conftest.py @@ -1 +1,8 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + pytest_plugins = 'indico' diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index 58af122..1460a9c 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -1,3 +1,10 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. + from __future__ import unicode_literals from setuptools import find_packages, setup diff --git a/vc_zoom/tests/operation_test.py b/vc_zoom/tests/operation_test.py index 7e809a7..1483528 100644 --- a/vc_zoom/tests/operation_test.py +++ b/vc_zoom/tests/operation_test.py @@ -1,3 +1,9 @@ +# This file is part of the Indico plugins. +# Copyright (C) 2020 CERN and ENEA +# +# The Indico plugins are free software; you can redistribute +# them and/or modify them under the terms of the MIT License; +# see the LICENSE file for more details. import pytest From 1d5b1b377a3bafadba23adcd7f096ef8f5ca9077 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 10:56:36 +0100 Subject: [PATCH 55/94] VC/Zoom: Fix setting initial passcode --- vc_zoom/indico_vc_zoom/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 82cac96..fb9b0cb 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -154,7 +154,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # webinar hosts cannot be changed through the API form.host_choice.render_kw = {'disabled': True} form.host_user.render_kw = {'disabled': True} - else: + elif not form.is_submitted(): form.password.data = gen_random_password() return form From b28793f936f4817c3f7c9bbe6efde14221908475 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 10:57:26 +0100 Subject: [PATCH 56/94] VC/Zoom: Bump version to 2.3b1 --- vc_zoom/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index 1460a9c..c119db3 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -12,7 +12,7 @@ from setuptools import find_packages, setup setup( name='indico-plugin-vc-zoom', - version='2.3-dev', + version='2.3b1', description='Zoom video-conferencing plugin for Indico', url='https://github.com/indico/indico-plugins', license='MIT', From ccd1db378d155d8da7c83996c09db70106ab9e93 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 10:59:49 +0100 Subject: [PATCH 57/94] VC/Zoom: Require Python 2.7 --- vc_zoom/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index c119db3..d20cbf6 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -26,6 +26,7 @@ setup( 'indico>=2.3.2.dev0', 'PyJWT<2' ], + python_requires='~=2.7', classifiers=[ 'Environment :: Plugins', 'Environment :: Web Environment', From 0d305bcd2240f2dc46fcc8ffb586068a3382f5a7 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 12:32:50 +0100 Subject: [PATCH 58/94] VC/Zoom: Only log unhandled room webhooks as DEBUG This happens a lot when people create zoom rooms outside indico --- vc_zoom/indico_vc_zoom/controllers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index 43993b3..a36ef38 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -56,7 +56,8 @@ class RHWebhook(RH): vc_room = VCRoom.query.filter(VCRoom.data.contains({'zoom_id': meeting_id})).first() if not vc_room: - current_plugin.logger.warning('Action for unhandled Zoom room: %s', meeting_id) + # This usually happens when a room wasn't created via indico + current_plugin.logger.debug('Action for unhandled Zoom room: %s', meeting_id) return if event in {'meeting.updated', 'webinar.updated', 'meeting.deleted', 'webinar.deleted'}: From 8f11af2beeadf03d97277e2a4e1eb8c1cc864bd4 Mon Sep 17 00:00:00 2001 From: Indico Team Date: Mon, 30 Nov 2020 13:01:18 +0100 Subject: [PATCH 59/94] VC/Zoom: Update French translation :fr: :baguette_bread: --- .../fr_FR/LC_MESSAGES/messages.po | 174 +++++++++++------- 1 file changed, 105 insertions(+), 69 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po index ebb8a69..575d13a 100644 --- a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po +++ b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po @@ -1,328 +1,364 @@ -# French (France) translations for PROJECT. +# Translations template for PROJECT. # Copyright (C) 2020 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # FIRST AUTHOR , 2020. -# +# +# Translators: +# Thomas Baron , 2020 +# +#, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2020-11-25 15:55+0100\n" -"PO-Revision-Date: 2020-11-25 15:57+0100\n" -"Last-Translator: FULL NAME \n" -"Language: fr_FR\n" -"Language-Team: fr_FR \n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"PO-Revision-Date: 2020-11-25 15:06+0000\n" +"Last-Translator: Thomas Baron , 2020\n" +"Language-Team: French (France) (https://www.transifex.com/indico/teams/6478/fr_FR/)\n" "MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=utf-8\n" +"Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.8.0\n" +"Language: fr_FR\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" #: indico_vc_zoom/controllers.py:36 msgid "You are now the host of room '{room.name}'" -msgstr "" +msgstr "Vous êtes maintenant l'hôte de la réunion '{room.name}'" #: indico_vc_zoom/forms.py:28 indico_vc_zoom/forms.py:61 msgid "Passcode visibility" -msgstr "" +msgstr "Visibilité du code secret" #: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:62 msgid "Who should be able to know this meeting's passcode" -msgstr "" +msgstr "Qui peut connaitre le code secret de cette réunion" #: indico_vc_zoom/forms.py:32 indico_vc_zoom/forms.py:65 msgid "Everyone" -msgstr "" +msgstr "Tout le monde" #: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:66 msgid "Logged-in users" -msgstr "" +msgstr "Utilisateurs connectés" #: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:67 msgid "No one" -msgstr "" +msgstr "Personne" #: indico_vc_zoom/forms.py:44 msgid "Meeting Type" -msgstr "" +msgstr "Type de réunion" #: indico_vc_zoom/forms.py:45 msgid "The type of Zoom meeting to be created" -msgstr "" +msgstr "Le type de réunion Zoom à créer" #: indico_vc_zoom/forms.py:48 msgid "Regular Meeting" -msgstr "" +msgstr "Réunion normale" #: indico_vc_zoom/forms.py:49 indico_vc_zoom/templates/room_labels.html:4 msgid "Webinar" -msgstr "" +msgstr "Wébinaire" #: indico_vc_zoom/forms.py:51 msgid "Meeting Host" -msgstr "" +msgstr "Hôte de la réunion" #: indico_vc_zoom/forms.py:52 msgid "Myself" -msgstr "" +msgstr "Moi-même" #: indico_vc_zoom/forms.py:52 msgid "Someone else" -msgstr "" +msgstr "Quelqu'un d'autre" #: indico_vc_zoom/forms.py:54 msgid "User" -msgstr "" +msgstr "Utilisateur" #: indico_vc_zoom/forms.py:57 indico_vc_zoom/templates/info_box.html:16 #: indico_vc_zoom/templates/manage_event_info_box.html:28 msgid "Passcode" -msgstr "" +msgstr "Code secret" #: indico_vc_zoom/forms.py:59 msgid "Meeting passcode (min. 8 digits)" -msgstr "" +msgstr "Code secret de la réunion (min. 8 chiffres)" #: indico_vc_zoom/forms.py:69 indico_vc_zoom/plugin.py:67 msgid "Mute audio" -msgstr "" +msgstr "Couper le micro" #: indico_vc_zoom/forms.py:71 indico_vc_zoom/plugin.py:69 msgid "Participants will join the VC room muted by default " msgstr "" +"Les participants rejoindront la réunion avec leur micro coupé par défaut" #: indico_vc_zoom/forms.py:73 indico_vc_zoom/plugin.py:71 msgid "Mute video (host)" -msgstr "" +msgstr "Couper la vidéo (hôte)" #: indico_vc_zoom/forms.py:75 indico_vc_zoom/plugin.py:73 msgid "The host will join the VC room with video disabled" -msgstr "" +msgstr "L'hôte rejoindra la réunion avec sa vidéo désactivée" #: indico_vc_zoom/forms.py:77 indico_vc_zoom/plugin.py:75 msgid "Mute video (participants)" -msgstr "" +msgstr "Couper la vidéo (participants)" #: indico_vc_zoom/forms.py:79 indico_vc_zoom/plugin.py:77 msgid "Participants will join the VC room with video disabled" -msgstr "" +msgstr "Les participants rejoindront la réunion avec leur vidéo coupée" #: indico_vc_zoom/forms.py:81 indico_vc_zoom/plugin.py:84 msgid "Waiting room" -msgstr "" +msgstr "Salle d'attente" #: indico_vc_zoom/forms.py:83 indico_vc_zoom/plugin.py:86 msgid "Participants may be kept in a waiting room by the host" -msgstr "" +msgstr "Les participants rejoindront une salle d'attente" #: indico_vc_zoom/forms.py:85 indico_vc_zoom/templates/info_box.html:7 #: indico_vc_zoom/templates/manage_event_info_box.html:8 msgid "Description" -msgstr "" +msgstr "Description" #: indico_vc_zoom/forms.py:85 msgid "Optional description for this room" -msgstr "" +msgstr "Description optionnelle de cette réunion" #: indico_vc_zoom/plugin.py:49 msgid "API Key" -msgstr "" +msgstr "Clé API" #: indico_vc_zoom/plugin.py:51 msgid "API Secret" -msgstr "" +msgstr "Secret de l'API" #: indico_vc_zoom/plugin.py:53 msgid "Webhook Token" -msgstr "" +msgstr "Jeton de webhook" #: indico_vc_zoom/plugin.py:54 msgid "Specify Zoom's webhook token if you want live updates" msgstr "" +"Spécifier le jeton de webhook Zoom si vous souhaitez des mises à jour en " +"direct" #: indico_vc_zoom/plugin.py:56 msgid "E-mail domains" -msgstr "" +msgstr "Domaines de courriel" #: indico_vc_zoom/plugin.py:57 msgid "Comma-separated list of e-mail domains which can use the Zoom API." msgstr "" +"Liste séparée par des virgules des domaines de courriels qui peuvent " +"utiliser l'API Zoom." #: indico_vc_zoom/plugin.py:59 msgid "Assistant Zoom ID" -msgstr "" +msgstr "Zoom ID de l'assistant" #: indico_vc_zoom/plugin.py:60 msgid "" "Account to be used as owner of all rooms. It will get \"assistant\" " "privileges on all accounts for which it books rooms" msgstr "" +"Compte à utiliser comme propriétaire de toutes les salles. Ce compte " +"obtiendra le privilège d'assistant pour tous les comptes pour qui les " +"réunions seront créées" #: indico_vc_zoom/plugin.py:63 msgid "Allow Webinars (Experimental)" -msgstr "" +msgstr "Autoriser les wébinaires (expérimental)" #: indico_vc_zoom/plugin.py:65 msgid "Allow webinars to be created through Indico. Use at your own risk." msgstr "" +"Autoriser les wébinaires à être créés via Indico. Utilisez à vos propres " +"risques." #: indico_vc_zoom/plugin.py:79 msgid "Join Before Host" -msgstr "" +msgstr "Rejoindre avant l'hôte" #: indico_vc_zoom/plugin.py:81 msgid "" -"Allow participants to join the meeting before the host starts the " -"meeting. Only used for scheduled or recurring meetings." +"Allow participants to join the meeting before the host starts the meeting. " +"Only used for scheduled or recurring meetings." msgstr "" +"Autoriser les participants à rejoindre la réunion avant que l'hôte démarre " +"la réunion. Utilisé uniquement pour les réunions programmées ou récurrentes." #: indico_vc_zoom/plugin.py:88 msgid "Creation email footer" -msgstr "" +msgstr "Pied de page du courriel de création" #: indico_vc_zoom/plugin.py:89 msgid "Footer to append to emails sent upon creation of a VC room" msgstr "" +"Pied de page à ajouter aux courriels envoyés lors de la création d'une " +"réunion" #: indico_vc_zoom/plugin.py:91 msgid "Send host URL" -msgstr "" +msgstr "Envoyer l'URL de l'hôte" #: indico_vc_zoom/plugin.py:93 msgid "" "Whether to send an e-mail with the Host URL to the meeting host upon " "creation of a meeting" msgstr "" +"Envoyer ou non un courriel contenant l'URL d'hôte à l'hôte de la réunion à " +"la création d'une réunion" #: indico_vc_zoom/plugin.py:233 msgid "No Zoom account found for this user" -msgstr "" +msgstr "Aucun compte Zoom pour cet utilisateur" #: indico_vc_zoom/plugin.py:235 msgid "Problem getting information about Zoom account" msgstr "" +"Une erreur est survenue lors de la récupération des informations sur le " +"compte Zoom" #: indico_vc_zoom/plugin.py:302 msgid "" "Could not create the room in Zoom. Please contact support if the error " "persists" msgstr "" +"Impossible de créer la réunion dans Zoom. Veuillez contacter le support si " +"l'erreur persiste" #: indico_vc_zoom/plugin.py:331 msgid "" "Can't get information about user. Please contact support if the error " "persists." msgstr "" +"Impossible d'obtenir des informations sur l'utilisateur. Veuillez contacter " +"le support si cette erreur persiste." #: indico_vc_zoom/plugin.py:338 msgid "This user doesn't seem to have an associated Zoom account" -msgstr "" +msgstr "Cet utilisateur ne semble pas avoir un compte Zoom associé" #: indico_vc_zoom/plugin.py:402 msgid "Room didn't existing in Zoom anymore" -msgstr "" +msgstr "La réunion n'existait plus dans Zoom" #: indico_vc_zoom/plugin.py:405 msgid "Problem deleting room" -msgstr "" +msgstr "Erreur lors de la suppression de la salle" #: indico_vc_zoom/plugin.py:461 msgid "" "There are one or more scheduled Zoom meetings associated with this event " "which were not automatically updated." msgstr "" +"Il existe une ou plusieurs réunions Zoom associées à cet événement qui n'ont" +" pas été automatiquement mises à jour." #: indico_vc_zoom/plugin.py:464 msgid "" -"There are one or more scheduled Zoom meetings associated with " -"contribution '{}' which were not automatically updated." +"There are one or more scheduled Zoom meetings associated with contribution " +"'{}' which were not automatically updated." msgstr "" +"Il existe une ou plusieurs réunions Zoom associées à la contribution '{}' " +"qui n'ont pas été mises à jour automatiquement." #: indico_vc_zoom/plugin.py:467 msgid "" -"There are one or more scheduled Zoom meetings associated with this " -"session block which were not automatically updated." +"There are one or more scheduled Zoom meetings associated with this session " +"block which were not automatically updated." msgstr "" +"Il existe une ou plusieurs réunions Zoom associées à ce bloc de session qui " +"n'ont pas été automatiquement mises à jour." #: indico_vc_zoom/util.py:74 msgid "This room has been deleted from Zoom" -msgstr "" +msgstr "Cette réunion a été effacée de Zoom" #: indico_vc_zoom/util.py:78 msgid "" "Problem fetching room from Zoom. Please contact support if the error " "persists." msgstr "" +"Erreur en récupérant la réunion Zoom. Veuillez contacter le support si cette" +" erreur persiste." #: indico_vc_zoom/util.py:97 msgid "Can't update meeting. Please contact support if the error persists." msgstr "" +"Impossible de mettre à jour la réunion. Veuillez contacter le support si " +"l'erreur persiste." #: indico_vc_zoom/templates/buttons.html:7 msgid "You will become the host of this Zoom meeting" -msgstr "" +msgstr "Vous deviendrez l'hôte de cette réunion Zoom" #: indico_vc_zoom/templates/buttons.html:10 msgid "Make me host" -msgstr "" +msgstr "Faites de moi l'hôte" #: indico_vc_zoom/templates/buttons.html:22 #: indico_vc_zoom/templates/buttons.html:28 msgid "Join" -msgstr "" +msgstr "Rejoindre" #: indico_vc_zoom/templates/buttons.html:26 msgid "You will need a passcode to join this Zoom meeting" -msgstr "" +msgstr "Vous aurez besoin d'un code secret pour rejoindre cette réunion Zoom" #: indico_vc_zoom/templates/buttons.html:32 msgid "This Zoom Meeting can only be seen by logged in users" msgstr "" +"Cette réunion Zoom ne peut être vue que par les utilisateurs connectés" #: indico_vc_zoom/templates/buttons.html:34 msgid "Please log in" -msgstr "" +msgstr "Veuillez vous connecter" #: indico_vc_zoom/templates/info_box.html:4 #: indico_vc_zoom/templates/manage_event_info_box.html:5 msgid "Zoom Meeting ID" -msgstr "" +msgstr "ID de réunion Zoom" #: indico_vc_zoom/templates/info_box.html:11 #: indico_vc_zoom/templates/manage_event_info_box.html:11 msgid "Host" -msgstr "" +msgstr "Hôte" #: indico_vc_zoom/templates/info_box.html:20 #: indico_vc_zoom/templates/manage_event_info_box.html:30 msgid "Zoom URL" -msgstr "" +msgstr "URL Zoom" #: indico_vc_zoom/templates/manage_event_info_box.html:15 msgid "Linked to" -msgstr "" +msgstr "Liée à" #: indico_vc_zoom/templates/manage_event_info_box.html:21 msgid "the whole event" -msgstr "" +msgstr "l'événement entier" #: indico_vc_zoom/templates/manage_event_info_box.html:23 msgid "Contribution" -msgstr "" +msgstr "Contribution" #: indico_vc_zoom/templates/manage_event_info_box.html:25 msgid "Session" -msgstr "" +msgstr "Session" #: indico_vc_zoom/templates/manage_event_info_box.html:34 msgid "Created on" -msgstr "" +msgstr "Créé le" #: indico_vc_zoom/templates/manage_event_info_box.html:37 msgid "Modified on" -msgstr "" +msgstr "Modifiée le" #: indico_vc_zoom/templates/room_labels.html:3 msgid "This is a Zoom webinar" -msgstr "" - +msgstr "Ceci est un wébinaire Zoom" From 9df423228bc86be5aadf83347fb996787432a564 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 13:12:10 +0100 Subject: [PATCH 60/94] Fix compiling plugin locales The po/pot files are often marked as fuzzy so we need to allo compiling such files as well. --- manage-i18n.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manage-i18n.sh b/manage-i18n.sh index 159cd01..38d815c 100755 --- a/manage-i18n.sh +++ b/manage-i18n.sh @@ -48,7 +48,7 @@ for plugin in $(find . -name setup.py -exec sh -c 'basename $(dirname $0)' {} \; pybabel update -i "./indico_${plugin}/translations/messages.pot" -l "$LOCALE" -d "./indico_${plugin}/translations" elif [[ "$ACTION" == "compile" ]]; then require_locale - pybabel compile -d "./indico_${plugin}/translations/" -l "$LOCALE" + pybabel compile -f -d "./indico_${plugin}/translations/" -l "$LOCALE" fi popd >/dev/null done From 1accbe3bfab73bbb4474ae6774e91c1c7ef115ed Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 15:17:52 +0100 Subject: [PATCH 61/94] VC/Zoom: Move most metadata to setup.cfg --- vc_zoom/setup.cfg | 27 +++++++++++++++++++++++++++ vc_zoom/setup.py | 22 ++++------------------ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/vc_zoom/setup.cfg b/vc_zoom/setup.cfg index a5814c8..fcfe660 100644 --- a/vc_zoom/setup.cfg +++ b/vc_zoom/setup.cfg @@ -1,2 +1,29 @@ +[metadata] +name = indico-plugin-vc-zoom +description = Zoom video-conferencing plugin for Indico +long_description = file: README.md +long_description_content_type = text/markdown; charset=UTF-8; variant=CommonMark +url = https://github.com/indico/indico-plugins +license = MIT +author = Giovanni Mariano (ENEA) and Indico Team (CERN) +author_email = indico-team@cern.ch +classifiers = + Environment :: Plugins + Environment :: Web Environment + License :: OSI Approved :: MIT License + Programming Language :: Python :: 2.7 + +[options] +packages = find: +zip_safe = false +include_package_data = true +python_requires = ~=2.7 + +[options.entry_points] +indico.plugins = + vc_zoom = indico_vc_zoom.plugin:ZoomPlugin + + + [pydocstyle] ignore = D100,D101,D102,D103,D104,D105,D107,D203,D213 diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index d20cbf6..9e4e740 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -7,31 +7,17 @@ from __future__ import unicode_literals -from setuptools import find_packages, setup +from setuptools import setup +# XXX: keeping some entries in here to make bulk updates easier while +# other plugins still have this metadata in setup.py; everything else +# is in setup.cfg now setup( name='indico-plugin-vc-zoom', version='2.3b1', - description='Zoom video-conferencing plugin for Indico', - url='https://github.com/indico/indico-plugins', - license='MIT', - author='Giovanni Mariano (ENEA) and Indico Team (CERN)', - author_email='indico-team@cern.ch', - packages=find_packages(), - zip_safe=False, - platforms='any', - include_package_data=True, install_requires=[ 'indico>=2.3.2.dev0', 'PyJWT<2' ], - python_requires='~=2.7', - classifiers=[ - 'Environment :: Plugins', - 'Environment :: Web Environment', - 'License :: OSI Approved :: MIT License', - 'Programming Language :: Python :: 2.7' - ], - entry_points={'indico.plugins': {'vc_zoom = indico_vc_zoom.plugin:ZoomPlugin'}} ) From be0b3dc9ea5ec7e359c1e055e12d0a7a8b9b34d7 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 15:29:11 +0100 Subject: [PATCH 62/94] VC/Zoom: Make linebreaks more consistent --- vc_zoom/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index c785dea..2898d73 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -13,9 +13,7 @@ Rooms are created under the account of an *assistant user* which can be set using the **Assistant Zoom ID** configuration setting. This account will also be added automatically as an assistant to every meeting host. -This is needed in order to allow for the host to be changed ([`scheduled_for`]( -https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate#request-body -) property in the Zoom API). The *assistant user* owns every Zoom meeting, with the `scheduled_for` property being +This is needed in order to allow for the host to be changed ([`scheduled_for`](https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate#request-body) property in the Zoom API). The *assistant user* owns every Zoom meeting, with the `scheduled_for` property being used to grant the required privileges to the desired hosts. ## Zoom App Configuration @@ -45,6 +43,7 @@ shall own all meetings ### Zoom API key/secret (JWT) + To obtain API key and API secret, please visit [https://marketplace.zoom.us/docs/guides/auth/jwt](https://marketplace.zoom.us/docs/guides/auth/jwt). From da693543eb2c2daa3228dc583bb527647cc1602c Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 15:44:09 +0100 Subject: [PATCH 63/94] VC/Zoom: Use more specific PyJWT version pin --- vc_zoom/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index 9e4e740..c6fb78a 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -18,6 +18,6 @@ setup( version='2.3b1', install_requires=[ 'indico>=2.3.2.dev0', - 'PyJWT<2' + 'PyJWT>=1.7.1,<2' ], ) From c8962c908b4d22458e8a015de712121fd282dc1c Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 30 Nov 2020 17:26:43 +0100 Subject: [PATCH 64/94] Improve API error logging --- vc_zoom/indico_vc_zoom/api/client.py | 11 ++++++++--- vc_zoom/indico_vc_zoom/plugin.py | 7 +++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index 9a9dba5..af45edb 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -25,9 +25,14 @@ def format_iso_dt(d): def _handle_response(resp, expected_code=200, expects_json=True): - resp.raise_for_status() - if resp.status_code != expected_code: - raise HTTPError("Unexpected status code {}".format(resp.status_code), response=resp) + try: + resp.raise_for_status() + if resp.status_code != expected_code: + raise HTTPError("Unexpected status code {}".format(resp.status_code), response=resp) + except HTTPError: + from indico_vc_zoom.plugin import ZoomPlugin + ZoomPlugin.logger.error('Error in API call to %s : %s', resp.url, resp.content) + raise return resp.json() if expects_json else resp diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index fb9b0cb..444a71f 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -228,13 +228,12 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if user_id != assistant_id: try: assistants = {assist['email'] for assist in client.get_assistants_for_user(user_id)['assistants']} + if assistant_id not in assistants: + client.add_assistant_to_user(user_id, assistant_id) except HTTPError as e: if e.response.status_code == 404: raise NotFound(_("No Zoom account found for this user")) - self.logger.exception('Error getting assistants for account %s: %s', user_id, e.response.content) - raise VCRoomError(_("Problem getting information about Zoom account")) - if assistant_id not in assistants: - client.add_assistant_to_user(user_id, assistant_id) + raise VCRoomError(_("Problem setting Zoom account assistants")) def create_room(self, vc_room, event): """Create a new Zoom room for an event, given a VC room. From 17416dbc9087c5dff71c2cf446a06740e60e9d3c Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 18:00:59 +0100 Subject: [PATCH 65/94] VC/Zoom: Handle missing zoom accounts gracefully --- vc_zoom/indico_vc_zoom/api/client.py | 7 +++++-- vc_zoom/indico_vc_zoom/forms.py | 15 +++++++++++++++ vc_zoom/indico_vc_zoom/util.py | 2 +- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index af45edb..e97c3fe 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -227,8 +227,11 @@ class ZoomIndicoClient(object): def delete_webinar(self, webinar_id): return _handle_response(self.client.webinar.delete(webinar_id), 204, expects_json=False) - def get_user(self, user_id): - return _handle_response(self.client.user.get(user_id)) + def get_user(self, user_id, silent=False): + resp = self.client.user.get(user_id) + if resp.status_code == 404 and silent: + return None + return _handle_response(resp) def get_assistants_for_user(self, user_id): return _handle_response(self.client.user.get_assistants(user_id)) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 8aa33d9..f990254 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -22,6 +22,8 @@ from indico.web.forms.validators import HiddenUnless, IndicoRegexp from indico.web.forms.widgets import SwitchWidget from indico_vc_zoom import _ +from indico_vc_zoom.api.client import ZoomIndicoClient +from indico_vc_zoom.util import find_enterprise_email class VCRoomAttachForm(VCRoomAttachFormBase): @@ -102,6 +104,19 @@ class VCRoomForm(VCRoomFormBase): if not allow_webinars: del self.meeting_type + def validate_host_choice(self, field): + if field.data == 'myself': + self._check_zoom_user(session.user) + + def validate_host_user(self, field): + if self.host_choice.data == 'someone_else': + self._check_zoom_user(field.data) + + def _check_zoom_user(self, user): + email = find_enterprise_email(user) + if email is None or ZoomIndicoClient().get_user(email, silent=True) is None: + raise ValidationError(_('This user has no Zoom account')) + @generated_data def host(self): if self.host_choice is None: diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 3200264..5ea5e40 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -40,7 +40,7 @@ def find_enterprise_email(user): :return: the e-mail address if it exists, otherwise `None` """ from indico_vc_zoom.plugin import ZoomPlugin - domains = [auth.strip() for auth in ZoomPlugin.settings.get('email_domains').split(',')] + domains = [domain.strip() for domain in ZoomPlugin.settings.get('email_domains').split(',')] # get all matching e-mails, primary first result = UserEmail.query.filter( UserEmail.user == user, From d935bb27c703cc02b89bf02802c1b6e7c97996f2 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Mon, 30 Nov 2020 18:12:34 +0100 Subject: [PATCH 66/94] VC/Zoom: Disable duplicate room name check --- vc_zoom/indico_vc_zoom/forms.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index f990254..629f33e 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -117,6 +117,10 @@ class VCRoomForm(VCRoomFormBase): if email is None or ZoomIndicoClient().get_user(email, silent=True) is None: raise ValidationError(_('This user has no Zoom account')) + def validate_name(self, field): + # Duplicate names are fine on Zoom + pass + @generated_data def host(self): if self.host_choice is None: From 45f14cf922ac47691dabab1dd78b6f89c8c77905 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 1 Dec 2020 11:26:21 +0100 Subject: [PATCH 67/94] VC/Zoom: update join URL when password changes --- vc_zoom/indico_vc_zoom/plugin.py | 12 ++++----- vc_zoom/indico_vc_zoom/util.py | 11 ++++++++ vc_zoom/tests/operation_test.py | 43 +++++++++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 444a71f..86ade35 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -34,7 +34,7 @@ from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_random_password, get_schedule_args, - update_zoom_meeting, ZoomMeetingType) + get_url_data_args, update_zoom_meeting, ZoomMeetingType) class PluginSettingsForm(VCPluginSettingsFormBase): @@ -302,12 +302,10 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room.data.update({ 'zoom_id': unicode(meeting_obj['id']), - 'url': meeting_obj['join_url'], - 'public_url': meeting_obj['join_url'].split('?')[0], 'start_url': meeting_obj['start_url'], 'host': host.identifier }) - + vc_room.data.update(get_url_data_args(meeting_obj['join_url'])) flag_modified(vc_room, 'data') # e-mail Host URL to meeting host @@ -366,6 +364,9 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if changes: update_zoom_meeting(vc_room.data['zoom_id'], changes, is_webinar=is_webinar) + # always refresh meeting URL (it may have changed if password changed) + zoom_meeting = fetch_zoom_meeting(vc_room, client=client, is_webinar=is_webinar) + vc_room.data.update(get_url_data_args(zoom_meeting['join_url'])) def refresh_room(self, vc_room, event): is_webinar = vc_room.data['meeting_type'] == 'webinar' @@ -373,8 +374,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room.name = zoom_meeting['topic'] vc_room.data.update({ 'description': zoom_meeting['agenda'], - 'url': zoom_meeting['join_url'], - 'public_url': zoom_meeting['join_url'].split('?')[0], 'zoom_id': zoom_meeting['id'], 'password': zoom_meeting['password'], 'mute_host_video': zoom_meeting['settings']['host_video'], @@ -384,6 +383,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'mute_participant_video': not zoom_meeting['settings'].get('participant_video'), 'waiting_room': zoom_meeting['settings'].get('waiting_room') }) + vc_room.data.update(get_url_data_args(zoom_meeting['join_url'])) flag_modified(vc_room, 'data') def delete_room(self, vc_room, event): diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 5ea5e40..12d297e 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -111,3 +111,14 @@ def get_schedule_args(obj): 'start_time': obj.start_dt, 'duration': duration.total_seconds() / 60, } + + +def get_url_data_args(url): + """Create a dictionary with proper public/private "join URL" fields."" + + :param url: the original URL + """ + return { + 'url': url, + 'public_url': url.split('?')[0], + } diff --git a/vc_zoom/tests/operation_test.py b/vc_zoom/tests/operation_test.py index 1483528..9073ca4 100644 --- a/vc_zoom/tests/operation_test.py +++ b/vc_zoom/tests/operation_test.py @@ -71,9 +71,7 @@ def zoom_api(create_user, mocker): } api_update_meeting = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.update_meeting') - api_update_meeting.return_value = { - - } + api_update_meeting.return_value = {} create_user(1, email='don.orange@megacorp.xyz') @@ -128,3 +126,42 @@ def test_host_change(create_user, mocker, create_meeting, zoom_plugin, zoom_api, 'schedule_for': 'joe.bidon@megacorp.xyz', 'agenda': 'something else' }),) + + +def test_password_change(create_user, mocker, create_meeting, zoom_plugin, zoom_api): + mocker.patch('indico_vc_zoom.plugin.notify_new_host') + + create_user(2, email='joe.bidon@megacorp.xyz') + vc_room = create_meeting() + vc_room.data['password'] = '1337' + + # simulate changes between calls of "GET meeting" + def _get_meeting(self, meeting_id): + result = { + 'id': meeting_id, + 'join_url': 'https://example.com/llamas' if _get_meeting.called else 'https://example.com/kitties', + 'start_url': 'https://example.com/puppies', + 'password': '1337' if _get_meeting.called else '1234', + 'host_id': 'don.orange@megacorp.xyz', + 'topic': 'New Room', + 'agenda': 'something something', + 'settings': { + 'host_video': True, + 'mute_upon_entry': False, + 'participant_video': True, + 'waiting_room': False + } + } + _get_meeting.called = True + return result + _get_meeting.called = False + mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.get_meeting', _get_meeting) + + zoom_plugin.update_room(vc_room, vc_room.events[0].event) + + zoom_api['update_meeting'].assert_called_with('12345abc', { + 'password': '1337' + }) + + assert vc_room.data['password'] == '1337' + assert vc_room.data['url'] == 'https://example.com/llamas' From 601245159f56ccfa1a7fb8d961b870dd569d6338 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 1 Dec 2020 11:49:35 +0100 Subject: [PATCH 68/94] VC/Zoom: handle case where 'agenda' field absent --- vc_zoom/indico_vc_zoom/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 86ade35..4ee605b 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -344,7 +344,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name - if vc_room.data['description'] != zoom_meeting.get('agenda'): + if vc_room.data['description'] != zoom_meeting.get('agenda', ''): changes['agenda'] = vc_room.data['description'] if vc_room.data['password'] != zoom_meeting['password']: @@ -373,7 +373,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): zoom_meeting = fetch_zoom_meeting(vc_room, is_webinar=is_webinar) vc_room.name = zoom_meeting['topic'] vc_room.data.update({ - 'description': zoom_meeting['agenda'], + 'description': zoom_meeting.get('agenda', ''), 'zoom_id': zoom_meeting['id'], 'password': zoom_meeting['password'], 'mute_host_video': zoom_meeting['settings']['host_video'], From a0bca2e207b109930eb4e9eb3e8cb89a4943e2af Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 1 Dec 2020 15:04:19 +0100 Subject: [PATCH 69/94] VC/Zoom: Use single quotes --- vc_zoom/indico_vc_zoom/api/client.py | 68 ++++++++++++++-------------- vc_zoom/indico_vc_zoom/forms.py | 22 ++++----- vc_zoom/indico_vc_zoom/plugin.py | 22 ++++----- vc_zoom/indico_vc_zoom/util.py | 4 +- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index e97c3fe..030032e 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -21,14 +21,14 @@ def format_iso_dt(d): :param d: The :class:`datetime.datetime` to convert to a string :returns: The string representation of the date """ - return d.astimezone(utc).strftime("%Y-%m-%dT%H:%M:%SZ") + return d.astimezone(utc).strftime('%Y-%m-%dT%H:%M:%SZ') def _handle_response(resp, expected_code=200, expects_json=True): try: resp.raise_for_status() if resp.status_code != expected_code: - raise HTTPError("Unexpected status code {}".format(resp.status_code), response=resp) + raise HTTPError('Unexpected status code {}'.format(resp.status_code), response=resp) except HTTPError: from indico_vc_zoom.plugin import ZoomPlugin ZoomPlugin.logger.error('Error in API call to %s : %s', resp.url, resp.content) @@ -48,10 +48,10 @@ class BaseComponent(object): @property def token(self): - header = {"alg": "HS256", "typ": "JWT"} - payload = {"iss": self.config['api_key'], "exp": int(time.time() + 3600)} - token = jwt.encode(payload, self.config['api_secret'], algorithm="HS256", headers=header) - return token.decode("utf-8") + header = {'alg': 'HS256', 'typ': 'JWT'} + payload = {'iss': self.config['api_key'], 'exp': int(time.time() + 3600)} + token = jwt.encode(payload, self.config['api_secret'], algorithm='HS256', headers=header) + return token.decode('utf-8') @property def session(self): @@ -66,60 +66,60 @@ class BaseComponent(object): class MeetingComponent(BaseComponent): def list(self, user_id, **kwargs): return self.get( - "{}/users/{}/meetings".format(self.base_uri, user_id), params=kwargs + '{}/users/{}/meetings'.format(self.base_uri, user_id), params=kwargs ) def create(self, user_id, **kwargs): - if kwargs.get("start_time"): - kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + if kwargs.get('start_time'): + kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.post( - "{}/users/{}/meetings".format(self.base_uri, user_id), + '{}/users/{}/meetings'.format(self.base_uri, user_id), json=kwargs ) def get(self, meeting_id, **kwargs): - return self.session.get("{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs) + return self.session.get('{}/meetings/{}'.format(self.base_uri, meeting_id), json=kwargs) def update(self, meeting_id, **kwargs): - if kwargs.get("start_time"): - kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + if kwargs.get('start_time'): + kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.patch( - "{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs + '{}/meetings/{}'.format(self.base_uri, meeting_id), json=kwargs ) def delete(self, meeting_id, **kwargs): return self.session.delete( - "{}/meetings/{}".format(self.base_uri, meeting_id), json=kwargs + '{}/meetings/{}'.format(self.base_uri, meeting_id), json=kwargs ) class WebinarComponent(BaseComponent): def list(self, user_id, **kwargs): return self.get( - "{}/users/{}/webinars".format(self.base_uri, user_id), params=kwargs + '{}/users/{}/webinars'.format(self.base_uri, user_id), params=kwargs ) def create(self, user_id, **kwargs): - if kwargs.get("start_time"): - kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + if kwargs.get('start_time'): + kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.post( - "{}/users/{}/webinars".format(self.base_uri, user_id), + '{}/users/{}/webinars'.format(self.base_uri, user_id), json=kwargs ) def get(self, meeting_id, **kwargs): - return self.session.get("{}/webinars/{}".format(self.base_uri, meeting_id), json=kwargs) + return self.session.get('{}/webinars/{}'.format(self.base_uri, meeting_id), json=kwargs) def update(self, meeting_id, **kwargs): - if kwargs.get("start_time"): - kwargs["start_time"] = format_iso_dt(kwargs["start_time"]) + if kwargs.get('start_time'): + kwargs['start_time'] = format_iso_dt(kwargs['start_time']) return self.session.patch( - "{}/webinars/{}".format(self.base_uri, meeting_id), json=kwargs + '{}/webinars/{}'.format(self.base_uri, meeting_id), json=kwargs ) def delete(self, meeting_id, **kwargs): return self.session.delete( - "{}/webinars/{}".format(self.base_uri, meeting_id), json=kwargs + '{}/webinars/{}'.format(self.base_uri, meeting_id), json=kwargs ) @@ -128,31 +128,31 @@ class UserComponent(BaseComponent): return self.get('me') def list(self, **kwargs): - return self.session.get("{}/users".format(self.base_uri), params=kwargs) + return self.session.get('{}/users'.format(self.base_uri), params=kwargs) def create(self, **kwargs): - return self.session.post("{}/users".format(self.base_uri), params=kwargs) + return self.session.post('{}/users'.format(self.base_uri), params=kwargs) def update(self, user_id, **kwargs): - return self.session.patch("{}/users/{}".format(self.base_uri, user_id), params=kwargs) + return self.session.patch('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) def delete(self, user_id, **kwargs): - return self.session.delete("{}/users/{}".format(self.base_uri, user_id), params=kwargs) + return self.session.delete('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) def add_assistant(self, user_id, **kwargs): - return self.session.post("{}/users/{}/assistants".format(self.base_uri, user_id), json=kwargs) + return self.session.post('{}/users/{}/assistants'.format(self.base_uri, user_id), json=kwargs) def get_assistants(self, user_id, **kwargs): - return self.session.get("{}/users/{}/assistants".format(self.base_uri, user_id), params=kwargs) + return self.session.get('{}/users/{}/assistants'.format(self.base_uri, user_id), params=kwargs) def get(self, user_id, **kwargs): - return self.session.get("{}/users/{}".format(self.base_uri, user_id), params=kwargs) + return self.session.get('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) class ZoomClient(object): """Zoom REST API Python Client.""" - BASE_URI = "https://api.zoom.us/v2" + BASE_URI = 'https://api.zoom.us/v2' _components = { 'user': UserComponent, @@ -169,8 +169,8 @@ class ZoomClient(object): """ # Setup the config details config = { - "api_key": api_key, - "api_secret": api_secret + 'api_key': api_key, + 'api_secret': api_secret } # Instantiate the components diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 629f33e..e04ebcc 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -27,13 +27,13 @@ from indico_vc_zoom.util import find_enterprise_email class VCRoomAttachForm(VCRoomAttachFormBase): - password_visibility = IndicoRadioField(_("Passcode visibility"), + password_visibility = IndicoRadioField(_('Passcode visibility'), description=_("Who should be able to know this meeting's passcode"), orientation='horizontal', choices=[ ('everyone', _('Everyone')), ('logged_in', _('Logged-in users')), - ('no_one', _("No one"))]) + ('no_one', _('No one'))]) class VCRoomForm(VCRoomFormBase): @@ -43,30 +43,30 @@ class VCRoomForm(VCRoomFormBase): skip_fields = advanced_fields | VCRoomFormBase.conditional_fields - meeting_type = IndicoRadioField(_("Meeting Type"), - description=_("The type of Zoom meeting to be created"), + meeting_type = IndicoRadioField(_('Meeting Type'), + description=_('The type of Zoom meeting to be created'), orientation='horizontal', choices=[ ('regular', _('Regular Meeting')), ('webinar', _('Webinar'))]) - host_choice = IndicoRadioField(_("Meeting Host"), [DataRequired()], - choices=[('myself', _("Myself")), ('someone_else', _("Someone else"))]) + host_choice = IndicoRadioField(_('Meeting Host'), [DataRequired()], + choices=[('myself', _('Myself')), ('someone_else', _('Someone else'))]) - host_user = PrincipalField(_("User"), + host_user = PrincipalField(_('User'), [HiddenUnless('host_choice', 'someone_else'), DataRequired()]) - password = StringField(_("Passcode"), + password = StringField(_('Passcode'), [DataRequired(), IndicoRegexp(r'^\d{8,}$')], - description=_("Meeting passcode (min. 8 digits)")) + description=_('Meeting passcode (min. 8 digits)')) - password_visibility = IndicoRadioField(_("Passcode visibility"), + password_visibility = IndicoRadioField(_('Passcode visibility'), description=_("Who should be able to know this meeting's passcode"), orientation='horizontal', choices=[ ('everyone', _('Everyone')), ('logged_in', _('Logged-in users')), - ('no_one', _("No one"))]) + ('no_one', _('No one'))]) mute_audio = BooleanField(_('Mute audio'), widget=SwitchWidget(), diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 4ee605b..2ab8097 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -54,7 +54,7 @@ class PluginSettingsForm(VCPluginSettingsFormBase): description=_("Specify Zoom's webhook token if you want live updates")) email_domains = StringField(_('E-mail domains'), [DataRequired()], - description=_("Comma-separated list of e-mail domains which can use the Zoom API.")) + description=_('Comma-separated list of e-mail domains which can use the Zoom API.')) assistant_id = StringField(_('Assistant Zoom ID'), [DataRequired()], description=_('Account to be used as owner of all rooms. It will get "assistant" ' @@ -232,8 +232,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): client.add_assistant_to_user(user_id, assistant_id) except HTTPError as e: if e.response.status_code == 404: - raise NotFound(_("No Zoom account found for this user")) - raise VCRoomError(_("Problem setting Zoom account assistants")) + raise NotFound(_('No Zoom account found for this user')) + raise VCRoomError(_('Problem setting Zoom account assistants')) def create_room(self, vc_room, event): """Create a new Zoom room for an event, given a VC room. @@ -298,7 +298,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): meeting_obj = client.create_meeting(self.settings.get('assistant_id'), **kwargs) except HTTPError as e: self.logger.exception('Error creating Zoom Room: %s', e.response.content) - raise VCRoomError(_("Could not create the room in Zoom. Please contact support if the error persists")) + raise VCRoomError(_('Could not create the room in Zoom. Please contact support if the error persists')) vc_room.data.update({ 'zoom_id': unicode(meeting_obj['id']), @@ -401,7 +401,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): flash(_("Room didn't existing in Zoom anymore"), 'warning') else: self.logger.error("Can't delete room") - raise VCRoomError(_("Problem deleting room")) + raise VCRoomError(_('Problem deleting room')) def get_blueprints(self): return blueprint @@ -457,14 +457,14 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if any(assoc.vc_room.type == 'zoom' and len(assoc.vc_room.events) == 1 for assoc in obj.vc_room_associations): if sender == Event: - message = _("There are one or more scheduled Zoom meetings associated with this event which were not " - "automatically updated.") + message = _('There are one or more scheduled Zoom meetings associated with this event which were not ' + 'automatically updated.') elif sender == Contribution: - message = _("There are one or more scheduled Zoom meetings associated with contribution '{}' which " - " were not automatically updated.").format(obj.title) + message = _('There are one or more scheduled Zoom meetings associated with the contribution "{}" which ' + ' were not automatically updated.').format(obj.title) elif sender == SessionBlock: - message = _("There are one or more scheduled Zoom meetings associated with this session block which " - "were not automatically updated.") + message = _('There are one or more scheduled Zoom meetings associated with this session block which ' + 'were not automatically updated.') else: return diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 12d297e..d947a60 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -71,11 +71,11 @@ def fetch_zoom_meeting(vc_room, client=None, is_webinar=False): except HTTPError as e: if e.response.status_code in {400, 404}: # Indico will automatically mark this room as deleted - raise VCRoomNotFoundError(_("This room has been deleted from Zoom")) + raise VCRoomNotFoundError(_('This room has been deleted from Zoom')) else: from indico_vc_zoom.plugin import ZoomPlugin ZoomPlugin.logger.exception('Error getting Zoom Room: %s', e.response.content) - raise VCRoomError(_("Problem fetching room from Zoom. Please contact support if the error persists.")) + raise VCRoomError(_('Problem fetching room from Zoom. Please contact support if the error persists.')) def update_zoom_meeting(zoom_id, changes, is_webinar=False): From e2bfceb99a7d2c2a0f4cdca1fb0a4c37de3b6ae2 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 1 Dec 2020 18:18:11 +0100 Subject: [PATCH 70/94] VC/Zoom: Support getting users via authenticators --- vc_zoom/indico_vc_zoom/forms.py | 3 +- vc_zoom/indico_vc_zoom/plugin.py | 63 +++++++++++++++++++++------- vc_zoom/indico_vc_zoom/util.py | 70 +++++++++++++++++++++++++------- vc_zoom/tests/operation_test.py | 1 + 4 files changed, 107 insertions(+), 30 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index e04ebcc..2f95ee8 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -113,8 +113,7 @@ class VCRoomForm(VCRoomFormBase): self._check_zoom_user(field.data) def _check_zoom_user(self, user): - email = find_enterprise_email(user) - if email is None or ZoomIndicoClient().get_user(email, silent=True) is None: + if find_enterprise_email(user) is None: raise ValidationError(_('This user has no Zoom account')) def validate_name(self, field): diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 2ab8097..99231c6 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -8,15 +8,17 @@ from __future__ import unicode_literals from flask import flash, session +from markupsafe import escape from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified from werkzeug.exceptions import Forbidden, NotFound from wtforms.fields.core import BooleanField from wtforms.fields import TextAreaField from wtforms.fields.simple import StringField -from wtforms.validators import DataRequired +from wtforms.validators import DataRequired, ValidationError from indico.core import signals +from indico.core.auth import multipass from indico.core.plugins import IndicoPlugin, render_plugin_template, url_for_plugin from indico.modules.events.views import WPSimpleEventDisplay from indico.modules.vc import VCPluginMixin, VCPluginSettingsFormBase @@ -24,7 +26,8 @@ from indico.modules.vc.exceptions import VCRoomError from indico.modules.vc.models.vc_rooms import VCRoom from indico.modules.vc.views import WPVCEventPage, WPVCManageEvent from indico.util.user import principal_from_identifier -from indico.web.forms.fields.simple import IndicoPasswordField +from indico.web.forms.fields import IndicoEnumSelectField, IndicoPasswordField, TextListField +from indico.web.forms.validators import HiddenUnless from indico.web.forms.widgets import CKEditorWidget, SwitchWidget from indico_vc_zoom import _ @@ -33,14 +36,15 @@ from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url -from indico_vc_zoom.util import (fetch_zoom_meeting, find_enterprise_email, gen_random_password, get_schedule_args, - get_url_data_args, update_zoom_meeting, ZoomMeetingType) +from indico_vc_zoom.util import (UserLookupMode, fetch_zoom_meeting, find_enterprise_email, gen_random_password, + get_schedule_args, get_url_data_args, update_zoom_meeting, ZoomMeetingType) class PluginSettingsForm(VCPluginSettingsFormBase): _fieldsets = [ ('API Credentials', ['api_key', 'api_secret', 'webhook_token']), - ('Zoom Account', ['email_domains', 'assistant_id', 'allow_webinars']), + ('Zoom Account', ['user_lookup_mode', 'email_domains', 'authenticators', 'enterprise_domain', 'assistant_id', + 'allow_webinars']), ('Room Settings', ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host', 'waiting_room']), ('Notifications', ['creation_email_footer', 'send_host_url']) @@ -53,8 +57,27 @@ class PluginSettingsForm(VCPluginSettingsFormBase): webhook_token = IndicoPasswordField(_('Webhook Token'), toggle=True, description=_("Specify Zoom's webhook token if you want live updates")) - email_domains = StringField(_('E-mail domains'), [DataRequired()], - description=_('Comma-separated list of e-mail domains which can use the Zoom API.')) + user_lookup_mode = IndicoEnumSelectField(_('User lookup mode'), [DataRequired()], enum=UserLookupMode, + description=_('Specify how Indico should look up the zoom user that ' + 'corresponds to an Indico user.')) + + email_domains = TextListField(_('E-mail domains'), + [HiddenUnless('user_lookup_mode', UserLookupMode.email_domains), DataRequired()], + description=_('List of e-mail domains which can use the Zoom API. Indico attempts ' + 'to find Zoom accounts using all email addresses of a user which use ' + 'those domains.')) + + authenticators = TextListField(_('Indico identity providers'), + [HiddenUnless('user_lookup_mode', UserLookupMode.authenticators), DataRequired()], + description=_('Identity providers from which to get usernames. ' + 'Indico queries those providers using the email addresses of the user ' + 'and attempts to find Zoom accounts having an email address looking ' + 'like @.')) + + enterprise_domain = StringField(_('Enterprise domain'), + [HiddenUnless('user_lookup_mode', UserLookupMode.authenticators), DataRequired()], + description=_('The domain name used together with the usernames from the Indico ' + 'identity provider')) assistant_id = StringField(_('Assistant Zoom ID'), [DataRequired()], description=_('Account to be used as owner of all rooms. It will get "assistant" ' @@ -93,6 +116,11 @@ class PluginSettingsForm(VCPluginSettingsFormBase): description=_('Whether to send an e-mail with the Host URL to the meeting host upon ' 'creation of a meeting')) + def validate_authenticators(self, field): + invalid = set(field.data) - set(multipass.identity_providers) + if invalid: + raise ValidationError(_('Invalid identity providers: {}').format(escape(', '.join(invalid)))) + class ZoomPlugin(VCPluginMixin, IndicoPlugin): """Zoom @@ -109,7 +137,10 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'api_key': '', 'api_secret': '', 'webhook_token': '', - 'email_domains': '', + 'user_lookup_mode': UserLookupMode.email_domains, + 'email_domains': [], + 'authenticators': [], + 'enterprise_domain': '', 'allow_webinars': False, 'mute_host_video': True, 'mute_audio': True, @@ -334,12 +365,16 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if not email: raise Forbidden(_("This user doesn't seem to have an associated Zoom account")) - if is_webinar: - changes.setdefault('settings', {})['alternative_hosts'] = email - else: - changes['schedule_for'] = email - self._check_indico_is_assistant(email) - notify_new_host(session.user, vc_room) + # When using authenticator mode for user lookups, the email address used on zoom + # may not be an email address the Indico user has, so we can only check if the host + # really changed after checking for the zoom account. + if host_data['email'] != email: + if is_webinar: + changes.setdefault('settings', {})['alternative_hosts'] = email + else: + changes['schedule_for'] = email + self._check_indico_is_assistant(email) + notify_new_host(session.user, vc_room) if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index d947a60..8ff9068 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -16,14 +16,15 @@ from indico.core.db import db from indico.modules.users.models.emails import UserEmail from indico.modules.users.models.users import User from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError +from indico.util.caching import memoize_request from indico.util.date_time import now_utc -from indico.util.struct.enum import RichIntEnum +from indico.util.struct.enum import IndicoEnum, RichEnum from indico_vc_zoom import _ from indico_vc_zoom.api import ZoomIndicoClient -class ZoomMeetingType(RichIntEnum): +class ZoomMeetingType(int, IndicoEnum): instant_meeting = 1 scheduled_meeting = 2 recurring_meeting_no_time = 3 @@ -33,22 +34,63 @@ class ZoomMeetingType(RichIntEnum): recurring_meeting_fixed_time = 9 -def find_enterprise_email(user): - """Find a user's first e-mail address which can be used by the Zoom API. +class UserLookupMode(unicode, RichEnum): + __titles__ = { + 'email_domains': _('Email domains'), + 'authenticators': _('Authenticators'), + } + + @property + def title(self): + return RichEnum.title.__get__(self, type(self)) + + email_domains = 'email_domains' + authenticators = 'authenticators' + + +def _iter_user_identifiers(user): + """Iterates over all existing user identifiers that can be used with Zoom""" + from indico_vc_zoom.plugin import ZoomPlugin + done = set() + for provider in ZoomPlugin.settings.get('authenticators'): + for __, identifier in user.iter_identifiers(check_providers=True, providers={provider}): + if identifier in done: + continue + done.add(identifier) + yield identifier + + +def _iter_user_emails(user): + """Yield all emails of a user that may work with zoom. :param user: the `User` in question - :return: the e-mail address if it exists, otherwise `None` """ from indico_vc_zoom.plugin import ZoomPlugin - domains = [domain.strip() for domain in ZoomPlugin.settings.get('email_domains').split(',')] - # get all matching e-mails, primary first - result = UserEmail.query.filter( - UserEmail.user == user, - ~User.is_blocked, - ~User.is_deleted, - db.or_(UserEmail.email.endswith(domain) for domain in domains) - ).join(User).order_by(UserEmail.is_primary.desc()).first() - return result.email if result else None + mode = ZoomPlugin.settings.get('user_lookup_mode') + if mode == UserLookupMode.email_domains: + domains = ZoomPlugin.settings.get('email_domains') + if not domains: + return + # get all matching e-mails, primary first + query = UserEmail.query.filter( + UserEmail.user == user, + ~User.is_blocked, + ~User.is_deleted, + db.or_(UserEmail.email.endswith('@{}'.format(domain)) for domain in domains) + ).join(User).order_by(UserEmail.is_primary.desc()) + for entry in query: + yield entry.email + elif mode == UserLookupMode.authenticators: + domain = ZoomPlugin.settings.get('enterprise_domain') + for username in _iter_user_identifiers(user): + yield '{}@{}'.format(username, domain) + + +@memoize_request +def find_enterprise_email(user): + """Get the email address of a user that has a zoom account.""" + client = ZoomIndicoClient() + return next((email for email in _iter_user_emails(user) if client.get_user(email, silent=True)), None) def gen_random_password(): diff --git a/vc_zoom/tests/operation_test.py b/vc_zoom/tests/operation_test.py index 9073ca4..86f7f61 100644 --- a/vc_zoom/tests/operation_test.py +++ b/vc_zoom/tests/operation_test.py @@ -107,6 +107,7 @@ def test_room_creation(create_meeting, zoom_api): def test_host_change(create_user, mocker, create_meeting, zoom_plugin, zoom_api, request_context): + mocker.patch('indico_vc_zoom.plugin.find_enterprise_email', return_value='joe.bidon@megacorp.xyz') notify_new_host = mocker.patch('indico_vc_zoom.plugin.notify_new_host') create_user(2, email='joe.bidon@megacorp.xyz') From 030fd37a67623d58eb219018a275008d4aef4f63 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Wed, 2 Dec 2020 13:25:03 +0100 Subject: [PATCH 71/94] VC/Zoom: Add a changelog --- vc_zoom/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index 2898d73..01478bf 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -9,6 +9,22 @@ * Protection of Zoom link (only logged in, everyone or no one) * Webinar mode; +## Changelog + +### 2.3b2 + +- Improve logging when a Zoom API request fails +- Fail more gracefully if no Zoom account could be found for a user +- Allow using the same name for multiple Zoom rooms +- Update the join url when changing the passcode +- Provide an alternative method of looking up the Zoom user corresponding to an Indico user + +**Breaking change:** The email domains are now stored as a list of strings instead of a comma-separated list. You need to update them in the plugin settings. + +### 2.3b1 + +- Initial beta release + ## Implementation details Rooms are created under the account of an *assistant user* which can be set using the **Assistant Zoom ID** From e2aab289f998b86886e6b05bf35fcc81fefe6be9 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Wed, 2 Dec 2020 13:37:48 +0100 Subject: [PATCH 72/94] VC/Zoom: Fix form field description --- vc_zoom/indico_vc_zoom/plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 99231c6..9f09455 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -71,8 +71,8 @@ class PluginSettingsForm(VCPluginSettingsFormBase): [HiddenUnless('user_lookup_mode', UserLookupMode.authenticators), DataRequired()], description=_('Identity providers from which to get usernames. ' 'Indico queries those providers using the email addresses of the user ' - 'and attempts to find Zoom accounts having an email address looking ' - 'like @.')) + 'and attempts to find Zoom accounts having an email address with the ' + 'format username@enterprise-domain.')) enterprise_domain = StringField(_('Enterprise domain'), [HiddenUnless('user_lookup_mode', UserLookupMode.authenticators), DataRequired()], From 65c9f54acadda5abc2d0444a5790769f9cd72467 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Wed, 2 Dec 2020 14:21:41 +0100 Subject: [PATCH 73/94] VC/Zoom: Remove weird space --- vc_zoom/indico_vc_zoom/api/client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index 030032e..9477a25 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -31,7 +31,7 @@ def _handle_response(resp, expected_code=200, expects_json=True): raise HTTPError('Unexpected status code {}'.format(resp.status_code), response=resp) except HTTPError: from indico_vc_zoom.plugin import ZoomPlugin - ZoomPlugin.logger.error('Error in API call to %s : %s', resp.url, resp.content) + ZoomPlugin.logger.error('Error in API call to %s: %s', resp.url, resp.content) raise return resp.json() if expects_json else resp From 7bf2dfac8e54885ce39c9e5e4c7a345686afb02a Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Wed, 2 Dec 2020 16:56:29 +0100 Subject: [PATCH 74/94] VC/Zoom: Add option to require registered participants --- vc_zoom/README.md | 2 ++ vc_zoom/indico_vc_zoom/forms.py | 3 +- vc_zoom/indico_vc_zoom/templates/buttons.html | 29 +++++++++++++++++-- .../indico_vc_zoom/templates/info_box.html | 6 ++-- .../templates/management_buttons.html | 2 +- 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index 01478bf..2b0b2d8 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -18,6 +18,8 @@ - Allow using the same name for multiple Zoom rooms - Update the join url when changing the passcode - Provide an alternative method of looking up the Zoom user corresponding to an Indico user +- Always show the full join link and passcode to event managers +- The meeting passcode can be restricted to registered participants **Breaking change:** The email domains are now stored as a list of strings instead of a comma-separated list. You need to update them in the plugin settings. diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 2f95ee8..36436f0 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -22,7 +22,6 @@ from indico.web.forms.validators import HiddenUnless, IndicoRegexp from indico.web.forms.widgets import SwitchWidget from indico_vc_zoom import _ -from indico_vc_zoom.api.client import ZoomIndicoClient from indico_vc_zoom.util import find_enterprise_email @@ -33,6 +32,7 @@ class VCRoomAttachForm(VCRoomAttachFormBase): choices=[ ('everyone', _('Everyone')), ('logged_in', _('Logged-in users')), + ('registered', _('Registered participants')), ('no_one', _('No one'))]) @@ -66,6 +66,7 @@ class VCRoomForm(VCRoomFormBase): choices=[ ('everyone', _('Everyone')), ('logged_in', _('Logged-in users')), + ('registered', _('Registered participants')), ('no_one', _('No one'))]) mute_audio = BooleanField(_('Mute audio'), diff --git a/vc_zoom/indico_vc_zoom/templates/buttons.html b/vc_zoom/indico_vc_zoom/templates/buttons.html index f64fcc5..bbe2157 100644 --- a/vc_zoom/indico_vc_zoom/templates/buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/buttons.html @@ -14,9 +14,11 @@ {% endif %} {% endmacro %} -{% macro render_join_button(vc_room, event_vc_room, extra_classes="", is_manager=false) %} - {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or - (session.user and event_vc_room.data.password_visibility == 'logged_in') %} +{% macro render_join_button(vc_room, event_vc_room, extra_classes='') %} + {% if event_vc_room.data.password_visibility == 'everyone' or + event_vc_room.event.can_manage(session.user) or + (session.user and event_vc_room.data.password_visibility == 'logged_in') or + (session.user and event_vc_room.data.password_visibility == 'registered' and event_vc_room.event.is_user_registered(session.user)) %} {% trans %}Join{% endtrans %} @@ -27,6 +29,27 @@ href="{{ vc_room.data.public_url }}"> {% trans %}Join{% endtrans %} + {% elif event_vc_room.data.password_visibility == 'registered' %} + {% if session.user %} + {% if event_vc_room.event.type == 'conference' %} + + {% trans %}Please register{% endtrans %} + + {% else %} + + {% trans %}Registration required{% endtrans %} + + {% endif %} + {% else %} + + {% trans %}Please log in and register{% endtrans %} + + {% endif %} {% else %} {% trans %}Host{% endtrans %}
    {{ (host|decodeprincipal).full_name }}
    {% endif %} - {% if event_vc_room.data.password_visibility == 'everyone' or is_manager or - (session.user and event_vc_room.data.password_visibility == 'logged_in') %} + {% if event_vc_room.data.password_visibility == 'everyone' or + event_vc_room.event.can_manage(session.user) or + (session.user and event_vc_room.data.password_visibility == 'logged_in') or + (session.user and event_vc_room.data.password_visibility == 'registered' and event_vc_room.event.is_user_registered(session.user)) %}
    {% trans %}Passcode{% endtrans %}
    {{ vc_room.data.password }}
    {% endif %} diff --git a/vc_zoom/indico_vc_zoom/templates/management_buttons.html b/vc_zoom/indico_vc_zoom/templates/management_buttons.html index ac8a8b6..81c7616 100644 --- a/vc_zoom/indico_vc_zoom/templates/management_buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/management_buttons.html @@ -2,5 +2,5 @@ {% from 'vc_zoom:buttons.html' import render_join_button %} {% block buttons %} - {{ render_join_button(vc_room, event_vc_room, extra_classes="icon-play", is_manager=true) }} + {{ render_join_button(vc_room, event_vc_room, extra_classes='icon-play') }} {% endblock %} From ac27a6475c417fa8106006ddb13b8693429aa470 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Thu, 3 Dec 2020 10:09:38 +0100 Subject: [PATCH 75/94] VC/Zoom: Add "make me host" button in mgmt and timetable --- vc_zoom/README.md | 1 + vc_zoom/indico_vc_zoom/templates/management_buttons.html | 3 ++- .../indico_vc_zoom/templates/vc_room_timetable_buttons.html | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index 2b0b2d8..f86394a 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -20,6 +20,7 @@ - Provide an alternative method of looking up the Zoom user corresponding to an Indico user - Always show the full join link and passcode to event managers - The meeting passcode can be restricted to registered participants +- Show "Make me host" button in the management area and in contributions/sessions as well **Breaking change:** The email domains are now stored as a list of strings instead of a comma-separated list. You need to update them in the plugin settings. diff --git a/vc_zoom/indico_vc_zoom/templates/management_buttons.html b/vc_zoom/indico_vc_zoom/templates/management_buttons.html index 81c7616..2ec6e31 100644 --- a/vc_zoom/indico_vc_zoom/templates/management_buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/management_buttons.html @@ -1,6 +1,7 @@ {% extends 'vc/management_buttons.html' %} -{% from 'vc_zoom:buttons.html' import render_join_button %} +{% from 'vc_zoom:buttons.html' import render_join_button, render_make_me_owner %} {% block buttons %} {{ render_join_button(vc_room, event_vc_room, extra_classes='icon-play') }} + {{ render_make_me_owner(event_vc_room.event, vc_room, event_vc_room) }} {% endblock %} diff --git a/vc_zoom/indico_vc_zoom/templates/vc_room_timetable_buttons.html b/vc_zoom/indico_vc_zoom/templates/vc_room_timetable_buttons.html index c1db6a8..67c79c1 100644 --- a/vc_zoom/indico_vc_zoom/templates/vc_room_timetable_buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/vc_room_timetable_buttons.html @@ -1,7 +1,8 @@ {% extends 'vc/vc_room_timetable_buttons.html' %} -{% from 'vc_zoom:buttons.html' import render_join_button %} +{% from 'vc_zoom:buttons.html' import render_join_button, render_make_me_owner %} {% set vc_room = event_vc_room.vc_room %} {% block buttons %} {{ render_join_button(vc_room, event_vc_room, "i-button-small event-service-right-button join-button") }} + {{ render_make_me_owner(event, vc_room, event_vc_room, extra_classes="i-button-small") }} {% endblock %} From 0de73f3e2f9b30741d1dcf3d7ede94963a4400d2 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Thu, 3 Dec 2020 11:17:56 +0100 Subject: [PATCH 76/94] VC/Zoom: Warn on deletion if user is not the host --- vc_zoom/README.md | 1 + vc_zoom/indico_vc_zoom/plugin.py | 6 ++++++ vc_zoom/indico_vc_zoom/templates/extra_delete_msg.html | 7 +++++++ 3 files changed, 14 insertions(+) create mode 100644 vc_zoom/indico_vc_zoom/templates/extra_delete_msg.html diff --git a/vc_zoom/README.md b/vc_zoom/README.md index f86394a..a3f0214 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -21,6 +21,7 @@ - Always show the full join link and passcode to event managers - The meeting passcode can be restricted to registered participants - Show "Make me host" button in the management area and in contributions/sessions as well +- Warn the user if they delete a Zoom meeting linked to multiple events if they aren't the host **Breaking change:** The email domains are now stored as a list of strings instead of a comma-separated list. You need to update them in the plugin settings. diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 9f09455..1914dfa 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -189,6 +189,12 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): form.password.data = gen_random_password() return form + def get_extra_delete_msg(self, vc_room, event_vc_room): + host = principal_from_identifier(vc_room.data['host']) + if host == session.user or len(vc_room.events) <= 1: + return '' + return render_plugin_template('vc_zoom:extra_delete_msg.html', host=host.full_name) + def _extend_indico_cli(self, sender, **kwargs): return cli diff --git a/vc_zoom/indico_vc_zoom/templates/extra_delete_msg.html b/vc_zoom/indico_vc_zoom/templates/extra_delete_msg.html new file mode 100644 index 0000000..c936287 --- /dev/null +++ b/vc_zoom/indico_vc_zoom/templates/extra_delete_msg.html @@ -0,0 +1,7 @@ +

    + {% trans %} + The host of this Zoom meeting is {{ host }}. In case you want + to delete this Zoom meeting from all events, please make sure that they do not + use it for other events that may still need it! + {% endtrans %} +

    From 3b56d304c478c280432542f9d22c95f249817d06 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Thu, 3 Dec 2020 12:02:07 +0100 Subject: [PATCH 77/94] Use union merge for zoom README Conflicts are likely in the changelog where this can usually resolve them. --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dde164b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +vc_zoom/README.md merge=union From 5d4fd976c66de160ce2ad5d98ffd0dfce8851a7f Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Wed, 2 Dec 2020 16:48:18 +0100 Subject: [PATCH 78/94] VC/Zoom: set meeting recurrence when cloning event --- vc_zoom/README.md | 1 + vc_zoom/indico_vc_zoom/plugin.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index a3f0214..deac4a1 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -22,6 +22,7 @@ - The meeting passcode can be restricted to registered participants - Show "Make me host" button in the management area and in contributions/sessions as well - Warn the user if they delete a Zoom meeting linked to multiple events if they aren't the host +- Change Zoom meeting to "recurring meeting" when cloning an event **Breaking change:** The email domains are now stored as a list of strings instead of a comma-separated list. You need to update them in the plugin settings. diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 1914dfa..d02f211 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -444,6 +444,25 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): self.logger.error("Can't delete room") raise VCRoomError(_('Problem deleting room')) + def clone_room(self, old_event_vc_room, link_object): + vc_room = old_event_vc_room.vc_room + is_webinar = vc_room.data.get('meeting_type', 'regular') == 'webinar' + has_only_one_association = len({assoc.event_id for assoc in vc_room.events}) == 1 + new_assoc = super(ZoomPlugin, self).clone_room(old_event_vc_room, link_object) + + if has_only_one_association: + update_zoom_meeting(vc_room.data['zoom_id'], { + 'start_time': None, + 'duration': None, + 'type': ( + ZoomMeetingType.recurring_webinar_no_time + if is_webinar + else ZoomMeetingType.recurring_meeting_no_time + ) + }) + + return new_assoc + def get_blueprints(self): return blueprint From 4063f405e91691578bfcae5af163d8b83bee9dc2 Mon Sep 17 00:00:00 2001 From: Indico Team Date: Thu, 3 Dec 2020 13:12:08 +0100 Subject: [PATCH 79/94] Update *.pot files --- .../indico_vc_zoom/translations/messages.pot | 225 ++++++++++++------ 1 file changed, 153 insertions(+), 72 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/translations/messages.pot b/vc_zoom/indico_vc_zoom/translations/messages.pot index b3ad8ad..d90908c 100644 --- a/vc_zoom/indico_vc_zoom/translations/messages.pot +++ b/vc_zoom/indico_vc_zoom/translations/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-11-25 15:55+0100\n" +"POT-Creation-Date: 2020-12-03 13:11+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -21,239 +21,294 @@ msgstr "" msgid "You are now the host of room '{room.name}'" msgstr "" -#: indico_vc_zoom/forms.py:28 indico_vc_zoom/forms.py:61 +#: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:63 msgid "Passcode visibility" msgstr "" -#: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:62 +#: indico_vc_zoom/forms.py:30 indico_vc_zoom/forms.py:64 msgid "Who should be able to know this meeting's passcode" msgstr "" -#: indico_vc_zoom/forms.py:32 indico_vc_zoom/forms.py:65 +#: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:67 msgid "Everyone" msgstr "" -#: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:66 +#: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:68 msgid "Logged-in users" msgstr "" -#: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:67 +#: indico_vc_zoom/forms.py:35 indico_vc_zoom/forms.py:69 +msgid "Registered participants" +msgstr "" + +#: indico_vc_zoom/forms.py:36 indico_vc_zoom/forms.py:70 msgid "No one" msgstr "" -#: indico_vc_zoom/forms.py:44 +#: indico_vc_zoom/forms.py:46 msgid "Meeting Type" msgstr "" -#: indico_vc_zoom/forms.py:45 +#: indico_vc_zoom/forms.py:47 msgid "The type of Zoom meeting to be created" msgstr "" -#: indico_vc_zoom/forms.py:48 +#: indico_vc_zoom/forms.py:50 msgid "Regular Meeting" msgstr "" -#: indico_vc_zoom/forms.py:49 indico_vc_zoom/templates/room_labels.html:4 +#: indico_vc_zoom/forms.py:51 indico_vc_zoom/templates/room_labels.html:4 msgid "Webinar" msgstr "" -#: indico_vc_zoom/forms.py:51 +#: indico_vc_zoom/forms.py:53 msgid "Meeting Host" msgstr "" -#: indico_vc_zoom/forms.py:52 +#: indico_vc_zoom/forms.py:54 msgid "Myself" msgstr "" -#: indico_vc_zoom/forms.py:52 +#: indico_vc_zoom/forms.py:54 msgid "Someone else" msgstr "" -#: indico_vc_zoom/forms.py:54 +#: indico_vc_zoom/forms.py:56 msgid "User" msgstr "" -#: indico_vc_zoom/forms.py:57 indico_vc_zoom/templates/info_box.html:16 +#: indico_vc_zoom/forms.py:59 indico_vc_zoom/templates/info_box.html:18 #: indico_vc_zoom/templates/manage_event_info_box.html:28 msgid "Passcode" msgstr "" -#: indico_vc_zoom/forms.py:59 +#: indico_vc_zoom/forms.py:61 msgid "Meeting passcode (min. 8 digits)" msgstr "" -#: indico_vc_zoom/forms.py:69 indico_vc_zoom/plugin.py:67 +#: indico_vc_zoom/forms.py:72 indico_vc_zoom/plugin.py:90 msgid "Mute audio" msgstr "" -#: indico_vc_zoom/forms.py:71 indico_vc_zoom/plugin.py:69 +#: indico_vc_zoom/forms.py:74 indico_vc_zoom/plugin.py:92 msgid "Participants will join the VC room muted by default " msgstr "" -#: indico_vc_zoom/forms.py:73 indico_vc_zoom/plugin.py:71 +#: indico_vc_zoom/forms.py:76 indico_vc_zoom/plugin.py:94 msgid "Mute video (host)" msgstr "" -#: indico_vc_zoom/forms.py:75 indico_vc_zoom/plugin.py:73 +#: indico_vc_zoom/forms.py:78 indico_vc_zoom/plugin.py:96 msgid "The host will join the VC room with video disabled" msgstr "" -#: indico_vc_zoom/forms.py:77 indico_vc_zoom/plugin.py:75 +#: indico_vc_zoom/forms.py:80 indico_vc_zoom/plugin.py:98 msgid "Mute video (participants)" msgstr "" -#: indico_vc_zoom/forms.py:79 indico_vc_zoom/plugin.py:77 +#: indico_vc_zoom/forms.py:82 indico_vc_zoom/plugin.py:100 msgid "Participants will join the VC room with video disabled" msgstr "" -#: indico_vc_zoom/forms.py:81 indico_vc_zoom/plugin.py:84 +#: indico_vc_zoom/forms.py:84 indico_vc_zoom/plugin.py:107 msgid "Waiting room" msgstr "" -#: indico_vc_zoom/forms.py:83 indico_vc_zoom/plugin.py:86 +#: indico_vc_zoom/forms.py:86 indico_vc_zoom/plugin.py:109 msgid "Participants may be kept in a waiting room by the host" msgstr "" -#: indico_vc_zoom/forms.py:85 indico_vc_zoom/templates/info_box.html:7 +#: indico_vc_zoom/forms.py:88 indico_vc_zoom/templates/info_box.html:7 #: indico_vc_zoom/templates/manage_event_info_box.html:8 msgid "Description" msgstr "" -#: indico_vc_zoom/forms.py:85 +#: indico_vc_zoom/forms.py:88 msgid "Optional description for this room" msgstr "" -#: indico_vc_zoom/plugin.py:49 -msgid "API Key" -msgstr "" - -#: indico_vc_zoom/plugin.py:51 -msgid "API Secret" +#: indico_vc_zoom/forms.py:118 +msgid "This user has no Zoom account" msgstr "" #: indico_vc_zoom/plugin.py:53 -msgid "Webhook Token" +msgid "API Key" msgstr "" -#: indico_vc_zoom/plugin.py:54 -msgid "Specify Zoom's webhook token if you want live updates" -msgstr "" - -#: indico_vc_zoom/plugin.py:56 -msgid "E-mail domains" +#: indico_vc_zoom/plugin.py:55 +msgid "API Secret" msgstr "" #: indico_vc_zoom/plugin.py:57 -msgid "Comma-separated list of e-mail domains which can use the Zoom API." +msgid "Webhook Token" msgstr "" -#: indico_vc_zoom/plugin.py:59 -msgid "Assistant Zoom ID" +#: indico_vc_zoom/plugin.py:58 +msgid "Specify Zoom's webhook token if you want live updates" msgstr "" #: indico_vc_zoom/plugin.py:60 +msgid "User lookup mode" +msgstr "" + +#: indico_vc_zoom/plugin.py:61 +msgid "" +"Specify how Indico should look up the zoom user that corresponds to an " +"Indico user." +msgstr "" + +#: indico_vc_zoom/plugin.py:64 +msgid "E-mail domains" +msgstr "" + +#: indico_vc_zoom/plugin.py:66 +msgid "" +"List of e-mail domains which can use the Zoom API. Indico attempts to " +"find Zoom accounts using all email addresses of a user which use those " +"domains." +msgstr "" + +#: indico_vc_zoom/plugin.py:70 +msgid "Indico identity providers" +msgstr "" + +#: indico_vc_zoom/plugin.py:72 +msgid "" +"Identity providers from which to get usernames. Indico queries those " +"providers using the email addresses of the user and attempts to find Zoom" +" accounts having an email address with the format username@enterprise-" +"domain." +msgstr "" + +#: indico_vc_zoom/plugin.py:77 +msgid "Enterprise domain" +msgstr "" + +#: indico_vc_zoom/plugin.py:79 +msgid "" +"The domain name used together with the usernames from the Indico identity" +" provider" +msgstr "" + +#: indico_vc_zoom/plugin.py:82 +msgid "Assistant Zoom ID" +msgstr "" + +#: indico_vc_zoom/plugin.py:83 msgid "" "Account to be used as owner of all rooms. It will get \"assistant\" " "privileges on all accounts for which it books rooms" msgstr "" -#: indico_vc_zoom/plugin.py:63 +#: indico_vc_zoom/plugin.py:86 msgid "Allow Webinars (Experimental)" msgstr "" -#: indico_vc_zoom/plugin.py:65 +#: indico_vc_zoom/plugin.py:88 msgid "Allow webinars to be created through Indico. Use at your own risk." msgstr "" -#: indico_vc_zoom/plugin.py:79 +#: indico_vc_zoom/plugin.py:102 msgid "Join Before Host" msgstr "" -#: indico_vc_zoom/plugin.py:81 +#: indico_vc_zoom/plugin.py:104 msgid "" "Allow participants to join the meeting before the host starts the " "meeting. Only used for scheduled or recurring meetings." msgstr "" -#: indico_vc_zoom/plugin.py:88 +#: indico_vc_zoom/plugin.py:111 msgid "Creation email footer" msgstr "" -#: indico_vc_zoom/plugin.py:89 +#: indico_vc_zoom/plugin.py:112 msgid "Footer to append to emails sent upon creation of a VC room" msgstr "" -#: indico_vc_zoom/plugin.py:91 +#: indico_vc_zoom/plugin.py:114 msgid "Send host URL" msgstr "" -#: indico_vc_zoom/plugin.py:93 +#: indico_vc_zoom/plugin.py:116 msgid "" "Whether to send an e-mail with the Host URL to the meeting host upon " "creation of a meeting" msgstr "" -#: indico_vc_zoom/plugin.py:233 +#: indico_vc_zoom/plugin.py:122 +msgid "Invalid identity providers: {}" +msgstr "" + +#: indico_vc_zoom/plugin.py:272 msgid "No Zoom account found for this user" msgstr "" -#: indico_vc_zoom/plugin.py:235 -msgid "Problem getting information about Zoom account" +#: indico_vc_zoom/plugin.py:273 +msgid "Problem setting Zoom account assistants" msgstr "" -#: indico_vc_zoom/plugin.py:302 +#: indico_vc_zoom/plugin.py:338 msgid "" "Could not create the room in Zoom. Please contact support if the error " "persists" msgstr "" -#: indico_vc_zoom/plugin.py:331 +#: indico_vc_zoom/plugin.py:365 msgid "" "Can't get information about user. Please contact support if the error " "persists." msgstr "" -#: indico_vc_zoom/plugin.py:338 +#: indico_vc_zoom/plugin.py:372 msgid "This user doesn't seem to have an associated Zoom account" msgstr "" -#: indico_vc_zoom/plugin.py:402 +#: indico_vc_zoom/plugin.py:442 msgid "Room didn't existing in Zoom anymore" msgstr "" -#: indico_vc_zoom/plugin.py:405 +#: indico_vc_zoom/plugin.py:445 msgid "Problem deleting room" msgstr "" -#: indico_vc_zoom/plugin.py:461 +#: indico_vc_zoom/plugin.py:520 msgid "" "There are one or more scheduled Zoom meetings associated with this event " "which were not automatically updated." msgstr "" -#: indico_vc_zoom/plugin.py:464 +#: indico_vc_zoom/plugin.py:523 msgid "" -"There are one or more scheduled Zoom meetings associated with " -"contribution '{}' which were not automatically updated." +"There are one or more scheduled Zoom meetings associated with the " +"contribution \"{}\" which were not automatically updated." msgstr "" -#: indico_vc_zoom/plugin.py:467 +#: indico_vc_zoom/plugin.py:526 msgid "" "There are one or more scheduled Zoom meetings associated with this " "session block which were not automatically updated." msgstr "" -#: indico_vc_zoom/util.py:74 +#: indico_vc_zoom/util.py:39 +msgid "Email domains" +msgstr "" + +#: indico_vc_zoom/util.py:40 +msgid "Authenticators" +msgstr "" + +#: indico_vc_zoom/util.py:116 msgid "This room has been deleted from Zoom" msgstr "" -#: indico_vc_zoom/util.py:78 +#: indico_vc_zoom/util.py:120 msgid "" "Problem fetching room from Zoom. Please contact support if the error " "persists." msgstr "" -#: indico_vc_zoom/util.py:97 +#: indico_vc_zoom/util.py:139 msgid "Can't update meeting. Please contact support if the error persists." msgstr "" @@ -265,23 +320,49 @@ msgstr "" msgid "Make me host" msgstr "" -#: indico_vc_zoom/templates/buttons.html:22 -#: indico_vc_zoom/templates/buttons.html:28 +#: indico_vc_zoom/templates/buttons.html:24 +#: indico_vc_zoom/templates/buttons.html:30 msgid "Join" msgstr "" -#: indico_vc_zoom/templates/buttons.html:26 +#: indico_vc_zoom/templates/buttons.html:28 msgid "You will need a passcode to join this Zoom meeting" msgstr "" -#: indico_vc_zoom/templates/buttons.html:32 +#: indico_vc_zoom/templates/buttons.html:36 +#: indico_vc_zoom/templates/buttons.html:42 +#: indico_vc_zoom/templates/buttons.html:48 +msgid "This Zoom Meeting can only be seen by registered participants" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:38 +msgid "Please register" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:43 +msgid "Registration required" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:50 +msgid "Please log in and register" +msgstr "" + +#: indico_vc_zoom/templates/buttons.html:55 msgid "This Zoom Meeting can only be seen by logged in users" msgstr "" -#: indico_vc_zoom/templates/buttons.html:34 +#: indico_vc_zoom/templates/buttons.html:57 msgid "Please log in" msgstr "" +#: indico_vc_zoom/templates/extra_delete_msg.html:2 +#, python-format +msgid "" +"The host of this Zoom meeting is %(host)s. In case you " +"want to delete this Zoom meeting from all events, please make sure that " +"they do not use it for other events that may still need it!" +msgstr "" + #: indico_vc_zoom/templates/info_box.html:4 #: indico_vc_zoom/templates/manage_event_info_box.html:5 msgid "Zoom Meeting ID" @@ -292,7 +373,7 @@ msgstr "" msgid "Host" msgstr "" -#: indico_vc_zoom/templates/info_box.html:20 +#: indico_vc_zoom/templates/info_box.html:22 #: indico_vc_zoom/templates/manage_event_info_box.html:30 msgid "Zoom URL" msgstr "" From 86135b03047606f2ddcc7831e7a655105e1a344c Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Mon, 7 Dec 2020 14:57:49 +0100 Subject: [PATCH 80/94] VC/Zoom: Show detailed error when deleting meeting --- vc_zoom/indico_vc_zoom/plugin.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index d02f211..d990eb8 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -440,6 +440,9 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # if there's a 404, there is no problem, since the room is supposed to be gone anyway if e.response.status_code == 404: flash(_("Room didn't existing in Zoom anymore"), 'warning') + elif e.response.status_code == 400: + # some sort of operational error on Zoom's side, deserves a specific error message + raise VCRoomError(_('Zoom Error: "{}"').format(e.response.json()['message'])) else: self.logger.error("Can't delete room") raise VCRoomError(_('Problem deleting room')) From cafed35e36a91fec41db2592d4af82c7d68e7d1a Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Tue, 8 Dec 2020 16:35:15 +0100 Subject: [PATCH 81/94] VC/Zoom: Set maximum length for passcodes --- vc_zoom/indico_vc_zoom/forms.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 36436f0..8af613a 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -57,8 +57,8 @@ class VCRoomForm(VCRoomFormBase): [HiddenUnless('host_choice', 'someone_else'), DataRequired()]) password = StringField(_('Passcode'), - [DataRequired(), IndicoRegexp(r'^\d{8,}$')], - description=_('Meeting passcode (min. 8 digits)')) + [DataRequired(), IndicoRegexp(r'^\d{8,10}$')], + description=_('Meeting passcode (8-10 digits)')) password_visibility = IndicoRadioField(_('Passcode visibility'), description=_("Who should be able to know this meeting's passcode"), From d00958eb68336563c9c125c8d8b0fb209121b94c Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 8 Dec 2020 23:00:14 +0100 Subject: [PATCH 82/94] VC/Zoom: Add option to lookup zoom users for all emails --- vc_zoom/indico_vc_zoom/util.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 8ff9068..30fdece 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -36,6 +36,7 @@ class ZoomMeetingType(int, IndicoEnum): class UserLookupMode(unicode, RichEnum): __titles__ = { + 'all_emails': _('All emails'), 'email_domains': _('Email domains'), 'authenticators': _('Authenticators'), } @@ -44,6 +45,7 @@ class UserLookupMode(unicode, RichEnum): def title(self): return RichEnum.title.__get__(self, type(self)) + all_emails = 'all_emails' email_domains = 'email_domains' authenticators = 'authenticators' @@ -67,16 +69,19 @@ def _iter_user_emails(user): """ from indico_vc_zoom.plugin import ZoomPlugin mode = ZoomPlugin.settings.get('user_lookup_mode') - if mode == UserLookupMode.email_domains: - domains = ZoomPlugin.settings.get('email_domains') - if not domains: - return + if mode in (UserLookupMode.all_emails, UserLookupMode.email_domains): + email_criterion = True + if mode == UserLookupMode.email_domains: + domains = ZoomPlugin.settings.get('email_domains') + if not domains: + return + email_criterion = db.or_(UserEmail.email.endswith('@{}'.format(domain)) for domain in domains) # get all matching e-mails, primary first query = UserEmail.query.filter( UserEmail.user == user, ~User.is_blocked, ~User.is_deleted, - db.or_(UserEmail.email.endswith('@{}'.format(domain)) for domain in domains) + email_criterion ).join(User).order_by(UserEmail.is_primary.desc()) for entry in query: yield entry.email From f95e73e214d15876985c5b06f76e3e03b6efbcd0 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Thu, 10 Dec 2020 12:30:23 +0100 Subject: [PATCH 83/94] VC/Zoom: Fix registration link in conferences --- vc_zoom/indico_vc_zoom/templates/buttons.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/templates/buttons.html b/vc_zoom/indico_vc_zoom/templates/buttons.html index bbe2157..51dab90 100644 --- a/vc_zoom/indico_vc_zoom/templates/buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/buttons.html @@ -34,7 +34,7 @@ {% if event_vc_room.event.type == 'conference' %}
    + href="{{ url_for('event_registration.display_regform_list', event_vc_room.event) }}"> {% trans %}Please register{% endtrans %} {% else %} From 54e0aef54d1a4fb3ece91389c0cf2f18a8efa031 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Thu, 10 Dec 2020 20:00:20 +0100 Subject: [PATCH 84/94] VC/Zoom: Remove assistants, disallow host changes Assistants are basically useless due to the rate limits in the Zoom API. --- vc_zoom/indico_vc_zoom/api/client.py | 12 ---- vc_zoom/indico_vc_zoom/notifications.py | 15 ----- vc_zoom/indico_vc_zoom/plugin.py | 59 ++----------------- .../templates/emails/notify_new_host.html | 25 -------- vc_zoom/tests/operation_test.py | 35 +---------- 5 files changed, 7 insertions(+), 139 deletions(-) delete mode 100644 vc_zoom/indico_vc_zoom/templates/emails/notify_new_host.html diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index 9477a25..2ba29b0 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -139,12 +139,6 @@ class UserComponent(BaseComponent): def delete(self, user_id, **kwargs): return self.session.delete('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) - def add_assistant(self, user_id, **kwargs): - return self.session.post('{}/users/{}/assistants'.format(self.base_uri, user_id), json=kwargs) - - def get_assistants(self, user_id, **kwargs): - return self.session.get('{}/users/{}/assistants'.format(self.base_uri, user_id), params=kwargs) - def get(self, user_id, **kwargs): return self.session.get('{}/users/{}'.format(self.base_uri, user_id), params=kwargs) @@ -232,9 +226,3 @@ class ZoomIndicoClient(object): if resp.status_code == 404 and silent: return None return _handle_response(resp) - - def get_assistants_for_user(self, user_id): - return _handle_response(self.client.user.get_assistants(user_id)) - - def add_assistant_to_user(self, user_id, assistant_email): - return _handle_response(self.client.user.add_assistant(user_id, assistants=[{'email': assistant_email}]), 201) diff --git a/vc_zoom/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py index da45dc3..5aa7707 100644 --- a/vc_zoom/indico_vc_zoom/notifications.py +++ b/vc_zoom/indico_vc_zoom/notifications.py @@ -27,18 +27,3 @@ def notify_host_start_url(vc_room): email = make_email(to_list, template=template_module, html=True) send_email(email) - - -def notify_new_host(actor, vc_room): - from indico_vc_zoom.plugin import ZoomPlugin - - template_module = get_template_module( - 'vc_zoom:emails/notify_new_host.html', - plugin=ZoomPlugin.instance, - vc_room=vc_room, - actor=actor - ) - - new_host = principal_from_identifier(vc_room.data['host']) - email = make_email({new_host.email}, cc_list={actor.email}, template=template_module, html=True) - send_email(email) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index d990eb8..cb722db 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -11,7 +11,6 @@ from flask import flash, session from markupsafe import escape from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified -from werkzeug.exceptions import Forbidden, NotFound from wtforms.fields.core import BooleanField from wtforms.fields import TextAreaField from wtforms.fields.simple import StringField @@ -35,7 +34,7 @@ from indico_vc_zoom.api import ZoomIndicoClient from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm -from indico_vc_zoom.notifications import notify_new_host, notify_host_start_url +from indico_vc_zoom.notifications import notify_host_start_url from indico_vc_zoom.util import (UserLookupMode, fetch_zoom_meeting, find_enterprise_email, gen_random_password, get_schedule_args, get_url_data_args, update_zoom_meeting, ZoomMeetingType) @@ -43,7 +42,7 @@ from indico_vc_zoom.util import (UserLookupMode, fetch_zoom_meeting, find_enterp class PluginSettingsForm(VCPluginSettingsFormBase): _fieldsets = [ ('API Credentials', ['api_key', 'api_secret', 'webhook_token']), - ('Zoom Account', ['user_lookup_mode', 'email_domains', 'authenticators', 'enterprise_domain', 'assistant_id', + ('Zoom Account', ['user_lookup_mode', 'email_domains', 'authenticators', 'enterprise_domain', 'allow_webinars']), ('Room Settings', ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host', 'waiting_room']), @@ -79,10 +78,6 @@ class PluginSettingsForm(VCPluginSettingsFormBase): description=_('The domain name used together with the usernames from the Indico ' 'identity provider')) - assistant_id = StringField(_('Assistant Zoom ID'), [DataRequired()], - description=_('Account to be used as owner of all rooms. It will get "assistant" ' - 'privileges on all accounts for which it books rooms')) - allow_webinars = BooleanField(_('Allow Webinars (Experimental)'), widget=SwitchWidget(), description=_('Allow webinars to be created through Indico. Use at your own risk.')) @@ -133,7 +128,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room_attach_form = VCRoomAttachForm friendly_name = 'Zoom' default_settings = dict(VCPluginMixin.default_settings, **{ - 'assistant_id': '', 'api_key': '', 'api_secret': '', 'webhook_token': '', @@ -177,6 +171,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): ) if existing_vc_room: + form.host_choice.render_kw = {'disabled': True} + form.host_user.render_kw = {'disabled': True} if self.settings.get('allow_webinars'): # if we're editing a VC room, we will not allow the meeting type to be changed form.meeting_type.render_kw = {'disabled': True} @@ -258,20 +254,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): flag_modified(vc_room, 'data') - def _check_indico_is_assistant(self, user_id): - client = ZoomIndicoClient() - assistant_id = self.settings.get('assistant_id') - - if user_id != assistant_id: - try: - assistants = {assist['email'] for assist in client.get_assistants_for_user(user_id)['assistants']} - if assistant_id not in assistants: - client.add_assistant_to_user(user_id, assistant_id) - except HTTPError as e: - if e.response.status_code == 404: - raise NotFound(_('No Zoom account found for this user')) - raise VCRoomError(_('Problem setting Zoom account assistants')) - def create_room(self, vc_room, event): """Create a new Zoom room for an event, given a VC room. @@ -292,8 +274,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): is_webinar = vc_room.data.setdefault('meeting_type', 'regular') == 'webinar' scheduling_args = get_schedule_args(link_obj) if link_obj.start_dt else {} - self._check_indico_is_assistant(host_email) - try: settings = { 'host_video': not vc_room.data['mute_host_video'], @@ -330,9 +310,9 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): }) kwargs.update(scheduling_args) if is_webinar: - meeting_obj = client.create_webinar(self.settings.get('assistant_id'), **kwargs) + meeting_obj = client.create_webinar(host_email, **kwargs) else: - meeting_obj = client.create_meeting(self.settings.get('assistant_id'), **kwargs) + meeting_obj = client.create_meeting(host_email, **kwargs) except HTTPError as e: self.logger.exception('Error creating Zoom Room: %s', e.response.content) raise VCRoomError(_('Could not create the room in Zoom. Please contact support if the error persists')) @@ -355,33 +335,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): zoom_meeting = fetch_zoom_meeting(vc_room, client=client, is_webinar=is_webinar) changes = {} - host = principal_from_identifier(vc_room.data['host']) - host_id = zoom_meeting['host_id'] - - try: - host_data = client.get_user(host_id) - except HTTPError as e: - self.logger.exception("Error retrieving user '%s': %s", host_id, e.response.content) - raise VCRoomError(_("Can't get information about user. Please contact support if the error persists.")) - - # host changed - if host_data['email'] not in host.all_emails: - email = find_enterprise_email(host) - - if not email: - raise Forbidden(_("This user doesn't seem to have an associated Zoom account")) - - # When using authenticator mode for user lookups, the email address used on zoom - # may not be an email address the Indico user has, so we can only check if the host - # really changed after checking for the zoom account. - if host_data['email'] != email: - if is_webinar: - changes.setdefault('settings', {})['alternative_hosts'] = email - else: - changes['schedule_for'] = email - self._check_indico_is_assistant(email) - notify_new_host(session.user, vc_room) - if vc_room.name != zoom_meeting['topic']: changes['topic'] = vc_room.name diff --git a/vc_zoom/indico_vc_zoom/templates/emails/notify_new_host.html b/vc_zoom/indico_vc_zoom/templates/emails/notify_new_host.html deleted file mode 100644 index 225aa88..0000000 --- a/vc_zoom/indico_vc_zoom/templates/emails/notify_new_host.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends 'emails/base.html' %} - -{% block subject -%} - [{{ plugin.friendly_name }}] You are now hosting '{{ vc_room.name }}' -{%- endblock %} - -{% block header -%} -

    - {{ actor.full_name }} has just made you the host of Zoom Meeting '{{ vc_room.name }}'. -

    - {% if plugin.settings.get('send_host_url') %} -

    - ATTENTION: - You should not share this URL with anyone, since it will allow them to become meeting hosts! -

    - - {% endif %} - - {% block custom_footer %}{% endblock %} -{%- endblock %} diff --git a/vc_zoom/tests/operation_test.py b/vc_zoom/tests/operation_test.py index 86f7f61..0c04942 100644 --- a/vc_zoom/tests/operation_test.py +++ b/vc_zoom/tests/operation_test.py @@ -18,7 +18,6 @@ def zoom_plugin(app): """Return a callable which lets you create dummy Zoom room occurrences.""" plugin = ZoomPlugin(plugin_engine, app) plugin.settings.set('email_domains', 'megacorp.xyz') - plugin.settings.set('assistant_id', 'zoom.master@megacorp.xyz') return plugin @@ -84,17 +83,11 @@ def zoom_api(create_user, mocker): api_get_meeting = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.get_meeting') api_get_meeting.return_value = api_create_meeting.return_value - api_get_assistants = mocker.patch('indico_vc_zoom.plugin.ZoomIndicoClient.get_assistants_for_user') - api_get_assistants.return_value = { - 'assistants': [{'email': 'zoom.master@megacorp.xyz'}] - } - return { 'create_meeting': api_create_meeting, 'get_meeting': api_get_meeting, 'update_meeting': api_update_meeting, - 'get_user': api_get_user, - 'get_assistants': api_get_assistants + 'get_user': api_get_user } @@ -103,35 +96,9 @@ def test_room_creation(create_meeting, zoom_api): assert vc_room.data['url'] == 'https://example.com/kitties' assert vc_room.data['host'] == 'User:1' assert zoom_api['create_meeting'].called - assert zoom_api['get_assistants'].called - - -def test_host_change(create_user, mocker, create_meeting, zoom_plugin, zoom_api, request_context): - mocker.patch('indico_vc_zoom.plugin.find_enterprise_email', return_value='joe.bidon@megacorp.xyz') - notify_new_host = mocker.patch('indico_vc_zoom.plugin.notify_new_host') - - create_user(2, email='joe.bidon@megacorp.xyz') - vc_room = create_meeting() - - assert vc_room.data['host'] == 'User:1' - assert not vc_room.data['mute_participant_video'] - assert zoom_api['create_meeting'].called - assert zoom_api['get_assistants'].called - - vc_room.data['host'] = 'User:2' - vc_room.data['description'] = 'something else' - zoom_plugin.update_room(vc_room, vc_room.events[0].event) - - assert notify_new_host.called - assert zoom_api['update_meeting'].call_args == (('12345abc', { - 'schedule_for': 'joe.bidon@megacorp.xyz', - 'agenda': 'something else' - }),) def test_password_change(create_user, mocker, create_meeting, zoom_plugin, zoom_api): - mocker.patch('indico_vc_zoom.plugin.notify_new_host') - create_user(2, email='joe.bidon@megacorp.xyz') vc_room = create_meeting() vc_room.data['password'] = '1337' From 878c5f65b30217d4c481076616d137e6bb5f23d4 Mon Sep 17 00:00:00 2001 From: Pedro Ferreira Date: Fri, 11 Dec 2020 12:17:26 +0100 Subject: [PATCH 85/94] VC/Zoom: Add action to become alternative host --- vc_zoom/indico_vc_zoom/blueprint.py | 8 ++++---- vc_zoom/indico_vc_zoom/controllers.py | 15 ++++++++------ vc_zoom/indico_vc_zoom/plugin.py | 20 ++++++++++++++++--- vc_zoom/indico_vc_zoom/templates/buttons.html | 10 ++++++---- .../indico_vc_zoom/templates/info_box.html | 13 ++++++++++++ .../templates/manage_event_info_box.html | 13 ++++++++++++ vc_zoom/indico_vc_zoom/util.py | 18 +++++++++++++++-- 7 files changed, 78 insertions(+), 19 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py index 93d723d..2392e1a 100644 --- a/vc_zoom/indico_vc_zoom/blueprint.py +++ b/vc_zoom/indico_vc_zoom/blueprint.py @@ -9,7 +9,7 @@ from __future__ import unicode_literals from indico.core.plugins import IndicoPluginBlueprint -from indico_vc_zoom.controllers import RHRoomHost, RHWebhook +from indico_vc_zoom.controllers import RHRoomAlternativeHost, RHWebhook blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') @@ -18,9 +18,9 @@ blueprint = IndicoPluginBlueprint('vc_zoom', 'indico_vc_zoom') # using any(zoom) instead of defaults since the event vc room locator # includes the service and normalization skips values provided in 'defaults' blueprint.add_url_rule( - '/event//manage/videoconference///make-me-host', - 'make_me_host', - RHRoomHost, + '/event//manage/videoconference///make-me-alt-host', + 'make_me_alt_host', + RHRoomAlternativeHost, methods=('POST',) ) blueprint.add_url_rule('/api/plugin/zoom/webhook', 'webhook', RHWebhook, methods=('POST',)) diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index a36ef38..3b10fa7 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -22,10 +22,14 @@ from indico.util.i18n import _ from werkzeug.exceptions import Forbidden -class RHRoomHost(RHVCSystemEventBase): +class RHRoomAlternativeHost(RHVCSystemEventBase): def _process(self): - result = {} - self.vc_room.data['host'] = session.user.identifier + new_identifier = session.user.identifier + if new_identifier == self.vc_room.data['host'] or new_identifier in self.vc_room.data['alternative_hosts']: + flash(_("You were already an (alternative) host of this meeting"), 'warning') + return jsonify(success=False) + + self.vc_room.data['alternative_hosts'].append(new_identifier) flag_modified(self.vc_room, 'data') try: self.plugin.update_room(self.vc_room, self.event) @@ -33,9 +37,8 @@ class RHRoomHost(RHVCSystemEventBase): db.session.rollback() raise else: - flash(_("You are now the host of room '{room.name}'".format(room=self.vc_room)), 'success') - result['success'] = True - return jsonify(result) + flash(_("You are now an alternative host of room '{room.name}'".format(room=self.vc_room)), 'success') + return jsonify(success=True) class RHWebhook(RH): diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index cb722db..5643a48 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -36,7 +36,8 @@ from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.notifications import notify_host_start_url from indico_vc_zoom.util import (UserLookupMode, fetch_zoom_meeting, find_enterprise_email, gen_random_password, - get_schedule_args, get_url_data_args, update_zoom_meeting, ZoomMeetingType) + get_alt_host_emails, get_schedule_args, get_url_data_args, process_alternative_hosts, + update_zoom_meeting, ZoomMeetingType) class PluginSettingsForm(VCPluginSettingsFormBase): @@ -320,7 +321,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): vc_room.data.update({ 'zoom_id': unicode(meeting_obj['id']), 'start_url': meeting_obj['start_url'], - 'host': host.identifier + 'host': host.identifier, + 'alternative_hosts': process_alternative_hosts(meeting_obj['settings'].get('alternative_hosts', [])) }) vc_room.data.update(get_url_data_args(meeting_obj['join_url'])) flag_modified(vc_room, 'data') @@ -348,6 +350,11 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): if vc_room.data['mute_host_video'] == zoom_meeting_settings['host_video']: changes.setdefault('settings', {})['host_video'] = not vc_room.data['mute_host_video'] + alternative_hosts = process_alternative_hosts(zoom_meeting_settings.get('alternative_hosts', '')) + if vc_room.data['alternative_hosts'] != alternative_hosts: + new_alt_host_emails = get_alt_host_emails(vc_room.data['alternative_hosts']) + changes.setdefault('settings', {})['alternative_hosts'] = ','.join(new_alt_host_emails) + if not is_webinar: if vc_room.data['mute_audio'] != zoom_meeting_settings['mute_upon_entry']: changes.setdefault('settings', {})['mute_upon_entry'] = vc_room.data['mute_audio'] @@ -375,7 +382,8 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # these options will be empty for webinars 'mute_audio': zoom_meeting['settings'].get('mute_upon_entry'), 'mute_participant_video': not zoom_meeting['settings'].get('participant_video'), - 'waiting_room': zoom_meeting['settings'].get('waiting_room') + 'waiting_room': zoom_meeting['settings'].get('waiting_room'), + 'alternative_hosts': process_alternative_hosts(zoom_meeting['settings'].get('alternative_hosts')) }) vc_room.data.update(get_url_data_args(zoom_meeting['join_url'])) flag_modified(vc_room, 'data') @@ -454,6 +462,12 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): ): room.data['host'] = target.identifier flag_modified(room, 'data') + for room in VCRoom.query.filter( + VCRoom.type == self.service_name, VCRoom.data.contains({'alternative_hosts': [source.identifier]}) + ): + room.data['alternative_hosts'].remove(source.identifier) + room.data['alternative_hosts'].append(target.identifier) + flag_modified(room, 'data') def get_notification_cc_list(self, action, vc_room, event): return {principal_from_identifier(vc_room.data['host']).email} diff --git a/vc_zoom/indico_vc_zoom/templates/buttons.html b/vc_zoom/indico_vc_zoom/templates/buttons.html index 51dab90..b0d5451 100644 --- a/vc_zoom/indico_vc_zoom/templates/buttons.html +++ b/vc_zoom/indico_vc_zoom/templates/buttons.html @@ -1,13 +1,15 @@ {% macro render_make_me_owner(event, vc_room, event_vc_room, extra_classes='') %} - {% if session.user.identifier != vc_room.data['host'] and event.can_manage(session.user) %} + {% if session.user.identifier != vc_room.data['host'] + and session.user.identifier not in vc_room.data['alternative_hosts'] + and event.can_manage(session.user) %} diff --git a/vc_zoom/indico_vc_zoom/templates/info_box.html b/vc_zoom/indico_vc_zoom/templates/info_box.html index f1d9286..08ed536 100644 --- a/vc_zoom/indico_vc_zoom/templates/info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/info_box.html @@ -1,5 +1,6 @@ {% from '_clipboard_input.html' import clipboard_input %} {% set host = vc_room.data.host %} +{% set alt_hosts = vc_room.data.alternative_hosts %}
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    @@ -11,6 +12,18 @@
    {% trans %}Host{% endtrans %}
    {{ (host|decodeprincipal).full_name }}
    {% endif %} + {% if alt_hosts %} +
    + {% trans count=alt_hosts|length -%} + Alternative host + {%- pluralize -%} + Alternative hosts + {%- endtrans %} +
    +
    + {{ alt_hosts | map('decodeprincipal') | map(attribute='full_name') | join(', ') }} +
    + {% endif %} {% if event_vc_room.data.password_visibility == 'everyone' or event_vc_room.event.can_manage(session.user) or (session.user and event_vc_room.data.password_visibility == 'logged_in') or diff --git a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html index 34943ae..2754718 100644 --- a/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html +++ b/vc_zoom/indico_vc_zoom/templates/manage_event_info_box.html @@ -1,6 +1,7 @@ {% from '_password.html' import password %} {% from '_clipboard_input.html' import clipboard_input %} {% set host = vc_room.data.host %} +{% set alt_hosts = vc_room.data.alternative_hosts %}
    {% trans %}Zoom Meeting ID{% endtrans %}
    {{ vc_room.data.zoom_id }}
    @@ -12,6 +13,18 @@
    {{ (host|decodeprincipal).full_name }}
    + {% if alt_hosts %} +
    + {% trans count=alt_hosts|length -%} + Alternative host + {%- pluralize -%} + Alternative hosts + {%- endtrans %} +
    +
    + {{ alt_hosts | map('decodeprincipal') | map(attribute='full_name') | join(', ') }} +
    + {% endif %}
    {% trans %}Linked to{% endtrans %}
    {% set obj = event_vc_room.link_object %} diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 30fdece..76693ab 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -8,6 +8,7 @@ from __future__ import unicode_literals import random +import re import string from requests.exceptions import HTTPError @@ -15,10 +16,12 @@ from requests.exceptions import HTTPError from indico.core.db import db from indico.modules.users.models.emails import UserEmail from indico.modules.users.models.users import User +from indico.modules.users.util import get_user_by_email from indico.modules.vc.exceptions import VCRoomError, VCRoomNotFoundError from indico.util.caching import memoize_request from indico.util.date_time import now_utc from indico.util.struct.enum import IndicoEnum, RichEnum +from indico.util.user import principal_from_identifier from indico_vc_zoom import _ from indico_vc_zoom.api import ZoomIndicoClient @@ -62,7 +65,7 @@ def _iter_user_identifiers(user): yield identifier -def _iter_user_emails(user): +def iter_user_emails(user): """Yield all emails of a user that may work with zoom. :param user: the `User` in question @@ -95,7 +98,7 @@ def _iter_user_emails(user): def find_enterprise_email(user): """Get the email address of a user that has a zoom account.""" client = ZoomIndicoClient() - return next((email for email in _iter_user_emails(user) if client.get_user(email, silent=True)), None) + return next((email for email in iter_user_emails(user) if client.get_user(email, silent=True)), None) def gen_random_password(): @@ -169,3 +172,14 @@ def get_url_data_args(url): 'url': url, 'public_url': url.split('?')[0], } + + +def process_alternative_hosts(emails): + """Convert a comma-concatenated list of alternative host e-mails into a list of identifiers.""" + users = [get_user_by_email(email) for email in re.findall(r'[^,;]+', emails)] + return [u.identifier for u in users if u is not None] + + +def get_alt_host_emails(identifiers): + """Convert a list of identities into a list of enterprise e-mails.""" + return [find_enterprise_email(principal_from_identifier(ident)) for ident in identifiers] From 1374e9e08923069c69a263fef5070e02caebccde Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 10:57:05 +0100 Subject: [PATCH 86/94] VC/Zoom: Fix changing room link obj if recurring --- vc_zoom/indico_vc_zoom/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 5643a48..91368fa 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -222,7 +222,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): # the booking should now be linked to something else new_schedule_args = get_schedule_args(room_assoc.link_object) meeting = fetch_zoom_meeting(vc_room) - current_schedule_args = {k: meeting[k] for k in {'start_time', 'duration'}} + current_schedule_args = {k: meeting[k] for k in {'start_time', 'duration'} if k in meeting} # check whether the start time / duration of the scheduled meeting differs if new_schedule_args != current_schedule_args: From 1d0556d09a066b0d699acd652284d184c6f5d558 Mon Sep 17 00:00:00 2001 From: Indico Team Date: Tue, 5 Jan 2021 11:01:51 +0100 Subject: [PATCH 87/94] Update *.pot files --- .../indico_vc_zoom/translations/messages.pot | 175 +++++++++--------- 1 file changed, 83 insertions(+), 92 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/translations/messages.pot b/vc_zoom/indico_vc_zoom/translations/messages.pot index d90908c..a546f44 100644 --- a/vc_zoom/indico_vc_zoom/translations/messages.pot +++ b/vc_zoom/indico_vc_zoom/translations/messages.pot @@ -1,14 +1,14 @@ # Translations template for PROJECT. -# Copyright (C) 2020 ORGANIZATION +# Copyright (C) 2021 ORGANIZATION # This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2020. +# FIRST AUTHOR , 2021. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-12-03 13:11+0100\n" +"POT-Creation-Date: 2021-01-05 10:58+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,8 +17,12 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.8.0\n" -#: indico_vc_zoom/controllers.py:36 -msgid "You are now the host of room '{room.name}'" +#: indico_vc_zoom/controllers.py:29 +msgid "You were already an (alternative) host of this meeting" +msgstr "" + +#: indico_vc_zoom/controllers.py:40 +msgid "You are now an alternative host of room '{room.name}'" msgstr "" #: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:63 @@ -77,49 +81,49 @@ msgstr "" msgid "User" msgstr "" -#: indico_vc_zoom/forms.py:59 indico_vc_zoom/templates/info_box.html:18 -#: indico_vc_zoom/templates/manage_event_info_box.html:28 +#: indico_vc_zoom/forms.py:59 indico_vc_zoom/templates/info_box.html:31 +#: indico_vc_zoom/templates/manage_event_info_box.html:41 msgid "Passcode" msgstr "" #: indico_vc_zoom/forms.py:61 -msgid "Meeting passcode (min. 8 digits)" +msgid "Meeting passcode (8-10 digits)" msgstr "" -#: indico_vc_zoom/forms.py:72 indico_vc_zoom/plugin.py:90 +#: indico_vc_zoom/forms.py:72 indico_vc_zoom/plugin.py:86 msgid "Mute audio" msgstr "" -#: indico_vc_zoom/forms.py:74 indico_vc_zoom/plugin.py:92 +#: indico_vc_zoom/forms.py:74 indico_vc_zoom/plugin.py:88 msgid "Participants will join the VC room muted by default " msgstr "" -#: indico_vc_zoom/forms.py:76 indico_vc_zoom/plugin.py:94 +#: indico_vc_zoom/forms.py:76 indico_vc_zoom/plugin.py:90 msgid "Mute video (host)" msgstr "" -#: indico_vc_zoom/forms.py:78 indico_vc_zoom/plugin.py:96 +#: indico_vc_zoom/forms.py:78 indico_vc_zoom/plugin.py:92 msgid "The host will join the VC room with video disabled" msgstr "" -#: indico_vc_zoom/forms.py:80 indico_vc_zoom/plugin.py:98 +#: indico_vc_zoom/forms.py:80 indico_vc_zoom/plugin.py:94 msgid "Mute video (participants)" msgstr "" -#: indico_vc_zoom/forms.py:82 indico_vc_zoom/plugin.py:100 +#: indico_vc_zoom/forms.py:82 indico_vc_zoom/plugin.py:96 msgid "Participants will join the VC room with video disabled" msgstr "" -#: indico_vc_zoom/forms.py:84 indico_vc_zoom/plugin.py:107 +#: indico_vc_zoom/forms.py:84 indico_vc_zoom/plugin.py:103 msgid "Waiting room" msgstr "" -#: indico_vc_zoom/forms.py:86 indico_vc_zoom/plugin.py:109 +#: indico_vc_zoom/forms.py:86 indico_vc_zoom/plugin.py:105 msgid "Participants may be kept in a waiting room by the host" msgstr "" -#: indico_vc_zoom/forms.py:88 indico_vc_zoom/templates/info_box.html:7 -#: indico_vc_zoom/templates/manage_event_info_box.html:8 +#: indico_vc_zoom/forms.py:88 indico_vc_zoom/templates/info_box.html:8 +#: indico_vc_zoom/templates/manage_event_info_box.html:9 msgid "Description" msgstr "" @@ -191,167 +195,147 @@ msgid "" msgstr "" #: indico_vc_zoom/plugin.py:82 -msgid "Assistant Zoom ID" -msgstr "" - -#: indico_vc_zoom/plugin.py:83 -msgid "" -"Account to be used as owner of all rooms. It will get \"assistant\" " -"privileges on all accounts for which it books rooms" -msgstr "" - -#: indico_vc_zoom/plugin.py:86 msgid "Allow Webinars (Experimental)" msgstr "" -#: indico_vc_zoom/plugin.py:88 +#: indico_vc_zoom/plugin.py:84 msgid "Allow webinars to be created through Indico. Use at your own risk." msgstr "" -#: indico_vc_zoom/plugin.py:102 +#: indico_vc_zoom/plugin.py:98 msgid "Join Before Host" msgstr "" -#: indico_vc_zoom/plugin.py:104 +#: indico_vc_zoom/plugin.py:100 msgid "" "Allow participants to join the meeting before the host starts the " "meeting. Only used for scheduled or recurring meetings." msgstr "" -#: indico_vc_zoom/plugin.py:111 +#: indico_vc_zoom/plugin.py:107 msgid "Creation email footer" msgstr "" -#: indico_vc_zoom/plugin.py:112 +#: indico_vc_zoom/plugin.py:108 msgid "Footer to append to emails sent upon creation of a VC room" msgstr "" -#: indico_vc_zoom/plugin.py:114 +#: indico_vc_zoom/plugin.py:110 msgid "Send host URL" msgstr "" -#: indico_vc_zoom/plugin.py:116 +#: indico_vc_zoom/plugin.py:112 msgid "" "Whether to send an e-mail with the Host URL to the meeting host upon " "creation of a meeting" msgstr "" -#: indico_vc_zoom/plugin.py:122 +#: indico_vc_zoom/plugin.py:118 msgid "Invalid identity providers: {}" msgstr "" -#: indico_vc_zoom/plugin.py:272 -msgid "No Zoom account found for this user" -msgstr "" - -#: indico_vc_zoom/plugin.py:273 -msgid "Problem setting Zoom account assistants" -msgstr "" - -#: indico_vc_zoom/plugin.py:338 +#: indico_vc_zoom/plugin.py:319 msgid "" "Could not create the room in Zoom. Please contact support if the error " "persists" msgstr "" -#: indico_vc_zoom/plugin.py:365 -msgid "" -"Can't get information about user. Please contact support if the error " -"persists." -msgstr "" - -#: indico_vc_zoom/plugin.py:372 -msgid "This user doesn't seem to have an associated Zoom account" -msgstr "" - -#: indico_vc_zoom/plugin.py:442 +#: indico_vc_zoom/plugin.py:403 msgid "Room didn't existing in Zoom anymore" msgstr "" -#: indico_vc_zoom/plugin.py:445 +#: indico_vc_zoom/plugin.py:406 +msgid "Zoom Error: \"{}\"" +msgstr "" + +#: indico_vc_zoom/plugin.py:409 msgid "Problem deleting room" msgstr "" -#: indico_vc_zoom/plugin.py:520 +#: indico_vc_zoom/plugin.py:490 msgid "" "There are one or more scheduled Zoom meetings associated with this event " "which were not automatically updated." msgstr "" -#: indico_vc_zoom/plugin.py:523 +#: indico_vc_zoom/plugin.py:493 msgid "" "There are one or more scheduled Zoom meetings associated with the " "contribution \"{}\" which were not automatically updated." msgstr "" -#: indico_vc_zoom/plugin.py:526 +#: indico_vc_zoom/plugin.py:496 msgid "" "There are one or more scheduled Zoom meetings associated with this " "session block which were not automatically updated." msgstr "" -#: indico_vc_zoom/util.py:39 +#: indico_vc_zoom/util.py:42 +msgid "All emails" +msgstr "" + +#: indico_vc_zoom/util.py:43 msgid "Email domains" msgstr "" -#: indico_vc_zoom/util.py:40 +#: indico_vc_zoom/util.py:44 msgid "Authenticators" msgstr "" -#: indico_vc_zoom/util.py:116 +#: indico_vc_zoom/util.py:124 msgid "This room has been deleted from Zoom" msgstr "" -#: indico_vc_zoom/util.py:120 +#: indico_vc_zoom/util.py:128 msgid "" "Problem fetching room from Zoom. Please contact support if the error " "persists." msgstr "" -#: indico_vc_zoom/util.py:139 +#: indico_vc_zoom/util.py:147 msgid "Can't update meeting. Please contact support if the error persists." msgstr "" -#: indico_vc_zoom/templates/buttons.html:7 -msgid "You will become the host of this Zoom meeting" +#: indico_vc_zoom/templates/buttons.html:9 +msgid "You will become an alternative host of this Zoom meeting" msgstr "" -#: indico_vc_zoom/templates/buttons.html:10 -msgid "Make me host" +#: indico_vc_zoom/templates/buttons.html:12 +msgid "Make me alternative host" msgstr "" -#: indico_vc_zoom/templates/buttons.html:24 -#: indico_vc_zoom/templates/buttons.html:30 +#: indico_vc_zoom/templates/buttons.html:26 +#: indico_vc_zoom/templates/buttons.html:32 msgid "Join" msgstr "" -#: indico_vc_zoom/templates/buttons.html:28 +#: indico_vc_zoom/templates/buttons.html:30 msgid "You will need a passcode to join this Zoom meeting" msgstr "" -#: indico_vc_zoom/templates/buttons.html:36 -#: indico_vc_zoom/templates/buttons.html:42 -#: indico_vc_zoom/templates/buttons.html:48 +#: indico_vc_zoom/templates/buttons.html:38 +#: indico_vc_zoom/templates/buttons.html:44 +#: indico_vc_zoom/templates/buttons.html:50 msgid "This Zoom Meeting can only be seen by registered participants" msgstr "" -#: indico_vc_zoom/templates/buttons.html:38 +#: indico_vc_zoom/templates/buttons.html:40 msgid "Please register" msgstr "" -#: indico_vc_zoom/templates/buttons.html:43 +#: indico_vc_zoom/templates/buttons.html:45 msgid "Registration required" msgstr "" -#: indico_vc_zoom/templates/buttons.html:50 +#: indico_vc_zoom/templates/buttons.html:52 msgid "Please log in and register" msgstr "" -#: indico_vc_zoom/templates/buttons.html:55 +#: indico_vc_zoom/templates/buttons.html:57 msgid "This Zoom Meeting can only be seen by logged in users" msgstr "" -#: indico_vc_zoom/templates/buttons.html:57 +#: indico_vc_zoom/templates/buttons.html:59 msgid "Please log in" msgstr "" @@ -363,42 +347,49 @@ msgid "" "they do not use it for other events that may still need it!" msgstr "" -#: indico_vc_zoom/templates/info_box.html:4 -#: indico_vc_zoom/templates/manage_event_info_box.html:5 +#: indico_vc_zoom/templates/info_box.html:5 +#: indico_vc_zoom/templates/manage_event_info_box.html:6 msgid "Zoom Meeting ID" msgstr "" -#: indico_vc_zoom/templates/info_box.html:11 -#: indico_vc_zoom/templates/manage_event_info_box.html:11 +#: indico_vc_zoom/templates/info_box.html:12 +#: indico_vc_zoom/templates/manage_event_info_box.html:12 msgid "Host" msgstr "" -#: indico_vc_zoom/templates/info_box.html:22 -#: indico_vc_zoom/templates/manage_event_info_box.html:30 +#: indico_vc_zoom/templates/info_box.html:17 +#: indico_vc_zoom/templates/manage_event_info_box.html:18 +msgid "Alternative host" +msgid_plural "Alternative hosts" +msgstr[0] "" +msgstr[1] "" + +#: indico_vc_zoom/templates/info_box.html:35 +#: indico_vc_zoom/templates/manage_event_info_box.html:43 msgid "Zoom URL" msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:15 +#: indico_vc_zoom/templates/manage_event_info_box.html:28 msgid "Linked to" msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:21 +#: indico_vc_zoom/templates/manage_event_info_box.html:34 msgid "the whole event" msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:23 +#: indico_vc_zoom/templates/manage_event_info_box.html:36 msgid "Contribution" msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:25 +#: indico_vc_zoom/templates/manage_event_info_box.html:38 msgid "Session" msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:34 +#: indico_vc_zoom/templates/manage_event_info_box.html:47 msgid "Created on" msgstr "" -#: indico_vc_zoom/templates/manage_event_info_box.html:37 +#: indico_vc_zoom/templates/manage_event_info_box.html:50 msgid "Modified on" msgstr "" From 7ab691787a4667b54fa0dc6c4767402eb72d7505 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 11:07:26 +0100 Subject: [PATCH 88/94] VC/Zoom: Update changelog/readme --- vc_zoom/README.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/vc_zoom/README.md b/vc_zoom/README.md index deac4a1..d20527c 100644 --- a/vc_zoom/README.md +++ b/vc_zoom/README.md @@ -23,6 +23,10 @@ - Show "Make me host" button in the management area and in contributions/sessions as well - Warn the user if they delete a Zoom meeting linked to multiple events if they aren't the host - Change Zoom meeting to "recurring meeting" when cloning an event +- Show detailed error when deleting a meeting fails +- Do not allow passcodes that are too long for zoom +- Remove the "Assistant Zoom ID" logic due to problems with Zoom's API rate limits (all meetings created were counted against the assistant's rate limit instead of the host's); this means the host can no longer be changed, but Indico instead provides an option to event managers to make themselves a co-host. +- Fix an error when changing the linked object of a recurring Zoom room in Indico **Breaking change:** The email domains are now stored as a list of strings instead of a comma-separated list. You need to update them in the plugin settings. @@ -30,13 +34,6 @@ - Initial beta release -## Implementation details - -Rooms are created under the account of an *assistant user* which can be set using the **Assistant Zoom ID** -configuration setting. This account will also be added automatically as an assistant to every meeting host. -This is needed in order to allow for the host to be changed ([`scheduled_for`](https://marketplace.zoom.us/docs/api-reference/zoom-api/meetings/meetingcreate#request-body) property in the Zoom API). The *assistant user* owns every Zoom meeting, with the `scheduled_for` property being -used to grant the required privileges to the desired hosts. - ## Zoom App Configuration ### Webhook (optional) @@ -57,9 +54,7 @@ Select the following "Event types": These are the most relevant configuration options: * **Notification email addresses** - Additional e-mails which will receive notifications - * **E-mail domains** - Comma-separated list of e-mail domains which can be used for the Zoom API (e.g. `cern.ch`) - * **Asistant Zoom ID** - Zoom ID (or e-mail) of the account which shall be used as an assistant to all hosts and -shall own all meetings + * **E-mail domains** - List of e-mail domains which can be used for the Zoom API (e.g. `cern.ch`) * **Webhook token** (optional) - the token which Zoom requests will authenticate with (get it from Zoom Marketplace) From 8f40828e61b13934d434605356b1976d1753aa63 Mon Sep 17 00:00:00 2001 From: Indico Team Date: Tue, 5 Jan 2021 11:13:21 +0100 Subject: [PATCH 89/94] Update French translation :fr: :baguette_bread: --- .../fr_FR/LC_MESSAGES/messages.po | 322 +++++++++++------- 1 file changed, 199 insertions(+), 123 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po index 575d13a..7d31507 100644 --- a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po +++ b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po @@ -1,19 +1,19 @@ # Translations template for PROJECT. -# Copyright (C) 2020 ORGANIZATION +# Copyright (C) 2021 ORGANIZATION # This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2020. +# FIRST AUTHOR , 2021. # # Translators: -# Thomas Baron , 2020 +# Thomas Baron , 2021 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-11-25 15:55+0100\n" +"POT-Creation-Date: 2021-01-05 10:58+0100\n" "PO-Revision-Date: 2020-11-25 15:06+0000\n" -"Last-Translator: Thomas Baron , 2020\n" +"Last-Translator: Thomas Baron , 2021\n" "Language-Team: French (France) (https://www.transifex.com/indico/teams/6478/fr_FR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -22,169 +22,210 @@ msgstr "" "Language: fr_FR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: indico_vc_zoom/controllers.py:36 -msgid "You are now the host of room '{room.name}'" -msgstr "Vous êtes maintenant l'hôte de la réunion '{room.name}'" +#: indico_vc_zoom/controllers.py:29 +msgid "You were already an (alternative) host of this meeting" +msgstr "Vous étiez déjà un hôte (alternatif) de cette réunion" -#: indico_vc_zoom/forms.py:28 indico_vc_zoom/forms.py:61 +#: indico_vc_zoom/controllers.py:40 +msgid "You are now an alternative host of room '{room.name}'" +msgstr "Vous êtes maintenant un hôte alternatif de la réunion '{room.name}'" + +#: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:63 msgid "Passcode visibility" msgstr "Visibilité du code secret" -#: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:62 +#: indico_vc_zoom/forms.py:30 indico_vc_zoom/forms.py:64 msgid "Who should be able to know this meeting's passcode" msgstr "Qui peut connaitre le code secret de cette réunion" -#: indico_vc_zoom/forms.py:32 indico_vc_zoom/forms.py:65 +#: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:67 msgid "Everyone" msgstr "Tout le monde" -#: indico_vc_zoom/forms.py:33 indico_vc_zoom/forms.py:66 +#: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:68 msgid "Logged-in users" msgstr "Utilisateurs connectés" -#: indico_vc_zoom/forms.py:34 indico_vc_zoom/forms.py:67 +#: indico_vc_zoom/forms.py:35 indico_vc_zoom/forms.py:69 +msgid "Registered participants" +msgstr "Participants inscrits" + +#: indico_vc_zoom/forms.py:36 indico_vc_zoom/forms.py:70 msgid "No one" msgstr "Personne" -#: indico_vc_zoom/forms.py:44 +#: indico_vc_zoom/forms.py:46 msgid "Meeting Type" msgstr "Type de réunion" -#: indico_vc_zoom/forms.py:45 +#: indico_vc_zoom/forms.py:47 msgid "The type of Zoom meeting to be created" msgstr "Le type de réunion Zoom à créer" -#: indico_vc_zoom/forms.py:48 +#: indico_vc_zoom/forms.py:50 msgid "Regular Meeting" msgstr "Réunion normale" -#: indico_vc_zoom/forms.py:49 indico_vc_zoom/templates/room_labels.html:4 +#: indico_vc_zoom/forms.py:51 indico_vc_zoom/templates/room_labels.html:4 msgid "Webinar" msgstr "Wébinaire" -#: indico_vc_zoom/forms.py:51 +#: indico_vc_zoom/forms.py:53 msgid "Meeting Host" msgstr "Hôte de la réunion" -#: indico_vc_zoom/forms.py:52 +#: indico_vc_zoom/forms.py:54 msgid "Myself" msgstr "Moi-même" -#: indico_vc_zoom/forms.py:52 +#: indico_vc_zoom/forms.py:54 msgid "Someone else" msgstr "Quelqu'un d'autre" -#: indico_vc_zoom/forms.py:54 +#: indico_vc_zoom/forms.py:56 msgid "User" msgstr "Utilisateur" -#: indico_vc_zoom/forms.py:57 indico_vc_zoom/templates/info_box.html:16 -#: indico_vc_zoom/templates/manage_event_info_box.html:28 +#: indico_vc_zoom/forms.py:59 indico_vc_zoom/templates/info_box.html:31 +#: indico_vc_zoom/templates/manage_event_info_box.html:41 msgid "Passcode" msgstr "Code secret" -#: indico_vc_zoom/forms.py:59 -msgid "Meeting passcode (min. 8 digits)" -msgstr "Code secret de la réunion (min. 8 chiffres)" +#: indico_vc_zoom/forms.py:61 +msgid "Meeting passcode (8-10 digits)" +msgstr "Code secret de la réunion (8-10 chiffres)" -#: indico_vc_zoom/forms.py:69 indico_vc_zoom/plugin.py:67 +#: indico_vc_zoom/forms.py:72 indico_vc_zoom/plugin.py:86 msgid "Mute audio" msgstr "Couper le micro" -#: indico_vc_zoom/forms.py:71 indico_vc_zoom/plugin.py:69 +#: indico_vc_zoom/forms.py:74 indico_vc_zoom/plugin.py:88 msgid "Participants will join the VC room muted by default " msgstr "" "Les participants rejoindront la réunion avec leur micro coupé par défaut" -#: indico_vc_zoom/forms.py:73 indico_vc_zoom/plugin.py:71 +#: indico_vc_zoom/forms.py:76 indico_vc_zoom/plugin.py:90 msgid "Mute video (host)" msgstr "Couper la vidéo (hôte)" -#: indico_vc_zoom/forms.py:75 indico_vc_zoom/plugin.py:73 +#: indico_vc_zoom/forms.py:78 indico_vc_zoom/plugin.py:92 msgid "The host will join the VC room with video disabled" msgstr "L'hôte rejoindra la réunion avec sa vidéo désactivée" -#: indico_vc_zoom/forms.py:77 indico_vc_zoom/plugin.py:75 +#: indico_vc_zoom/forms.py:80 indico_vc_zoom/plugin.py:94 msgid "Mute video (participants)" msgstr "Couper la vidéo (participants)" -#: indico_vc_zoom/forms.py:79 indico_vc_zoom/plugin.py:77 +#: indico_vc_zoom/forms.py:82 indico_vc_zoom/plugin.py:96 msgid "Participants will join the VC room with video disabled" msgstr "Les participants rejoindront la réunion avec leur vidéo coupée" -#: indico_vc_zoom/forms.py:81 indico_vc_zoom/plugin.py:84 +#: indico_vc_zoom/forms.py:84 indico_vc_zoom/plugin.py:103 msgid "Waiting room" msgstr "Salle d'attente" -#: indico_vc_zoom/forms.py:83 indico_vc_zoom/plugin.py:86 +#: indico_vc_zoom/forms.py:86 indico_vc_zoom/plugin.py:105 msgid "Participants may be kept in a waiting room by the host" msgstr "Les participants rejoindront une salle d'attente" -#: indico_vc_zoom/forms.py:85 indico_vc_zoom/templates/info_box.html:7 -#: indico_vc_zoom/templates/manage_event_info_box.html:8 +#: indico_vc_zoom/forms.py:88 indico_vc_zoom/templates/info_box.html:8 +#: indico_vc_zoom/templates/manage_event_info_box.html:9 msgid "Description" msgstr "Description" -#: indico_vc_zoom/forms.py:85 +#: indico_vc_zoom/forms.py:88 msgid "Optional description for this room" msgstr "Description optionnelle de cette réunion" -#: indico_vc_zoom/plugin.py:49 +#: indico_vc_zoom/forms.py:118 +msgid "This user has no Zoom account" +msgstr "Cet utilisateur n'a pas de compte Zoom" + +#: indico_vc_zoom/plugin.py:53 msgid "API Key" msgstr "Clé API" -#: indico_vc_zoom/plugin.py:51 +#: indico_vc_zoom/plugin.py:55 msgid "API Secret" msgstr "Secret de l'API" -#: indico_vc_zoom/plugin.py:53 +#: indico_vc_zoom/plugin.py:57 msgid "Webhook Token" msgstr "Jeton de webhook" -#: indico_vc_zoom/plugin.py:54 +#: indico_vc_zoom/plugin.py:58 msgid "Specify Zoom's webhook token if you want live updates" msgstr "" "Spécifier le jeton de webhook Zoom si vous souhaitez des mises à jour en " "direct" -#: indico_vc_zoom/plugin.py:56 +#: indico_vc_zoom/plugin.py:60 +msgid "User lookup mode" +msgstr "Mode de recherche d'utilisateur" + +#: indico_vc_zoom/plugin.py:61 +msgid "" +"Specify how Indico should look up the zoom user that corresponds to an " +"Indico user." +msgstr "" +"Veuillez spécifier comment Indico doit rechercher l'utilisateur Zoom qui " +"correspond à un utilisateur Indico." + +#: indico_vc_zoom/plugin.py:64 msgid "E-mail domains" msgstr "Domaines de courriel" -#: indico_vc_zoom/plugin.py:57 -msgid "Comma-separated list of e-mail domains which can use the Zoom API." -msgstr "" -"Liste séparée par des virgules des domaines de courriels qui peuvent " -"utiliser l'API Zoom." - -#: indico_vc_zoom/plugin.py:59 -msgid "Assistant Zoom ID" -msgstr "Zoom ID de l'assistant" - -#: indico_vc_zoom/plugin.py:60 +#: indico_vc_zoom/plugin.py:66 msgid "" -"Account to be used as owner of all rooms. It will get \"assistant\" " -"privileges on all accounts for which it books rooms" +"List of e-mail domains which can use the Zoom API. Indico attempts to find " +"Zoom accounts using all email addresses of a user which use those domains." msgstr "" -"Compte à utiliser comme propriétaire de toutes les salles. Ce compte " -"obtiendra le privilège d'assistant pour tous les comptes pour qui les " -"réunions seront créées" +"Liste des domaines de courriel qui peuvent utiliser l'API Zoom. Indico " +"essaie de trouver des comptes Zoom en utilisant toutes les adresses de " +"courriel d'un utilisateur qui utilisent ces domaines." -#: indico_vc_zoom/plugin.py:63 +#: indico_vc_zoom/plugin.py:70 +msgid "Indico identity providers" +msgstr "Fournisseurs d'identité d'Indico" + +#: indico_vc_zoom/plugin.py:72 +msgid "" +"Identity providers from which to get usernames. Indico queries those " +"providers using the email addresses of the user and attempts to find Zoom " +"accounts having an email address with the format username@enterprise-domain." +msgstr "" +"Fournisseurs d'identité de qui récupérer les noms d'utilisateurs. Indico " +"interroge ces fournisseurs en utilisant les adresses de courriel de " +"l'utilisateur, et essaie de trouver des comptes Zoom ayant une adresse de " +"courriel de la forme nom-d-utilisateur@domaine-d-entreprise." + +#: indico_vc_zoom/plugin.py:77 +msgid "Enterprise domain" +msgstr "Domaine d'entreprise" + +#: indico_vc_zoom/plugin.py:79 +msgid "" +"The domain name used together with the usernames from the Indico identity " +"provider" +msgstr "" +"Le nom de domaine utilisé avec les noms d'utilisateurs du fournisseur " +"d'identité d'indico" + +#: indico_vc_zoom/plugin.py:82 msgid "Allow Webinars (Experimental)" msgstr "Autoriser les wébinaires (expérimental)" -#: indico_vc_zoom/plugin.py:65 +#: indico_vc_zoom/plugin.py:84 msgid "Allow webinars to be created through Indico. Use at your own risk." msgstr "" "Autoriser les wébinaires à être créés via Indico. Utilisez à vos propres " "risques." -#: indico_vc_zoom/plugin.py:79 +#: indico_vc_zoom/plugin.py:98 msgid "Join Before Host" msgstr "Rejoindre avant l'hôte" -#: indico_vc_zoom/plugin.py:81 +#: indico_vc_zoom/plugin.py:100 msgid "" "Allow participants to join the meeting before the host starts the meeting. " "Only used for scheduled or recurring meetings." @@ -192,21 +233,21 @@ msgstr "" "Autoriser les participants à rejoindre la réunion avant que l'hôte démarre " "la réunion. Utilisé uniquement pour les réunions programmées ou récurrentes." -#: indico_vc_zoom/plugin.py:88 +#: indico_vc_zoom/plugin.py:107 msgid "Creation email footer" msgstr "Pied de page du courriel de création" -#: indico_vc_zoom/plugin.py:89 +#: indico_vc_zoom/plugin.py:108 msgid "Footer to append to emails sent upon creation of a VC room" msgstr "" "Pied de page à ajouter aux courriels envoyés lors de la création d'une " "réunion" -#: indico_vc_zoom/plugin.py:91 +#: indico_vc_zoom/plugin.py:110 msgid "Send host URL" msgstr "Envoyer l'URL de l'hôte" -#: indico_vc_zoom/plugin.py:93 +#: indico_vc_zoom/plugin.py:112 msgid "" "Whether to send an e-mail with the Host URL to the meeting host upon " "creation of a meeting" @@ -214,17 +255,11 @@ msgstr "" "Envoyer ou non un courriel contenant l'URL d'hôte à l'hôte de la réunion à " "la création d'une réunion" -#: indico_vc_zoom/plugin.py:233 -msgid "No Zoom account found for this user" -msgstr "Aucun compte Zoom pour cet utilisateur" +#: indico_vc_zoom/plugin.py:118 +msgid "Invalid identity providers: {}" +msgstr "Fournisseurs d'identité invalides: {}" -#: indico_vc_zoom/plugin.py:235 -msgid "Problem getting information about Zoom account" -msgstr "" -"Une erreur est survenue lors de la récupération des informations sur le " -"compte Zoom" - -#: indico_vc_zoom/plugin.py:302 +#: indico_vc_zoom/plugin.py:319 msgid "" "Could not create the room in Zoom. Please contact support if the error " "persists" @@ -232,27 +267,19 @@ msgstr "" "Impossible de créer la réunion dans Zoom. Veuillez contacter le support si " "l'erreur persiste" -#: indico_vc_zoom/plugin.py:331 -msgid "" -"Can't get information about user. Please contact support if the error " -"persists." -msgstr "" -"Impossible d'obtenir des informations sur l'utilisateur. Veuillez contacter " -"le support si cette erreur persiste." - -#: indico_vc_zoom/plugin.py:338 -msgid "This user doesn't seem to have an associated Zoom account" -msgstr "Cet utilisateur ne semble pas avoir un compte Zoom associé" - -#: indico_vc_zoom/plugin.py:402 +#: indico_vc_zoom/plugin.py:403 msgid "Room didn't existing in Zoom anymore" msgstr "La réunion n'existait plus dans Zoom" -#: indico_vc_zoom/plugin.py:405 +#: indico_vc_zoom/plugin.py:406 +msgid "Zoom Error: \"{}\"" +msgstr "Erreur Zoom: \"{}\"" + +#: indico_vc_zoom/plugin.py:409 msgid "Problem deleting room" msgstr "Erreur lors de la suppression de la salle" -#: indico_vc_zoom/plugin.py:461 +#: indico_vc_zoom/plugin.py:490 msgid "" "There are one or more scheduled Zoom meetings associated with this event " "which were not automatically updated." @@ -260,15 +287,15 @@ msgstr "" "Il existe une ou plusieurs réunions Zoom associées à cet événement qui n'ont" " pas été automatiquement mises à jour." -#: indico_vc_zoom/plugin.py:464 +#: indico_vc_zoom/plugin.py:493 msgid "" -"There are one or more scheduled Zoom meetings associated with contribution " -"'{}' which were not automatically updated." +"There are one or more scheduled Zoom meetings associated with the " +"contribution \"{}\" which were not automatically updated." msgstr "" -"Il existe une ou plusieurs réunions Zoom associées à la contribution '{}' " -"qui n'ont pas été mises à jour automatiquement." +"Il y a une ou plusieurs réunion Zoom associées à la contribution \"{}\" qui " +"n'ont pas été automatiquement mises à jour." -#: indico_vc_zoom/plugin.py:467 +#: indico_vc_zoom/plugin.py:496 msgid "" "There are one or more scheduled Zoom meetings associated with this session " "block which were not automatically updated." @@ -276,11 +303,23 @@ msgstr "" "Il existe une ou plusieurs réunions Zoom associées à ce bloc de session qui " "n'ont pas été automatiquement mises à jour." -#: indico_vc_zoom/util.py:74 +#: indico_vc_zoom/util.py:42 +msgid "All emails" +msgstr "Toutes les adresses de courriel" + +#: indico_vc_zoom/util.py:43 +msgid "Email domains" +msgstr "Domaines de courriel" + +#: indico_vc_zoom/util.py:44 +msgid "Authenticators" +msgstr "Authentificateurs" + +#: indico_vc_zoom/util.py:124 msgid "This room has been deleted from Zoom" msgstr "Cette réunion a été effacée de Zoom" -#: indico_vc_zoom/util.py:78 +#: indico_vc_zoom/util.py:128 msgid "" "Problem fetching room from Zoom. Please contact support if the error " "persists." @@ -288,74 +327,111 @@ msgstr "" "Erreur en récupérant la réunion Zoom. Veuillez contacter le support si cette" " erreur persiste." -#: indico_vc_zoom/util.py:97 +#: indico_vc_zoom/util.py:147 msgid "Can't update meeting. Please contact support if the error persists." msgstr "" "Impossible de mettre à jour la réunion. Veuillez contacter le support si " "l'erreur persiste." -#: indico_vc_zoom/templates/buttons.html:7 -msgid "You will become the host of this Zoom meeting" -msgstr "Vous deviendrez l'hôte de cette réunion Zoom" +#: indico_vc_zoom/templates/buttons.html:9 +msgid "You will become an alternative host of this Zoom meeting" +msgstr "Vous deviendrez un hôte alternatif de cette réunion Zoom" -#: indico_vc_zoom/templates/buttons.html:10 -msgid "Make me host" -msgstr "Faites de moi l'hôte" +#: indico_vc_zoom/templates/buttons.html:12 +msgid "Make me alternative host" +msgstr "Faites de moi un hôte alternatif" -#: indico_vc_zoom/templates/buttons.html:22 -#: indico_vc_zoom/templates/buttons.html:28 +#: indico_vc_zoom/templates/buttons.html:26 +#: indico_vc_zoom/templates/buttons.html:32 msgid "Join" msgstr "Rejoindre" -#: indico_vc_zoom/templates/buttons.html:26 +#: indico_vc_zoom/templates/buttons.html:30 msgid "You will need a passcode to join this Zoom meeting" msgstr "Vous aurez besoin d'un code secret pour rejoindre cette réunion Zoom" -#: indico_vc_zoom/templates/buttons.html:32 +#: indico_vc_zoom/templates/buttons.html:38 +#: indico_vc_zoom/templates/buttons.html:44 +#: indico_vc_zoom/templates/buttons.html:50 +msgid "This Zoom Meeting can only be seen by registered participants" +msgstr "Cette réunion Zoom ne peut être vue que par les participants inscrits" + +#: indico_vc_zoom/templates/buttons.html:40 +msgid "Please register" +msgstr "Veuillez vous inscrire" + +#: indico_vc_zoom/templates/buttons.html:45 +msgid "Registration required" +msgstr "Inscription nécessaire" + +#: indico_vc_zoom/templates/buttons.html:52 +msgid "Please log in and register" +msgstr "Veuillez vous connecter et vous inscrire" + +#: indico_vc_zoom/templates/buttons.html:57 msgid "This Zoom Meeting can only be seen by logged in users" msgstr "" "Cette réunion Zoom ne peut être vue que par les utilisateurs connectés" -#: indico_vc_zoom/templates/buttons.html:34 +#: indico_vc_zoom/templates/buttons.html:59 msgid "Please log in" msgstr "Veuillez vous connecter" -#: indico_vc_zoom/templates/info_box.html:4 -#: indico_vc_zoom/templates/manage_event_info_box.html:5 +#: indico_vc_zoom/templates/extra_delete_msg.html:2 +#, python-format +msgid "" +"The host of this Zoom meeting is %(host)s. In case you want" +" to delete this Zoom meeting from all events, please make sure that they do " +"not use it for other events that may still need it!" +msgstr "" +"L'hôte de cette réunion Zoom est %(host)s. Au cas où vous " +"voudriez supprimer cette réunion Zoom de tous les évènements, veuillez vous " +"assurer qu'ils ne l'utilisent pas pour d'autres événements qui pourraient " +"toujours en avoir besoin!" + +#: indico_vc_zoom/templates/info_box.html:5 +#: indico_vc_zoom/templates/manage_event_info_box.html:6 msgid "Zoom Meeting ID" msgstr "ID de réunion Zoom" -#: indico_vc_zoom/templates/info_box.html:11 -#: indico_vc_zoom/templates/manage_event_info_box.html:11 +#: indico_vc_zoom/templates/info_box.html:12 +#: indico_vc_zoom/templates/manage_event_info_box.html:12 msgid "Host" msgstr "Hôte" -#: indico_vc_zoom/templates/info_box.html:20 -#: indico_vc_zoom/templates/manage_event_info_box.html:30 +#: indico_vc_zoom/templates/info_box.html:17 +#: indico_vc_zoom/templates/manage_event_info_box.html:18 +msgid "Alternative host" +msgid_plural "Alternative hosts" +msgstr[0] "Hôte alternatif" +msgstr[1] "Hôtes alternatifs" + +#: indico_vc_zoom/templates/info_box.html:35 +#: indico_vc_zoom/templates/manage_event_info_box.html:43 msgid "Zoom URL" msgstr "URL Zoom" -#: indico_vc_zoom/templates/manage_event_info_box.html:15 +#: indico_vc_zoom/templates/manage_event_info_box.html:28 msgid "Linked to" msgstr "Liée à" -#: indico_vc_zoom/templates/manage_event_info_box.html:21 +#: indico_vc_zoom/templates/manage_event_info_box.html:34 msgid "the whole event" msgstr "l'événement entier" -#: indico_vc_zoom/templates/manage_event_info_box.html:23 +#: indico_vc_zoom/templates/manage_event_info_box.html:36 msgid "Contribution" msgstr "Contribution" -#: indico_vc_zoom/templates/manage_event_info_box.html:25 +#: indico_vc_zoom/templates/manage_event_info_box.html:38 msgid "Session" msgstr "Session" -#: indico_vc_zoom/templates/manage_event_info_box.html:34 +#: indico_vc_zoom/templates/manage_event_info_box.html:47 msgid "Created on" msgstr "Créé le" -#: indico_vc_zoom/templates/manage_event_info_box.html:37 +#: indico_vc_zoom/templates/manage_event_info_box.html:50 msgid "Modified on" msgstr "Modifiée le" From 81802aa297987406e75dfcd0b9afd598bb9803c7 Mon Sep 17 00:00:00 2001 From: Indico Team Date: Tue, 5 Jan 2021 12:30:39 +0100 Subject: [PATCH 90/94] Happy new year 2021 :fireworks: --- _meta/setup.py | 2 +- importer/indico_importer/__init__.py | 2 +- importer/indico_importer/base.py | 2 +- importer/indico_importer/client/index.js | 2 +- importer/indico_importer/client/main.css | 2 +- importer/indico_importer/controllers.py | 2 +- importer/indico_importer/converter.py | 2 +- importer/indico_importer/plugin.py | 2 +- importer/indico_importer/util.py | 2 +- importer/setup.py | 2 +- importer_invenio/indico_importer_invenio/__init__.py | 2 +- importer_invenio/indico_importer_invenio/connector.py | 2 +- importer_invenio/indico_importer_invenio/converters.py | 2 +- importer_invenio/indico_importer_invenio/forms.py | 2 +- importer_invenio/indico_importer_invenio/importer.py | 2 +- importer_invenio/indico_importer_invenio/plugin.py | 2 +- importer_invenio/setup.py | 2 +- livesync/indico_livesync/__init__.py | 2 +- livesync/indico_livesync/base.py | 2 +- livesync/indico_livesync/blueprint.py | 2 +- livesync/indico_livesync/cli.py | 2 +- livesync/indico_livesync/controllers.py | 2 +- livesync/indico_livesync/forms.py | 2 +- livesync/indico_livesync/handler.py | 2 +- livesync/indico_livesync/marcxml.py | 2 +- livesync/indico_livesync/models/agents.py | 2 +- livesync/indico_livesync/models/queue.py | 2 +- livesync/indico_livesync/plugin.py | 2 +- livesync/indico_livesync/simplify.py | 2 +- livesync/indico_livesync/task.py | 2 +- livesync/indico_livesync/uploader.py | 2 +- livesync/indico_livesync/util.py | 2 +- livesync/setup.py | 2 +- livesync/tests/agent_test.py | 2 +- livesync/tests/conftest.py | 2 +- livesync/tests/queue_test.py | 2 +- livesync/tests/simplify_test.py | 2 +- livesync/tests/uploader_test.py | 2 +- livesync/tests/util_test.py | 2 +- livesync_debug/indico_livesync_debug/backend.py | 2 +- livesync_debug/indico_livesync_debug/plugin.py | 2 +- livesync_debug/setup.py | 2 +- payment_manual/indico_payment_manual/__init__.py | 2 +- payment_manual/indico_payment_manual/placeholders.py | 2 +- payment_manual/indico_payment_manual/plugin.py | 2 +- payment_manual/setup.py | 2 +- payment_paypal/indico_payment_paypal/__init__.py | 2 +- payment_paypal/indico_payment_paypal/blueprint.py | 2 +- payment_paypal/indico_payment_paypal/controllers.py | 2 +- payment_paypal/indico_payment_paypal/plugin.py | 2 +- payment_paypal/indico_payment_paypal/util.py | 2 +- payment_paypal/setup.py | 2 +- payment_paypal/tests/controllers_test.py | 2 +- payment_paypal/tests/util_test.py | 2 +- piwik/indico_piwik/__init__.py | 2 +- piwik/indico_piwik/client/index.js | 2 +- piwik/indico_piwik/client/main.css | 2 +- piwik/indico_piwik/controllers.py | 2 +- piwik/indico_piwik/forms.py | 2 +- piwik/indico_piwik/piwik.py | 2 +- piwik/indico_piwik/plugin.py | 2 +- piwik/indico_piwik/queries/base.py | 2 +- piwik/indico_piwik/queries/graphs.py | 2 +- piwik/indico_piwik/queries/metrics.py | 2 +- piwik/indico_piwik/queries/tracking.py | 2 +- piwik/indico_piwik/queries/utils.py | 2 +- piwik/indico_piwik/reports.py | 2 +- piwik/indico_piwik/views.py | 2 +- piwik/setup.py | 2 +- previewer_code/indico_previewer_code/__init__.py | 2 +- previewer_code/indico_previewer_code/plugin.py | 2 +- previewer_code/setup.py | 2 +- previewer_jupyter/indico_previewer_jupyter/__init__.py | 2 +- previewer_jupyter/indico_previewer_jupyter/blueprint.py | 2 +- previewer_jupyter/indico_previewer_jupyter/controllers.py | 2 +- previewer_jupyter/indico_previewer_jupyter/cpp_highlighter.py | 2 +- previewer_jupyter/indico_previewer_jupyter/plugin.py | 2 +- previewer_jupyter/setup.py | 2 +- search/indico_search/__init__.py | 2 +- search/indico_search/base.py | 2 +- search/indico_search/blueprint.py | 2 +- search/indico_search/client/index.js | 2 +- search/indico_search/client/main.scss | 2 +- search/indico_search/controllers.py | 2 +- search/indico_search/forms.py | 2 +- search/indico_search/plugin.py | 2 +- search/indico_search/util.py | 2 +- search/indico_search/views.py | 2 +- search/setup.py | 2 +- storage_s3/indico_storage_s3/__init__.py | 2 +- storage_s3/indico_storage_s3/blueprint.py | 2 +- storage_s3/indico_storage_s3/controllers.py | 2 +- storage_s3/indico_storage_s3/migrate.py | 2 +- storage_s3/indico_storage_s3/plugin.py | 2 +- storage_s3/indico_storage_s3/storage.py | 2 +- storage_s3/indico_storage_s3/task.py | 2 +- storage_s3/setup.py | 2 +- storage_s3/tests/plugin_test.py | 2 +- update-meta.py | 2 +- ursh/indico_ursh/__init__.py | 2 +- ursh/indico_ursh/blueprint.py | 2 +- ursh/indico_ursh/client/index.js | 2 +- ursh/indico_ursh/controllers.py | 2 +- ursh/indico_ursh/plugin.py | 2 +- ursh/indico_ursh/util.py | 2 +- ursh/indico_ursh/views.py | 2 +- ursh/setup.py | 2 +- vc_dummy/indico_vc_dummy/plugin.py | 2 +- vc_dummy/setup.py | 2 +- vc_vidyo/indico_vc_vidyo/__init__.py | 2 +- vc_vidyo/indico_vc_vidyo/api/__init__.py | 2 +- vc_vidyo/indico_vc_vidyo/api/cache.py | 2 +- vc_vidyo/indico_vc_vidyo/api/client.py | 2 +- vc_vidyo/indico_vc_vidyo/blueprint.py | 2 +- vc_vidyo/indico_vc_vidyo/cli.py | 2 +- vc_vidyo/indico_vc_vidyo/client/index.js | 2 +- vc_vidyo/indico_vc_vidyo/controllers.py | 2 +- vc_vidyo/indico_vc_vidyo/forms.py | 2 +- vc_vidyo/indico_vc_vidyo/http_api.py | 2 +- vc_vidyo/indico_vc_vidyo/models/vidyo_extensions.py | 2 +- vc_vidyo/indico_vc_vidyo/plugin.py | 2 +- vc_vidyo/indico_vc_vidyo/task.py | 2 +- vc_vidyo/indico_vc_vidyo/util.py | 2 +- vc_vidyo/setup.py | 2 +- vc_vidyo/tests/task_test.py | 2 +- vc_zoom/conftest.py | 2 +- vc_zoom/indico_vc_zoom/__init__.py | 2 +- vc_zoom/indico_vc_zoom/api/__init__.py | 2 +- vc_zoom/indico_vc_zoom/api/client.py | 2 +- vc_zoom/indico_vc_zoom/blueprint.py | 2 +- vc_zoom/indico_vc_zoom/cli.py | 2 +- vc_zoom/indico_vc_zoom/client/index.js | 2 +- vc_zoom/indico_vc_zoom/controllers.py | 2 +- vc_zoom/indico_vc_zoom/forms.py | 2 +- vc_zoom/indico_vc_zoom/notifications.py | 2 +- vc_zoom/indico_vc_zoom/plugin.py | 2 +- vc_zoom/indico_vc_zoom/util.py | 2 +- vc_zoom/setup.py | 2 +- vc_zoom/tests/operation_test.py | 2 +- 139 files changed, 139 insertions(+), 139 deletions(-) diff --git a/_meta/setup.py b/_meta/setup.py index 7b33ec4..9a448b5 100644 --- a/_meta/setup.py +++ b/_meta/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/__init__.py b/importer/indico_importer/__init__.py index 55a1b99..2667e51 100644 --- a/importer/indico_importer/__init__.py +++ b/importer/indico_importer/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/base.py b/importer/indico_importer/base.py index e9fbee3..8d70e52 100644 --- a/importer/indico_importer/base.py +++ b/importer/indico_importer/base.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/client/index.js b/importer/indico_importer/client/index.js index 077cf83..59eedcf 100644 --- a/importer/indico_importer/client/index.js +++ b/importer/indico_importer/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2020 CERN +// Copyright (C) 2002 - 2021 CERN // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/client/main.css b/importer/indico_importer/client/main.css index 39e07b5..778c623 100644 --- a/importer/indico_importer/client/main.css +++ b/importer/indico_importer/client/main.css @@ -1,5 +1,5 @@ /* This file is part of the Indico plugins. - * Copyright (C) 2002 - 2020 CERN + * Copyright (C) 2002 - 2021 CERN * * The Indico plugins are free software; you can redistribute * them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/controllers.py b/importer/indico_importer/controllers.py index d5d2b52..0e9c49d 100644 --- a/importer/indico_importer/controllers.py +++ b/importer/indico_importer/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/converter.py b/importer/indico_importer/converter.py index f8b138c..c0a0e5b 100644 --- a/importer/indico_importer/converter.py +++ b/importer/indico_importer/converter.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/plugin.py b/importer/indico_importer/plugin.py index 4dc2be7..18eaac3 100644 --- a/importer/indico_importer/plugin.py +++ b/importer/indico_importer/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/indico_importer/util.py b/importer/indico_importer/util.py index 96f8693..ac72ce7 100644 --- a/importer/indico_importer/util.py +++ b/importer/indico_importer/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer/setup.py b/importer/setup.py index 59bf38f..9a67255 100644 --- a/importer/setup.py +++ b/importer/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/indico_importer_invenio/__init__.py b/importer_invenio/indico_importer_invenio/__init__.py index ef7b709..a70b410 100644 --- a/importer_invenio/indico_importer_invenio/__init__.py +++ b/importer_invenio/indico_importer_invenio/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/indico_importer_invenio/connector.py b/importer_invenio/indico_importer_invenio/connector.py index 98d5915..8477cb6 100644 --- a/importer_invenio/indico_importer_invenio/connector.py +++ b/importer_invenio/indico_importer_invenio/connector.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/indico_importer_invenio/converters.py b/importer_invenio/indico_importer_invenio/converters.py index 5c55e90..83cafd3 100644 --- a/importer_invenio/indico_importer_invenio/converters.py +++ b/importer_invenio/indico_importer_invenio/converters.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/indico_importer_invenio/forms.py b/importer_invenio/indico_importer_invenio/forms.py index 0529a5e..4b73cdc 100644 --- a/importer_invenio/indico_importer_invenio/forms.py +++ b/importer_invenio/indico_importer_invenio/forms.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/indico_importer_invenio/importer.py b/importer_invenio/indico_importer_invenio/importer.py index 78aed0b..c6bc814 100644 --- a/importer_invenio/indico_importer_invenio/importer.py +++ b/importer_invenio/indico_importer_invenio/importer.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/indico_importer_invenio/plugin.py b/importer_invenio/indico_importer_invenio/plugin.py index 5333b03..5c6b03b 100644 --- a/importer_invenio/indico_importer_invenio/plugin.py +++ b/importer_invenio/indico_importer_invenio/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/importer_invenio/setup.py b/importer_invenio/setup.py index 25b404a..211fe12 100644 --- a/importer_invenio/setup.py +++ b/importer_invenio/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/__init__.py b/livesync/indico_livesync/__init__.py index a086bbc..cd633a1 100644 --- a/livesync/indico_livesync/__init__.py +++ b/livesync/indico_livesync/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/base.py b/livesync/indico_livesync/base.py index 9004cc3..43cc23d 100644 --- a/livesync/indico_livesync/base.py +++ b/livesync/indico_livesync/base.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/blueprint.py b/livesync/indico_livesync/blueprint.py index a70a8b4..37aaaaa 100644 --- a/livesync/indico_livesync/blueprint.py +++ b/livesync/indico_livesync/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/cli.py b/livesync/indico_livesync/cli.py index 1885ace..b74e0d3 100644 --- a/livesync/indico_livesync/cli.py +++ b/livesync/indico_livesync/cli.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/controllers.py b/livesync/indico_livesync/controllers.py index db8663e..cd5405e 100644 --- a/livesync/indico_livesync/controllers.py +++ b/livesync/indico_livesync/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/forms.py b/livesync/indico_livesync/forms.py index d9563d7..1f191e4 100644 --- a/livesync/indico_livesync/forms.py +++ b/livesync/indico_livesync/forms.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/handler.py b/livesync/indico_livesync/handler.py index 2c37237..9952ea9 100644 --- a/livesync/indico_livesync/handler.py +++ b/livesync/indico_livesync/handler.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/marcxml.py b/livesync/indico_livesync/marcxml.py index 81d91a6..1bb4905 100644 --- a/livesync/indico_livesync/marcxml.py +++ b/livesync/indico_livesync/marcxml.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/models/agents.py b/livesync/indico_livesync/models/agents.py index 892e54a..8e54341 100644 --- a/livesync/indico_livesync/models/agents.py +++ b/livesync/indico_livesync/models/agents.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/models/queue.py b/livesync/indico_livesync/models/queue.py index 6097cb0..80a1797 100644 --- a/livesync/indico_livesync/models/queue.py +++ b/livesync/indico_livesync/models/queue.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/plugin.py b/livesync/indico_livesync/plugin.py index 9912e92..282e217 100644 --- a/livesync/indico_livesync/plugin.py +++ b/livesync/indico_livesync/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/simplify.py b/livesync/indico_livesync/simplify.py index b1db9fe..85d0bdb 100644 --- a/livesync/indico_livesync/simplify.py +++ b/livesync/indico_livesync/simplify.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/task.py b/livesync/indico_livesync/task.py index 65a477f..7aa9f80 100644 --- a/livesync/indico_livesync/task.py +++ b/livesync/indico_livesync/task.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/uploader.py b/livesync/indico_livesync/uploader.py index bc9b744..8e35b8f 100644 --- a/livesync/indico_livesync/uploader.py +++ b/livesync/indico_livesync/uploader.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/indico_livesync/util.py b/livesync/indico_livesync/util.py index 09b090c..983f332 100644 --- a/livesync/indico_livesync/util.py +++ b/livesync/indico_livesync/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/setup.py b/livesync/setup.py index 8eee8dd..39f982a 100644 --- a/livesync/setup.py +++ b/livesync/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/tests/agent_test.py b/livesync/tests/agent_test.py index ea506f3..a3900cd 100644 --- a/livesync/tests/agent_test.py +++ b/livesync/tests/agent_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/tests/conftest.py b/livesync/tests/conftest.py index d6a4853..a724745 100644 --- a/livesync/tests/conftest.py +++ b/livesync/tests/conftest.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/tests/queue_test.py b/livesync/tests/queue_test.py index 398b714..2150ae5 100644 --- a/livesync/tests/queue_test.py +++ b/livesync/tests/queue_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/tests/simplify_test.py b/livesync/tests/simplify_test.py index c30e233..0636fad 100644 --- a/livesync/tests/simplify_test.py +++ b/livesync/tests/simplify_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/tests/uploader_test.py b/livesync/tests/uploader_test.py index 2caa0a1..868ad77 100644 --- a/livesync/tests/uploader_test.py +++ b/livesync/tests/uploader_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync/tests/util_test.py b/livesync/tests/util_test.py index 09d9774..440e6d7 100644 --- a/livesync/tests/util_test.py +++ b/livesync/tests/util_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync_debug/indico_livesync_debug/backend.py b/livesync_debug/indico_livesync_debug/backend.py index 40fd974..6494bd0 100644 --- a/livesync_debug/indico_livesync_debug/backend.py +++ b/livesync_debug/indico_livesync_debug/backend.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync_debug/indico_livesync_debug/plugin.py b/livesync_debug/indico_livesync_debug/plugin.py index 5446d83..1f83930 100644 --- a/livesync_debug/indico_livesync_debug/plugin.py +++ b/livesync_debug/indico_livesync_debug/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/livesync_debug/setup.py b/livesync_debug/setup.py index d3b8020..9f6ca2b 100644 --- a/livesync_debug/setup.py +++ b/livesync_debug/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_manual/indico_payment_manual/__init__.py b/payment_manual/indico_payment_manual/__init__.py index 04f67c2..23dd811 100644 --- a/payment_manual/indico_payment_manual/__init__.py +++ b/payment_manual/indico_payment_manual/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_manual/indico_payment_manual/placeholders.py b/payment_manual/indico_payment_manual/placeholders.py index fb85c53..7150aa7 100644 --- a/payment_manual/indico_payment_manual/placeholders.py +++ b/payment_manual/indico_payment_manual/placeholders.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_manual/indico_payment_manual/plugin.py b/payment_manual/indico_payment_manual/plugin.py index 58fe235..65fa6a7 100644 --- a/payment_manual/indico_payment_manual/plugin.py +++ b/payment_manual/indico_payment_manual/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_manual/setup.py b/payment_manual/setup.py index f6a8ef3..13269d0 100644 --- a/payment_manual/setup.py +++ b/payment_manual/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/indico_payment_paypal/__init__.py b/payment_paypal/indico_payment_paypal/__init__.py index 9d2be1a..64395de 100644 --- a/payment_paypal/indico_payment_paypal/__init__.py +++ b/payment_paypal/indico_payment_paypal/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/indico_payment_paypal/blueprint.py b/payment_paypal/indico_payment_paypal/blueprint.py index e00da1a..27cfbc1 100644 --- a/payment_paypal/indico_payment_paypal/blueprint.py +++ b/payment_paypal/indico_payment_paypal/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/indico_payment_paypal/controllers.py b/payment_paypal/indico_payment_paypal/controllers.py index f40b1b9..b1d12ff 100644 --- a/payment_paypal/indico_payment_paypal/controllers.py +++ b/payment_paypal/indico_payment_paypal/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/indico_payment_paypal/plugin.py b/payment_paypal/indico_payment_paypal/plugin.py index 8e7764f..01fcc83 100644 --- a/payment_paypal/indico_payment_paypal/plugin.py +++ b/payment_paypal/indico_payment_paypal/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/indico_payment_paypal/util.py b/payment_paypal/indico_payment_paypal/util.py index 2352737..6ab6962 100644 --- a/payment_paypal/indico_payment_paypal/util.py +++ b/payment_paypal/indico_payment_paypal/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/setup.py b/payment_paypal/setup.py index 21222b6..3c1cbed 100644 --- a/payment_paypal/setup.py +++ b/payment_paypal/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/tests/controllers_test.py b/payment_paypal/tests/controllers_test.py index f083eda..a0948af 100644 --- a/payment_paypal/tests/controllers_test.py +++ b/payment_paypal/tests/controllers_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/payment_paypal/tests/util_test.py b/payment_paypal/tests/util_test.py index 484c1ba..62ced7c 100644 --- a/payment_paypal/tests/util_test.py +++ b/payment_paypal/tests/util_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/__init__.py b/piwik/indico_piwik/__init__.py index ee76d4b..c06335e 100644 --- a/piwik/indico_piwik/__init__.py +++ b/piwik/indico_piwik/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/client/index.js b/piwik/indico_piwik/client/index.js index dd37c19..7f53b04 100644 --- a/piwik/indico_piwik/client/index.js +++ b/piwik/indico_piwik/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2020 CERN +// Copyright (C) 2002 - 2021 CERN // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/client/main.css b/piwik/indico_piwik/client/main.css index 10c48ac..a73dcd8 100644 --- a/piwik/indico_piwik/client/main.css +++ b/piwik/indico_piwik/client/main.css @@ -1,5 +1,5 @@ /* This file is part of the Indico plugins. - * Copyright (C) 2002 - 2020 CERN + * Copyright (C) 2002 - 2021 CERN * * The Indico plugins are free software; you can redistribute * them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/controllers.py b/piwik/indico_piwik/controllers.py index 4e5f540..101fdae 100644 --- a/piwik/indico_piwik/controllers.py +++ b/piwik/indico_piwik/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/forms.py b/piwik/indico_piwik/forms.py index b57f15a..28619f2 100644 --- a/piwik/indico_piwik/forms.py +++ b/piwik/indico_piwik/forms.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/piwik.py b/piwik/indico_piwik/piwik.py index 46291e6..b9f1ff5 100644 --- a/piwik/indico_piwik/piwik.py +++ b/piwik/indico_piwik/piwik.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/plugin.py b/piwik/indico_piwik/plugin.py index 173ac5e..39e96c2 100644 --- a/piwik/indico_piwik/plugin.py +++ b/piwik/indico_piwik/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/queries/base.py b/piwik/indico_piwik/queries/base.py index 4409f16..5bf9a77 100644 --- a/piwik/indico_piwik/queries/base.py +++ b/piwik/indico_piwik/queries/base.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/queries/graphs.py b/piwik/indico_piwik/queries/graphs.py index eeeb543..34fe660 100644 --- a/piwik/indico_piwik/queries/graphs.py +++ b/piwik/indico_piwik/queries/graphs.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/queries/metrics.py b/piwik/indico_piwik/queries/metrics.py index fe6bd90..624b457 100644 --- a/piwik/indico_piwik/queries/metrics.py +++ b/piwik/indico_piwik/queries/metrics.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/queries/tracking.py b/piwik/indico_piwik/queries/tracking.py index 5f35693..c45f4be 100644 --- a/piwik/indico_piwik/queries/tracking.py +++ b/piwik/indico_piwik/queries/tracking.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/queries/utils.py b/piwik/indico_piwik/queries/utils.py index ab0a7f0..2cbad73 100644 --- a/piwik/indico_piwik/queries/utils.py +++ b/piwik/indico_piwik/queries/utils.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/reports.py b/piwik/indico_piwik/reports.py index bbc8343..b6fab57 100644 --- a/piwik/indico_piwik/reports.py +++ b/piwik/indico_piwik/reports.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/indico_piwik/views.py b/piwik/indico_piwik/views.py index a3cfee7..56f8909 100644 --- a/piwik/indico_piwik/views.py +++ b/piwik/indico_piwik/views.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/piwik/setup.py b/piwik/setup.py index 8c37e08..aa37bab 100644 --- a/piwik/setup.py +++ b/piwik/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_code/indico_previewer_code/__init__.py b/previewer_code/indico_previewer_code/__init__.py index 9b79da3..888e8c8 100644 --- a/previewer_code/indico_previewer_code/__init__.py +++ b/previewer_code/indico_previewer_code/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_code/indico_previewer_code/plugin.py b/previewer_code/indico_previewer_code/plugin.py index 32d7bb6..5df5f91 100644 --- a/previewer_code/indico_previewer_code/plugin.py +++ b/previewer_code/indico_previewer_code/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_code/setup.py b/previewer_code/setup.py index 3dbdccb..353328d 100644 --- a/previewer_code/setup.py +++ b/previewer_code/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_jupyter/indico_previewer_jupyter/__init__.py b/previewer_jupyter/indico_previewer_jupyter/__init__.py index 67a0745..eadb69c 100644 --- a/previewer_jupyter/indico_previewer_jupyter/__init__.py +++ b/previewer_jupyter/indico_previewer_jupyter/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_jupyter/indico_previewer_jupyter/blueprint.py b/previewer_jupyter/indico_previewer_jupyter/blueprint.py index 9984b23..fb418f6 100644 --- a/previewer_jupyter/indico_previewer_jupyter/blueprint.py +++ b/previewer_jupyter/indico_previewer_jupyter/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_jupyter/indico_previewer_jupyter/controllers.py b/previewer_jupyter/indico_previewer_jupyter/controllers.py index e097351..d82f72c 100644 --- a/previewer_jupyter/indico_previewer_jupyter/controllers.py +++ b/previewer_jupyter/indico_previewer_jupyter/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_jupyter/indico_previewer_jupyter/cpp_highlighter.py b/previewer_jupyter/indico_previewer_jupyter/cpp_highlighter.py index ae52666..baa575c 100644 --- a/previewer_jupyter/indico_previewer_jupyter/cpp_highlighter.py +++ b/previewer_jupyter/indico_previewer_jupyter/cpp_highlighter.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_jupyter/indico_previewer_jupyter/plugin.py b/previewer_jupyter/indico_previewer_jupyter/plugin.py index 0e93001..0574b87 100644 --- a/previewer_jupyter/indico_previewer_jupyter/plugin.py +++ b/previewer_jupyter/indico_previewer_jupyter/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/previewer_jupyter/setup.py b/previewer_jupyter/setup.py index 7be753d..0cb6da3 100644 --- a/previewer_jupyter/setup.py +++ b/previewer_jupyter/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/__init__.py b/search/indico_search/__init__.py index 0b57e03..43512a1 100644 --- a/search/indico_search/__init__.py +++ b/search/indico_search/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/base.py b/search/indico_search/base.py index 6559422..ac66ecf 100644 --- a/search/indico_search/base.py +++ b/search/indico_search/base.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/blueprint.py b/search/indico_search/blueprint.py index c81c463..ecc5a8f 100644 --- a/search/indico_search/blueprint.py +++ b/search/indico_search/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/client/index.js b/search/indico_search/client/index.js index 98c6c74..a49acb2 100644 --- a/search/indico_search/client/index.js +++ b/search/indico_search/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2020 CERN +// Copyright (C) 2002 - 2021 CERN // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/client/main.scss b/search/indico_search/client/main.scss index fae692f..9405e53 100644 --- a/search/indico_search/client/main.scss +++ b/search/indico_search/client/main.scss @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2020 CERN +// Copyright (C) 2002 - 2021 CERN // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/controllers.py b/search/indico_search/controllers.py index e0d945f..bfdebd7 100644 --- a/search/indico_search/controllers.py +++ b/search/indico_search/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/forms.py b/search/indico_search/forms.py index c7264ed..0c0397a 100644 --- a/search/indico_search/forms.py +++ b/search/indico_search/forms.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/plugin.py b/search/indico_search/plugin.py index 855a272..e04cf92 100644 --- a/search/indico_search/plugin.py +++ b/search/indico_search/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/util.py b/search/indico_search/util.py index 9901f6c..5beabd1 100644 --- a/search/indico_search/util.py +++ b/search/indico_search/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/indico_search/views.py b/search/indico_search/views.py index 109bb86..f57f89e 100644 --- a/search/indico_search/views.py +++ b/search/indico_search/views.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/search/setup.py b/search/setup.py index 48b8b6c..39435dd 100644 --- a/search/setup.py +++ b/search/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/__init__.py b/storage_s3/indico_storage_s3/__init__.py index c0e9cbe..77417db 100644 --- a/storage_s3/indico_storage_s3/__init__.py +++ b/storage_s3/indico_storage_s3/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/blueprint.py b/storage_s3/indico_storage_s3/blueprint.py index 469c52a..db6bc0c 100644 --- a/storage_s3/indico_storage_s3/blueprint.py +++ b/storage_s3/indico_storage_s3/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/controllers.py b/storage_s3/indico_storage_s3/controllers.py index 64e9cbf..7e26bf3 100644 --- a/storage_s3/indico_storage_s3/controllers.py +++ b/storage_s3/indico_storage_s3/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/migrate.py b/storage_s3/indico_storage_s3/migrate.py index a409ac3..eb1656b 100644 --- a/storage_s3/indico_storage_s3/migrate.py +++ b/storage_s3/indico_storage_s3/migrate.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/plugin.py b/storage_s3/indico_storage_s3/plugin.py index 914462f..564ad90 100644 --- a/storage_s3/indico_storage_s3/plugin.py +++ b/storage_s3/indico_storage_s3/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/storage.py b/storage_s3/indico_storage_s3/storage.py index 2b96149..bba877b 100644 --- a/storage_s3/indico_storage_s3/storage.py +++ b/storage_s3/indico_storage_s3/storage.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/indico_storage_s3/task.py b/storage_s3/indico_storage_s3/task.py index 1c27916..bc5f07a 100644 --- a/storage_s3/indico_storage_s3/task.py +++ b/storage_s3/indico_storage_s3/task.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/setup.py b/storage_s3/setup.py index c447318..1aa6be7 100644 --- a/storage_s3/setup.py +++ b/storage_s3/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/storage_s3/tests/plugin_test.py b/storage_s3/tests/plugin_test.py index 1133e2c..279ca51 100644 --- a/storage_s3/tests/plugin_test.py +++ b/storage_s3/tests/plugin_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/update-meta.py b/update-meta.py index ab25fca..62f168a 100644 --- a/update-meta.py +++ b/update-meta.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/__init__.py b/ursh/indico_ursh/__init__.py index 2128765..9bc3b0e 100644 --- a/ursh/indico_ursh/__init__.py +++ b/ursh/indico_ursh/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/blueprint.py b/ursh/indico_ursh/blueprint.py index e1ddcef..27e7c1a 100644 --- a/ursh/indico_ursh/blueprint.py +++ b/ursh/indico_ursh/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/client/index.js b/ursh/indico_ursh/client/index.js index 8c852aa..f097a12 100644 --- a/ursh/indico_ursh/client/index.js +++ b/ursh/indico_ursh/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2020 CERN +// Copyright (C) 2002 - 2021 CERN // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/controllers.py b/ursh/indico_ursh/controllers.py index 6ff5e02..548beef 100644 --- a/ursh/indico_ursh/controllers.py +++ b/ursh/indico_ursh/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/plugin.py b/ursh/indico_ursh/plugin.py index 77e6fdb..62133ca 100644 --- a/ursh/indico_ursh/plugin.py +++ b/ursh/indico_ursh/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/util.py b/ursh/indico_ursh/util.py index 08daa7c..8325ba3 100644 --- a/ursh/indico_ursh/util.py +++ b/ursh/indico_ursh/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/indico_ursh/views.py b/ursh/indico_ursh/views.py index a44b2f6..885d458 100644 --- a/ursh/indico_ursh/views.py +++ b/ursh/indico_ursh/views.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/ursh/setup.py b/ursh/setup.py index 3c87dd1..92f4c3c 100644 --- a/ursh/setup.py +++ b/ursh/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_dummy/indico_vc_dummy/plugin.py b/vc_dummy/indico_vc_dummy/plugin.py index 87aa077..ccdd34b 100644 --- a/vc_dummy/indico_vc_dummy/plugin.py +++ b/vc_dummy/indico_vc_dummy/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_dummy/setup.py b/vc_dummy/setup.py index 3e512e5..6f9702d 100644 --- a/vc_dummy/setup.py +++ b/vc_dummy/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/__init__.py b/vc_vidyo/indico_vc_vidyo/__init__.py index 12347a6..6cf1daf 100644 --- a/vc_vidyo/indico_vc_vidyo/__init__.py +++ b/vc_vidyo/indico_vc_vidyo/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/api/__init__.py b/vc_vidyo/indico_vc_vidyo/api/__init__.py index 4020bee..afcef7a 100644 --- a/vc_vidyo/indico_vc_vidyo/api/__init__.py +++ b/vc_vidyo/indico_vc_vidyo/api/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/api/cache.py b/vc_vidyo/indico_vc_vidyo/api/cache.py index 90450f7..4c05836 100644 --- a/vc_vidyo/indico_vc_vidyo/api/cache.py +++ b/vc_vidyo/indico_vc_vidyo/api/cache.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/api/client.py b/vc_vidyo/indico_vc_vidyo/api/client.py index fc16f72..8929542 100644 --- a/vc_vidyo/indico_vc_vidyo/api/client.py +++ b/vc_vidyo/indico_vc_vidyo/api/client.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/blueprint.py b/vc_vidyo/indico_vc_vidyo/blueprint.py index 32036eb..c66f042 100644 --- a/vc_vidyo/indico_vc_vidyo/blueprint.py +++ b/vc_vidyo/indico_vc_vidyo/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/cli.py b/vc_vidyo/indico_vc_vidyo/cli.py index 083f276..f1448b1 100644 --- a/vc_vidyo/indico_vc_vidyo/cli.py +++ b/vc_vidyo/indico_vc_vidyo/cli.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/client/index.js b/vc_vidyo/indico_vc_vidyo/client/index.js index 3773394..0707b50 100644 --- a/vc_vidyo/indico_vc_vidyo/client/index.js +++ b/vc_vidyo/indico_vc_vidyo/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2002 - 2020 CERN +// Copyright (C) 2002 - 2021 CERN // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/controllers.py b/vc_vidyo/indico_vc_vidyo/controllers.py index 618d173..5abdbf1 100644 --- a/vc_vidyo/indico_vc_vidyo/controllers.py +++ b/vc_vidyo/indico_vc_vidyo/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/forms.py b/vc_vidyo/indico_vc_vidyo/forms.py index 4d8ae31..f929f05 100644 --- a/vc_vidyo/indico_vc_vidyo/forms.py +++ b/vc_vidyo/indico_vc_vidyo/forms.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/http_api.py b/vc_vidyo/indico_vc_vidyo/http_api.py index ec74191..f7ab62b 100644 --- a/vc_vidyo/indico_vc_vidyo/http_api.py +++ b/vc_vidyo/indico_vc_vidyo/http_api.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/models/vidyo_extensions.py b/vc_vidyo/indico_vc_vidyo/models/vidyo_extensions.py index 882f3a7..865acb8 100644 --- a/vc_vidyo/indico_vc_vidyo/models/vidyo_extensions.py +++ b/vc_vidyo/indico_vc_vidyo/models/vidyo_extensions.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/plugin.py b/vc_vidyo/indico_vc_vidyo/plugin.py index bb28a3b..4bd1da3 100644 --- a/vc_vidyo/indico_vc_vidyo/plugin.py +++ b/vc_vidyo/indico_vc_vidyo/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/task.py b/vc_vidyo/indico_vc_vidyo/task.py index 18e4fdc..d197552 100644 --- a/vc_vidyo/indico_vc_vidyo/task.py +++ b/vc_vidyo/indico_vc_vidyo/task.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/indico_vc_vidyo/util.py b/vc_vidyo/indico_vc_vidyo/util.py index 450083e..2e6f8a9 100644 --- a/vc_vidyo/indico_vc_vidyo/util.py +++ b/vc_vidyo/indico_vc_vidyo/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/setup.py b/vc_vidyo/setup.py index d42c728..f8b26d7 100644 --- a/vc_vidyo/setup.py +++ b/vc_vidyo/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_vidyo/tests/task_test.py b/vc_vidyo/tests/task_test.py index 1b62e93..8401509 100644 --- a/vc_vidyo/tests/task_test.py +++ b/vc_vidyo/tests/task_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2002 - 2020 CERN +# Copyright (C) 2002 - 2021 CERN # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/conftest.py b/vc_zoom/conftest.py index 2dba5e3..2071ebf 100644 --- a/vc_zoom/conftest.py +++ b/vc_zoom/conftest.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/__init__.py b/vc_zoom/indico_vc_zoom/__init__.py index c99356c..cd6162c 100644 --- a/vc_zoom/indico_vc_zoom/__init__.py +++ b/vc_zoom/indico_vc_zoom/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/api/__init__.py b/vc_zoom/indico_vc_zoom/api/__init__.py index b040413..28dc103 100644 --- a/vc_zoom/indico_vc_zoom/api/__init__.py +++ b/vc_zoom/indico_vc_zoom/api/__init__.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index 2ba29b0..6b3da45 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/blueprint.py b/vc_zoom/indico_vc_zoom/blueprint.py index 2392e1a..57cab6d 100644 --- a/vc_zoom/indico_vc_zoom/blueprint.py +++ b/vc_zoom/indico_vc_zoom/blueprint.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/cli.py b/vc_zoom/indico_vc_zoom/cli.py index 48c65e2..fe99cfd 100644 --- a/vc_zoom/indico_vc_zoom/cli.py +++ b/vc_zoom/indico_vc_zoom/cli.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/client/index.js b/vc_zoom/indico_vc_zoom/client/index.js index 60c2f37..d06eb04 100644 --- a/vc_zoom/indico_vc_zoom/client/index.js +++ b/vc_zoom/indico_vc_zoom/client/index.js @@ -1,5 +1,5 @@ // This file is part of the Indico plugins. -// Copyright (C) 2020 CERN and ENEA +// Copyright (C) 2020 - 2021 CERN and ENEA // // The Indico plugins are free software; you can redistribute // them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index 3b10fa7..940f3c4 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 8af613a..0dd0f50 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py index 5aa7707..87a1b14 100644 --- a/vc_zoom/indico_vc_zoom/notifications.py +++ b/vc_zoom/indico_vc_zoom/notifications.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 91368fa..64fd148 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 76693ab..54b38d8 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/setup.py b/vc_zoom/setup.py index c6fb78a..a1994c4 100644 --- a/vc_zoom/setup.py +++ b/vc_zoom/setup.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; diff --git a/vc_zoom/tests/operation_test.py b/vc_zoom/tests/operation_test.py index 0c04942..93896b0 100644 --- a/vc_zoom/tests/operation_test.py +++ b/vc_zoom/tests/operation_test.py @@ -1,5 +1,5 @@ # This file is part of the Indico plugins. -# Copyright (C) 2020 CERN and ENEA +# Copyright (C) 2020 - 2021 CERN and ENEA # # The Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; From 23148c6ffdc795de3e45a823d5b7255c5edfba43 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 13:26:55 +0100 Subject: [PATCH 91/94] Fix string formatting inside _() --- vc_vidyo/indico_vc_vidyo/controllers.py | 2 +- .../fr_FR/LC_MESSAGES/messages.po | 121 +++++++++--------- .../indico_vc_vidyo/translations/messages.pot | 8 +- vc_zoom/indico_vc_zoom/controllers.py | 2 +- .../fr_FR/LC_MESSAGES/messages.po | 9 +- .../indico_vc_zoom/translations/messages.pot | 4 +- 6 files changed, 70 insertions(+), 76 deletions(-) diff --git a/vc_vidyo/indico_vc_vidyo/controllers.py b/vc_vidyo/indico_vc_vidyo/controllers.py index 5abdbf1..8ba0e91 100644 --- a/vc_vidyo/indico_vc_vidyo/controllers.py +++ b/vc_vidyo/indico_vc_vidyo/controllers.py @@ -26,6 +26,6 @@ class RHVidyoRoomOwner(RHVCSystemEventBase): result['success'] = False db.session.rollback() else: - flash(_("You are now the owner of the room '{room.name}'".format(room=self.vc_room)), 'success') + flash(_("You are now the owner of the room '{room}'").format(room=self.vc_room.name), 'success') result['success'] = True return jsonify(result) diff --git a/vc_vidyo/indico_vc_vidyo/translations/fr_FR/LC_MESSAGES/messages.po b/vc_vidyo/indico_vc_vidyo/translations/fr_FR/LC_MESSAGES/messages.po index 61f9670..8de1736 100644 --- a/vc_vidyo/indico_vc_vidyo/translations/fr_FR/LC_MESSAGES/messages.po +++ b/vc_vidyo/indico_vc_vidyo/translations/fr_FR/LC_MESSAGES/messages.po @@ -1,231 +1,224 @@ # Translations template for PROJECT. -# Copyright (C) 2017 ORGANIZATION +# Copyright (C) 2021 ORGANIZATION # This file is distributed under the same license as the PROJECT project. # # Translators: +# Adrian Mönnich, 2021 # Thomas Baron , 2015,2017 msgid "" msgstr "" "Project-Id-Version: Indico\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2017-10-18 11:55+0200\n" -"PO-Revision-Date: 2017-10-30 11:04+0000\n" -"Last-Translator: Thomas Baron \n" +"POT-Creation-Date: 2021-01-05 13:23+0100\n" +"PO-Revision-Date: 2021-01-05 12:24+0000\n" +"Last-Translator: Adrian Mönnich\n" "Language-Team: French (France) (http://www.transifex.com/indico/indico/language/fr_FR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Generated-By: Babel 2.5.1\n" +"Generated-By: Babel 2.8.0\n" "Language: fr_FR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: indico_vc_vidyo/controllers.py:38 -msgid "You are now the owner of the room '{room.name}'" -msgstr "Vous êtes maintenant responsable de la salle '{room.name}'" +#: indico_vc_vidyo/controllers.py:29 +msgid "You are now the owner of the room '{room}'" +msgstr "Vous êtes maintenant responsable de la salle '{room}'" -#: indico_vc_vidyo/forms.py:32 +#: indico_vc_vidyo/forms.py:23 msgid "The PIN must be a number" msgstr "Le code confidentiel doit être un nombre entier" -#: indico_vc_vidyo/forms.py:37 +#: indico_vc_vidyo/forms.py:28 msgid "Show PIN" msgstr "Afficher le code confidentiel" -#: indico_vc_vidyo/forms.py:39 +#: indico_vc_vidyo/forms.py:30 msgid "Show the VC Room PIN on the event page (insecure!)" msgstr "Afficher le code confidentiel de la salle Vidyo sur la page de l'événement (peu sûr!)" -#: indico_vc_vidyo/forms.py:40 +#: indico_vc_vidyo/forms.py:31 msgid "Show Auto-join URL" msgstr "Afficher l'URL de connexion" -#: indico_vc_vidyo/forms.py:42 +#: indico_vc_vidyo/forms.py:33 msgid "Show the auto-join URL on the event page" msgstr "Afficher l'URL de connexion sur la page de l'événement" -#: indico_vc_vidyo/forms.py:43 +#: indico_vc_vidyo/forms.py:34 msgid "Show Phone Access numbers" msgstr "Afficher les numéros d'accès téléphonique" -#: indico_vc_vidyo/forms.py:45 +#: indico_vc_vidyo/forms.py:36 msgid "Show a link to the list of phone access numbers" msgstr "Afficher un lien vers la liste des numéros d'accès téléphonique" -#: indico_vc_vidyo/forms.py:58 indico_vc_vidyo/templates/info_box.html:7 +#: indico_vc_vidyo/forms.py:49 indico_vc_vidyo/templates/info_box.html:7 #: indico_vc_vidyo/templates/manage_event_info_box.html:6 msgid "Description" msgstr "Description" -#: indico_vc_vidyo/forms.py:58 +#: indico_vc_vidyo/forms.py:49 msgid "The description of the room" msgstr "La description de la salle" -#: indico_vc_vidyo/forms.py:59 indico_vc_vidyo/templates/info_box.html:14 +#: indico_vc_vidyo/forms.py:50 indico_vc_vidyo/templates/info_box.html:14 #: indico_vc_vidyo/templates/manage_event_info_box.html:10 msgid "Owner" msgstr "Responsable" -#: indico_vc_vidyo/forms.py:59 +#: indico_vc_vidyo/forms.py:50 msgid "The owner of the room" msgstr "Le responsable de la salle" -#: indico_vc_vidyo/forms.py:60 +#: indico_vc_vidyo/forms.py:51 #: indico_vc_vidyo/templates/manage_event_info_box.html:39 msgid "Moderation PIN" msgstr "Code confidentiel de modération" -#: indico_vc_vidyo/forms.py:61 +#: indico_vc_vidyo/forms.py:52 msgid "Used to moderate the VC Room. Only digits allowed." msgstr "Utilisé pour modérer la salle de VC. Seuls les chiffres sont autorisés." -#: indico_vc_vidyo/forms.py:62 indico_vc_vidyo/templates/info_box.html:18 +#: indico_vc_vidyo/forms.py:53 indico_vc_vidyo/templates/info_box.html:18 #: indico_vc_vidyo/templates/manage_event_info_box.html:32 msgid "Room PIN" msgstr "Code confidentiel de la salle" -#: indico_vc_vidyo/forms.py:63 +#: indico_vc_vidyo/forms.py:54 msgid "" "Used to protect the access to the VC Room (leave blank for open access). " "Only digits allowed." msgstr "Utilisé pour protéger l'accès à la salle de VC (laisser vide pour un accès ouvert). Seuls les chiffres sont autorisés." -#: indico_vc_vidyo/forms.py:65 +#: indico_vc_vidyo/forms.py:56 msgid "Auto mute" msgstr "Coupure automatique des périphériques d'entrée" -#: indico_vc_vidyo/forms.py:66 -msgid "On" -msgstr "Activé" - -#: indico_vc_vidyo/forms.py:66 -msgid "Off" -msgstr "Désactivé" - -#: indico_vc_vidyo/forms.py:67 +#: indico_vc_vidyo/forms.py:58 msgid "" "The VidyoDesktop clients will join the VC room muted by default (audio and " "video)" msgstr "Les clients VidyoDesktop rejoindront la salle Vidyo avec le micro et la caméra coupés par défaut" -#: indico_vc_vidyo/forms.py:82 +#: indico_vc_vidyo/forms.py:73 msgid "Unable to find this user in Indico." msgstr "Impossible de trouver cet utilisateur dans Indico." -#: indico_vc_vidyo/forms.py:84 +#: indico_vc_vidyo/forms.py:75 msgid "This user does not have a suitable account to use Vidyo." msgstr "Cet utilisateur n'a pas de compte qui lui permet d'utiliser Vidyo." -#: indico_vc_vidyo/plugin.py:49 +#: indico_vc_vidyo/plugin.py:40 msgid "Vidyo email support" msgstr "Adresse électronique de l'assistance Vidyo" -#: indico_vc_vidyo/plugin.py:50 +#: indico_vc_vidyo/plugin.py:41 msgid "Username" msgstr "Identifiant" -#: indico_vc_vidyo/plugin.py:50 +#: indico_vc_vidyo/plugin.py:41 msgid "Indico username for Vidyo" msgstr "Identifiant Indico pour Vidyo" -#: indico_vc_vidyo/plugin.py:51 +#: indico_vc_vidyo/plugin.py:42 msgid "Password" msgstr "Mot de passe" -#: indico_vc_vidyo/plugin.py:52 +#: indico_vc_vidyo/plugin.py:43 msgid "Indico password for Vidyo" msgstr "Mot de passe utilisateur pour Vidyo" -#: indico_vc_vidyo/plugin.py:53 +#: indico_vc_vidyo/plugin.py:44 msgid "Admin API WSDL URL" msgstr "URL WSDL pour l'API admin" -#: indico_vc_vidyo/plugin.py:54 +#: indico_vc_vidyo/plugin.py:45 msgid "User API WSDL URL" msgstr "URL WSDL pour l'API utilisateur" -#: indico_vc_vidyo/plugin.py:55 +#: indico_vc_vidyo/plugin.py:46 msgid "Indico tenant prefix" msgstr "Préfixe de tenant pour Indico" -#: indico_vc_vidyo/plugin.py:56 +#: indico_vc_vidyo/plugin.py:47 msgid "The tenant prefix for Indico rooms created on this server" msgstr "Le préfixe de tenant pour les salles Vidyo créées sur ce serveur Indico" -#: indico_vc_vidyo/plugin.py:57 +#: indico_vc_vidyo/plugin.py:48 msgid "Public rooms' group name" msgstr "Nom du groupe Vidyo pour les salles Vidyo" -#: indico_vc_vidyo/plugin.py:58 +#: indico_vc_vidyo/plugin.py:49 msgid "Group name for public videoconference rooms created by Indico" msgstr "Nom du groupe pour les salles publiques de visioconférence créées par Indico" -#: indico_vc_vidyo/plugin.py:59 +#: indico_vc_vidyo/plugin.py:50 msgid "Authenticators" msgstr "Services d'authentification" -#: indico_vc_vidyo/plugin.py:60 +#: indico_vc_vidyo/plugin.py:51 msgid "Identity providers to convert Indico users to Vidyo accounts" msgstr "Fournisseurs d'identité pour convertir des utilisateurs Indico en comptes Vidyo" -#: indico_vc_vidyo/plugin.py:61 +#: indico_vc_vidyo/plugin.py:52 msgid "VC room age threshold" msgstr "Limite d'âge pour les salles Vidyo" -#: indico_vc_vidyo/plugin.py:62 +#: indico_vc_vidyo/plugin.py:53 msgid "" "Number of days after an Indico event when a videoconference room is " "considered old" msgstr "Nombre de jours à partir de la fin d'un événement dans Indico après lesquels une salle de visioconférence est considérée comme agée" -#: indico_vc_vidyo/plugin.py:64 +#: indico_vc_vidyo/plugin.py:55 msgid "Max. num. VC rooms before warning" msgstr "Nombre maximum de salles Vidyo avant un message d'alerte" -#: indico_vc_vidyo/plugin.py:65 +#: indico_vc_vidyo/plugin.py:56 msgid "Maximum number of rooms until a warning is sent to the managers" msgstr "Nombre maximum de salles Vidyo créées sur ce serveur avant qu'un message d'alerte soit envoyé aux administrateurs" -#: indico_vc_vidyo/plugin.py:66 +#: indico_vc_vidyo/plugin.py:57 msgid "VidyoVoice phone number" msgstr "Numéros de téléphone VidyoVoice" -#: indico_vc_vidyo/plugin.py:67 +#: indico_vc_vidyo/plugin.py:58 msgid "Link to the list of VidyoVoice phone numbers" msgstr "Lien vers la liste des numéros de téléphones VidyoVoice" -#: indico_vc_vidyo/plugin.py:68 +#: indico_vc_vidyo/plugin.py:59 msgid "Client Chooser URL" msgstr "URL de sélection du client" -#: indico_vc_vidyo/plugin.py:69 +#: indico_vc_vidyo/plugin.py:60 msgid "" "URL for client chooser interface. The room key will be passed as a 'url' GET" " query argument" msgstr "L'URL pour l'interface de sélection du client. Le code de la salle sera passé comme argument de requête GET." -#: indico_vc_vidyo/plugin.py:71 +#: indico_vc_vidyo/plugin.py:62 msgid "Creation email footer" msgstr "Pied de page du courriel de création" -#: indico_vc_vidyo/plugin.py:72 +#: indico_vc_vidyo/plugin.py:63 msgid "Footer to append to emails sent upon creation of a VC room" msgstr "Pied de page ajouté au courriel envoyé à la création d'une nouvelle salle Vidyo" -#: indico_vc_vidyo/plugin.py:162 indico_vc_vidyo/plugin.py:202 -#: indico_vc_vidyo/plugin.py:240 indico_vc_vidyo/plugin.py:269 +#: indico_vc_vidyo/plugin.py:153 indico_vc_vidyo/plugin.py:193 +#: indico_vc_vidyo/plugin.py:231 indico_vc_vidyo/plugin.py:260 msgid "No valid Vidyo account found for this user" msgstr "Pas de compte Vidyo valide pour cet utilisateur" -#: indico_vc_vidyo/plugin.py:198 indico_vc_vidyo/plugin.py:263 +#: indico_vc_vidyo/plugin.py:189 indico_vc_vidyo/plugin.py:254 msgid "Room name already in use" msgstr "Ce nom de salle est déjà utilisé" -#: indico_vc_vidyo/plugin.py:213 +#: indico_vc_vidyo/plugin.py:204 msgid "Could not find newly created room in Vidyo" msgstr "Impossible de trouver la nouvelle salle dans Vidyo" -#: indico_vc_vidyo/plugin.py:232 indico_vc_vidyo/plugin.py:259 -#: indico_vc_vidyo/plugin.py:288 +#: indico_vc_vidyo/plugin.py:223 indico_vc_vidyo/plugin.py:250 +#: indico_vc_vidyo/plugin.py:279 msgid "This room has been deleted from Vidyo" msgstr "Cette salle a été supprimée de Vidyo" diff --git a/vc_vidyo/indico_vc_vidyo/translations/messages.pot b/vc_vidyo/indico_vc_vidyo/translations/messages.pot index 785a5cf..323ba6b 100644 --- a/vc_vidyo/indico_vc_vidyo/translations/messages.pot +++ b/vc_vidyo/indico_vc_vidyo/translations/messages.pot @@ -1,14 +1,14 @@ # Translations template for PROJECT. -# Copyright (C) 2020 ORGANIZATION +# Copyright (C) 2021 ORGANIZATION # This file is distributed under the same license as the PROJECT project. -# FIRST AUTHOR , 2020. +# FIRST AUTHOR , 2021. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2020-08-19 20:40+0200\n" +"POT-Creation-Date: 2021-01-05 13:23+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Generated-By: Babel 2.8.0\n" #: indico_vc_vidyo/controllers.py:29 -msgid "You are now the owner of the room '{room.name}'" +msgid "You are now the owner of the room '{room}'" msgstr "" #: indico_vc_vidyo/forms.py:23 diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index 940f3c4..b099a5f 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -37,7 +37,7 @@ class RHRoomAlternativeHost(RHVCSystemEventBase): db.session.rollback() raise else: - flash(_("You are now an alternative host of room '{room.name}'".format(room=self.vc_room)), 'success') + flash(_("You are now an alternative host of room '{room}'").format(room=self.vc_room.name), 'success') return jsonify(success=True) diff --git a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po index 7d31507..65fdf03 100644 --- a/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po +++ b/vc_zoom/indico_vc_zoom/translations/fr_FR/LC_MESSAGES/messages.po @@ -5,15 +5,16 @@ # # Translators: # Thomas Baron , 2021 +# Adrian Mönnich, 2021 # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-01-05 10:58+0100\n" +"POT-Creation-Date: 2021-01-05 13:20+0100\n" "PO-Revision-Date: 2020-11-25 15:06+0000\n" -"Last-Translator: Thomas Baron , 2021\n" +"Last-Translator: Adrian Mönnich, 2021\n" "Language-Team: French (France) (https://www.transifex.com/indico/teams/6478/fr_FR/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -27,8 +28,8 @@ msgid "You were already an (alternative) host of this meeting" msgstr "Vous étiez déjà un hôte (alternatif) de cette réunion" #: indico_vc_zoom/controllers.py:40 -msgid "You are now an alternative host of room '{room.name}'" -msgstr "Vous êtes maintenant un hôte alternatif de la réunion '{room.name}'" +msgid "You are now an alternative host of room '{room}'" +msgstr "Vous êtes maintenant un hôte alternatif de la réunion '{room}'" #: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:63 msgid "Passcode visibility" diff --git a/vc_zoom/indico_vc_zoom/translations/messages.pot b/vc_zoom/indico_vc_zoom/translations/messages.pot index a546f44..2eff619 100644 --- a/vc_zoom/indico_vc_zoom/translations/messages.pot +++ b/vc_zoom/indico_vc_zoom/translations/messages.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2021-01-05 10:58+0100\n" +"POT-Creation-Date: 2021-01-05 13:20+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,7 +22,7 @@ msgid "You were already an (alternative) host of this meeting" msgstr "" #: indico_vc_zoom/controllers.py:40 -msgid "You are now an alternative host of room '{room.name}'" +msgid "You are now an alternative host of room '{room}'" msgstr "" #: indico_vc_zoom/forms.py:29 indico_vc_zoom/forms.py:63 From 5d86bc7f079b81ea430ac1e15a183868e8c658e3 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 13:43:25 +0100 Subject: [PATCH 92/94] VC/Zoom: Fix meeting type enum --- vc_zoom/indico_vc_zoom/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/util.py b/vc_zoom/indico_vc_zoom/util.py index 54b38d8..978d648 100644 --- a/vc_zoom/indico_vc_zoom/util.py +++ b/vc_zoom/indico_vc_zoom/util.py @@ -31,10 +31,11 @@ class ZoomMeetingType(int, IndicoEnum): instant_meeting = 1 scheduled_meeting = 2 recurring_meeting_no_time = 3 - recurring_meeting_fixed_time = 4 + recurring_meeting_fixed_time = 8 + pmi_meeting = 4 webinar = 5 recurring_webinar_no_time = 6 - recurring_meeting_fixed_time = 9 + recurring_webinar_fixed_time = 9 class UserLookupMode(unicode, RichEnum): From 99a3ef4df07d49ba4049ff0c1f4694adcb778898 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 14:27:31 +0100 Subject: [PATCH 93/94] VC/Zoom: Fix tests Incorrect alternative_hosts defeault value (that was apparently only used in tests, since it's always present when using the real Zoom API) --- vc_zoom/indico_vc_zoom/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 64fd148..2bd5eec 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -322,7 +322,7 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin): 'zoom_id': unicode(meeting_obj['id']), 'start_url': meeting_obj['start_url'], 'host': host.identifier, - 'alternative_hosts': process_alternative_hosts(meeting_obj['settings'].get('alternative_hosts', [])) + 'alternative_hosts': process_alternative_hosts(meeting_obj['settings'].get('alternative_hosts', '')) }) vc_room.data.update(get_url_data_args(meeting_obj['join_url'])) flag_modified(vc_room, 'data') From 172fcb1ae18923b6bc120969ca5924f586b16887 Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 5 Jan 2021 14:31:05 +0100 Subject: [PATCH 94/94] VC/Zoom: Run isort + flake8 --- vc_zoom/indico_vc_zoom/api/__init__.py | 2 +- vc_zoom/indico_vc_zoom/api/client.py | 2 +- vc_zoom/indico_vc_zoom/controllers.py | 6 +++--- vc_zoom/indico_vc_zoom/forms.py | 2 +- vc_zoom/indico_vc_zoom/notifications.py | 2 +- vc_zoom/indico_vc_zoom/plugin.py | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/vc_zoom/indico_vc_zoom/api/__init__.py b/vc_zoom/indico_vc_zoom/api/__init__.py index 28dc103..035dd7c 100644 --- a/vc_zoom/indico_vc_zoom/api/__init__.py +++ b/vc_zoom/indico_vc_zoom/api/__init__.py @@ -5,7 +5,7 @@ # them and/or modify them under the terms of the MIT License; # see the LICENSE file for more details. -from .client import ZoomIndicoClient, ZoomClient +from .client import ZoomClient, ZoomIndicoClient __all__ = ['ZoomIndicoClient', 'ZoomClient'] diff --git a/vc_zoom/indico_vc_zoom/api/client.py b/vc_zoom/indico_vc_zoom/api/client.py index 6b3da45..ad223c3 100644 --- a/vc_zoom/indico_vc_zoom/api/client.py +++ b/vc_zoom/indico_vc_zoom/api/client.py @@ -10,9 +10,9 @@ from __future__ import absolute_import, unicode_literals import time import jwt +from pytz import utc from requests import Session from requests.exceptions import HTTPError -from pytz import utc def format_iso_dt(d): diff --git a/vc_zoom/indico_vc_zoom/controllers.py b/vc_zoom/indico_vc_zoom/controllers.py index b099a5f..86fddce 100644 --- a/vc_zoom/indico_vc_zoom/controllers.py +++ b/vc_zoom/indico_vc_zoom/controllers.py @@ -12,21 +12,21 @@ from flask_pluginengine import current_plugin from sqlalchemy.orm.attributes import flag_modified from webargs import fields from webargs.flaskparser import use_kwargs +from werkzeug.exceptions import Forbidden from indico.core.db import db from indico.modules.vc.controllers import RHVCSystemEventBase from indico.modules.vc.exceptions import VCRoomError from indico.modules.vc.models.vc_rooms import VCRoom -from indico.web.rh import RH from indico.util.i18n import _ -from werkzeug.exceptions import Forbidden +from indico.web.rh import RH class RHRoomAlternativeHost(RHVCSystemEventBase): def _process(self): new_identifier = session.user.identifier if new_identifier == self.vc_room.data['host'] or new_identifier in self.vc_room.data['alternative_hosts']: - flash(_("You were already an (alternative) host of this meeting"), 'warning') + flash(_('You were already an (alternative) host of this meeting'), 'warning') return jsonify(success=False) self.vc_room.data['alternative_hosts'].append(new_identifier) diff --git a/vc_zoom/indico_vc_zoom/forms.py b/vc_zoom/indico_vc_zoom/forms.py index 0dd0f50..75a0289 100644 --- a/vc_zoom/indico_vc_zoom/forms.py +++ b/vc_zoom/indico_vc_zoom/forms.py @@ -6,9 +6,9 @@ # see the LICENSE file for more details. from __future__ import unicode_literals + from flask import session from flask_pluginengine import current_plugin - from wtforms.fields.core import BooleanField, StringField from wtforms.fields.simple import TextAreaField from wtforms.validators import DataRequired, ValidationError diff --git a/vc_zoom/indico_vc_zoom/notifications.py b/vc_zoom/indico_vc_zoom/notifications.py index 87a1b14..0e58d85 100644 --- a/vc_zoom/indico_vc_zoom/notifications.py +++ b/vc_zoom/indico_vc_zoom/notifications.py @@ -7,9 +7,9 @@ from __future__ import unicode_literals -from indico.web.flask.templating import get_template_module from indico.core.notifications import make_email, send_email from indico.util.user import principal_from_identifier +from indico.web.flask.templating import get_template_module def notify_host_start_url(vc_room): diff --git a/vc_zoom/indico_vc_zoom/plugin.py b/vc_zoom/indico_vc_zoom/plugin.py index 2bd5eec..b3f17d2 100644 --- a/vc_zoom/indico_vc_zoom/plugin.py +++ b/vc_zoom/indico_vc_zoom/plugin.py @@ -11,8 +11,8 @@ from flask import flash, session from markupsafe import escape from requests.exceptions import HTTPError from sqlalchemy.orm.attributes import flag_modified -from wtforms.fields.core import BooleanField from wtforms.fields import TextAreaField +from wtforms.fields.core import BooleanField from wtforms.fields.simple import StringField from wtforms.validators import DataRequired, ValidationError @@ -35,9 +35,9 @@ from indico_vc_zoom.blueprint import blueprint from indico_vc_zoom.cli import cli from indico_vc_zoom.forms import VCRoomAttachForm, VCRoomForm from indico_vc_zoom.notifications import notify_host_start_url -from indico_vc_zoom.util import (UserLookupMode, fetch_zoom_meeting, find_enterprise_email, gen_random_password, - get_alt_host_emails, get_schedule_args, get_url_data_args, process_alternative_hosts, - update_zoom_meeting, ZoomMeetingType) +from indico_vc_zoom.util import (UserLookupMode, ZoomMeetingType, fetch_zoom_meeting, find_enterprise_email, + gen_random_password, get_alt_host_emails, get_schedule_args, get_url_data_args, + process_alternative_hosts, update_zoom_meeting) class PluginSettingsForm(VCPluginSettingsFormBase):