Remove vc_vidyo plugin

This commit is contained in:
Indico Team 2021-03-17 11:40:49 +01:00 committed by Adrian Moennich
parent ec757d9f98
commit a6625281d5
37 changed files with 0 additions and 1905 deletions

View File

@ -30,6 +30,5 @@ install_requires =
indico-plugin-previewer-jupyter>=3.0.dev0,<3.1.dev0
indico-plugin-storage-s3>=3.0.dev0,<3.1.dev0
indico-plugin-ursh>=3.0.dev0,<3.1.dev0
indico-plugin-vc-vidyo>=3.0.dev0,<3.1.dev0
indico-plugin-vc-zoom>=3.0.dev0,<3.1.dev0
# END GENERATED REQUIREMENTS

View File

@ -1,6 +0,0 @@
graft indico_vc_vidyo/static
graft indico_vc_vidyo/migrations
graft indico_vc_vidyo/templates
graft indico_vc_vidyo/translations
global-exclude *.pyc __pycache__ .keep

View File

@ -1,17 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from indico.core import signals
from indico.util.i18n import make_bound_gettext
_ = make_bound_gettext('vc_vidyo')
@signals.import_tasks.connect
def _import_tasks(sender, **kwargs):
import indico_vc_vidyo.task # noqa: F401

View File

@ -1,11 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from .client import AdminClient, APIException, RoomNotFoundAPIException, UserClient
__all__ = ['UserClient', 'AdminClient', 'APIException', 'RoomNotFoundAPIException']

View File

@ -1,27 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from zeep.cache import Base
from indico.core.cache import make_scoped_cache
DEFAULT_CACHE_TTL = 24 * 3600
class ZeepCache(Base):
_instance = None
def __init__(self, duration=DEFAULT_CACHE_TTL):
self._cache = make_scoped_cache('zeep')
self._duration = duration
def get(self, url):
self._cache.get(url)
def add(self, url, content):
self._cache.set(url, content, timeout=self._duration)

View File

@ -1,119 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from requests import Session
from requests.auth import HTTPBasicAuth
from zeep import Client
from zeep.exceptions import Fault
from zeep.transports import Transport
from indico_vc_vidyo.api.cache import ZeepCache
DEFAULT_CLIENT_TIMEOUT = 30
AUTOMUTE_API_PROFILE = "NoAudioAndVideo"
class APIException(Exception):
pass
class RoomNotFoundAPIException(APIException):
pass
def raises_api_error(wrapped):
def _wrapper(*args, **kwargs):
try:
return wrapped(*args, **kwargs)
except Fault as err:
err_msg = err.message
if err_msg.startswith('Room not found for roomID') or 'Invalid roomID' in err_msg:
raise RoomNotFoundAPIException()
else:
raise APIException(err_msg)
return _wrapper
class ClientBase:
def __init__(self, wsdl, settings):
session = Session()
transport = Transport(session=session, cache=ZeepCache())
session.auth = HTTPBasicAuth(settings.get('username'), settings.get('password'))
self.client = Client(wsdl, transport=transport)
self.factory = self.client.type_factory('ns0')
@property
def soap(self):
return self.client.service
class UserClient(ClientBase):
def __init__(self, settings):
super().__init__(settings.get('user_api_wsdl'), settings)
class AdminClient(ClientBase):
def __init__(self, settings):
super().__init__(settings.get('admin_api_wsdl'), settings)
def create_room_object(self, **kwargs):
return self.factory.Room(**kwargs)
@raises_api_error
def find_room(self, extension):
from indico_vc_vidyo.plugin import VidyoPlugin
filter_ = {
'query': extension,
'limit': 40,
'dir': 'DESC'
}
counter = 0
while True:
filter_['start'] = counter * filter_['limit']
response = self.soap.getRooms(filter_)
if not response.total:
return None
for room in response.room:
if int(room.extension) == int(extension):
VidyoPlugin.logger.debug('Room: %s has been found.', room)
return room
else:
VidyoPlugin.logger.debug('Dismissing room extension %s', room.extension)
counter += 1
@raises_api_error
def get_room(self, vidyo_id):
return self.soap.getRoom(roomID=vidyo_id)
@raises_api_error
def add_room(self, room_obj):
self.soap.addRoom(room=room_obj)
@raises_api_error
def update_room(self, room_id, room_obj):
self.soap.updateRoom(roomID=room_id, room=room_obj)
@raises_api_error
def delete_room(self, room_id):
self.soap.deleteRoom(roomID=room_id)
@raises_api_error
def get_automute(self, room_id):
answer = self.soap.getRoomProfile(roomID=room_id)
if answer:
return answer.roomProfileName == AUTOMUTE_API_PROFILE
else:
return False
@raises_api_error
def set_automute(self, room_id, status):
if status:
self.soap.setRoomProfile(roomID=room_id, roomProfileName=AUTOMUTE_API_PROFILE)
else:
self.soap.removeRoomProfile(roomID=room_id)

View File

@ -1,23 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from indico.core.plugins import IndicoPluginBlueprint
from indico_vc_vidyo.controllers import RHVidyoRoomOwner
blueprint = IndicoPluginBlueprint('vc_vidyo', 'indico_vc_vidyo')
# Room management
# using any(vidyo) instead of defaults since the event vc room locator
# includes the service and normalization skips values provided in 'defaults'
blueprint.add_url_rule(
'/event/<int:event_id>/manage/videoconference/<any(vidyo):service>/<int:event_vc_room_id>/room-owner',
'set_room_owner',
RHVidyoRoomOwner,
methods=('POST',)
)

View File

@ -1,38 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
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='vidyo')
def cli():
"""Manage the Vidyo plugin."""
@cli.command()
@click.option('--status', type=click.Choice(['deleted', 'created']))
def rooms(status=None):
"""Lists all Vidyo rooms"""
room_query = VCRoom.query.filter_by(type='vidyo')
table_data = [['ID', 'Name', 'Status', 'Vidyo ID', 'Extension']]
if status:
room_query = room_query.filter(VCRoom.status == VCRoomStatus.get(status))
for room in room_query:
table_data.append([str(room.id), room.name, room.status.name,
str(room.data['vidyo_id']), str(room.vidyo_extension.extension)])
table = AsciiTable(table_data)
for col in (0, 3, 4):
table.justify_columns[col] = 'right'
print(table.table)

View File

@ -1,34 +0,0 @@
// This file is part of the Indico plugins.
// 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;
// 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);
});
});
});

View File

@ -1,29 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
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 RHVidyoRoomOwner(RHVCSystemEventBase):
def _process(self):
result = {}
self.vc_room.vidyo_extension.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}'").format(room=self.vc_room.name), 'success')
result['success'] = True
return jsonify(result)

View File

@ -1,73 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from wtforms.fields.core import BooleanField
from wtforms.fields.simple import TextAreaField
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_vidyo import _
from indico_vc_vidyo.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 VidyoAdvancedFormMixin:
# Advanced options (per event)
show_pin = BooleanField(_('Show PIN'),
widget=SwitchWidget(),
description=_("Show the VC Room PIN on the event page (insecure!)"))
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, VidyoAdvancedFormMixin):
pass
class VCRoomForm(VCRoomFormBase, VidyoAdvancedFormMixin):
"""Contains all information concerning a Vidyo booking"""
advanced_fields = {'show_pin', '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'))
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.'))
auto_mute = BooleanField(_('Auto mute'),
widget=SwitchWidget(),
description=_('The VidyoDesktop clients will join the VC room muted by default '
'(audio and video)'))
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().__init__(*args, **kwargs)
@generated_data
def owner(self):
return 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 Vidyo."))

View File

@ -1,56 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
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'vidyo'
GUEST_ALLOWED = False
VALID_FORMATS = ('json',)
COMMIT = True
HTTP_POST = True
def _has_access(self, user):
from indico_vc_vidyo.plugin import VidyoPlugin
return user in VidyoPlugin.settings.acls.get('managers')
def _getParams(self):
super()._getParams()
self._room_ids = list(map(int, request.form.getlist('rid')))
def api_deletevcroom(self, user):
from indico_vc_vidyo.api import APIException
from indico_vc_vidyo.plugin import VidyoPlugin
success = []
failed = []
not_in_db = []
for rid in self._room_ids:
room = VCRoom.query.filter(VCRoom.type == 'vidyo',
VCRoom.status == VCRoomStatus.created,
VCRoom.data.contains({'vidyo_id': str(rid)})).first()
if not room:
not_in_db.append(rid)
continue
try:
room.plugin.delete_room(room, None)
except APIException:
failed.append(rid)
VidyoPlugin.logger.exception('Could not delete VC room %s', room)
else:
room.status = VCRoomStatus.deleted
success.append(rid)
VidyoPlugin.logger.info('%s deleted', room)
return {'success': success, 'failed': failed, 'missing': not_in_db}

View File

@ -1,34 +0,0 @@
"""Create tables
Revision ID: 6019621fea50
Revises:
Create Date: 2017-06-30 16:11:31.486845
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.sql.ddl import CreateSchema, DropSchema
# revision identifiers, used by Alembic.
revision = '6019621fea50'
down_revision = None
branch_labels = None
depends_on = None
def upgrade():
op.execute(CreateSchema('plugin_vc_vidyo'))
op.create_table('vidyo_extensions',
sa.Column('vc_room_id', sa.Integer(), nullable=False),
sa.Column('extension', sa.BigInteger(), nullable=True, index=True),
sa.Column('owned_by_id', sa.Integer(), nullable=False, index=True),
sa.ForeignKeyConstraint(['owned_by_id'], ['users.users.id']),
sa.ForeignKeyConstraint(['vc_room_id'], ['events.vc_rooms.id']),
sa.PrimaryKeyConstraint('vc_room_id'),
schema='plugin_vc_vidyo')
def downgrade():
op.drop_table('vidyo_extensions', schema='plugin_vc_vidyo')
op.execute(DropSchema('plugin_vc_vidyo'))

View File

@ -1,74 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from urllib.parse import urlencode
from sqlalchemy.event import listens_for
from sqlalchemy.orm.attributes import flag_modified
from indico.core.db.sqlalchemy import db
class VidyoExtension(db.Model):
__tablename__ = 'vidyo_extensions'
__table_args__ = {'schema': 'plugin_vc_vidyo'}
#: ID of the videoconference room
vc_room_id = db.Column(
db.Integer,
db.ForeignKey('events.vc_rooms.id'),
primary_key=True
)
extension = db.Column(
db.BigInteger,
index=True
)
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(
'vidyo_extension',
cascade='all, delete-orphan',
uselist=False,
lazy=False
)
)
#: The user who owns the Vidyo room
owned_by_user = db.relationship(
'User',
lazy=True,
backref=db.backref(
'vc_rooms_vidyo',
lazy='dynamic'
)
)
@property
def join_url(self):
from indico_vc_vidyo.plugin import VidyoPlugin
url = self.vc_room.data['url']
custom_url_tpl = VidyoPlugin.settings.get('client_chooser_url')
if custom_url_tpl:
return custom_url_tpl + '?' + urlencode({'url': url})
return url
def __repr__(self):
return f'<VidyoExtension({self.vc_room}, {self.extension}, {self.owned_by_user})>'
@listens_for(VidyoExtension.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')

View File

@ -1,330 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from flask import session
from sqlalchemy.orm.attributes import flag_modified
from wtforms.fields import IntegerField, TextAreaField
from wtforms.fields.html5 import EmailField, URLField
from wtforms.fields.simple import StringField
from wtforms.validators import DataRequired, NumberRange
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_vc_vidyo import _
from indico_vc_vidyo.api import AdminClient, APIException, RoomNotFoundAPIException
from indico_vc_vidyo.blueprint import blueprint
from indico_vc_vidyo.cli import cli
from indico_vc_vidyo.forms import VCRoomAttachForm, VCRoomForm
from indico_vc_vidyo.http_api import DeleteVCRoomAPI
from indico_vc_vidyo.models.vidyo_extensions import VidyoExtension
from indico_vc_vidyo.util import iter_extensions, iter_user_identities, retrieve_principal, update_room_from_obj
class PluginSettingsForm(VCPluginSettingsFormBase):
support_email = EmailField(_('Vidyo email support'))
username = StringField(_('Username'), [DataRequired()], description=_('Indico username for Vidyo'))
password = IndicoPasswordField(_('Password'), [DataRequired()], toggle=True,
description=_('Indico password for Vidyo'))
admin_api_wsdl = URLField(_('Admin API WSDL URL'), [DataRequired()])
user_api_wsdl = URLField(_('User API WSDL URL'), [DataRequired()])
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'))
authenticators = StringField(_('Authenticators'), [DataRequired()],
description=_('Identity providers to convert Indico users to Vidyo accounts'))
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'))
vidyo_phone_link = URLField(_('VidyoVoice phone number'),
description=_('Link to the list of VidyoVoice phone numbers'))
client_chooser_url = URLField(_('Client Chooser URL'),
description=_("URL for client chooser interface. The room key will be passed as a "
"'url' GET query argument"))
creation_email_footer = TextAreaField(_('Creation email footer'), widget=CKEditorWidget(),
description=_('Footer to append to emails sent upon creation of a VC room'))
class VidyoPlugin(VCPluginMixin, IndicoPlugin):
"""Vidyo
Videoconferencing with Vidyo
"""
configurable = True
settings_form = PluginSettingsForm
vc_room_form = VCRoomForm
vc_room_attach_form = VCRoomAttachForm
friendly_name = 'Vidyo'
def init(self):
super().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,
'username': 'indico',
'password': None,
'admin_api_wsdl': 'https://yourvidyoportal/services/v1_1/VidyoPortalAdminService?wsdl',
'user_api_wsdl': 'https://yourvidyoportal/services/v1_1/VidyoPortalUserService?wsdl',
'indico_room_prefix': 10,
'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 vidyo infrastructure.
'authenticators': ', '.join(p.name for p in multipass.identity_providers.values() if p.supports_get),
'num_days_old': 365,
'max_rooms_warning': 5000,
'vidyo_phone_link': None,
'creation_email_footer': None,
'client_chooser_url': None
})
@property
def logo_url(self):
return url_for_plugin(self.name + '.static', filename='images/logo.png')
@property
def icon_url(self):
return url_for_plugin(self.name + '.static', filename='images/vidyo_logo_notext.png')
def _extend_indico_cli(self, sender, **kwargs):
return cli
def update_data_association(self, event, vc_room, event_vc_room, data):
super().update_data_association(event, vc_room, event_vc_room, data)
event_vc_room.data.update({key: data.pop(key) for key in [
'show_pin',
'show_autojoin',
'show_phone_numbers'
]})
flag_modified(event_vc_room, 'data')
def update_data_vc_room(self, vc_room, data, is_new=False):
super().update_data_vc_room(vc_room, data, is_new=is_new)
for key in ['description', 'owner', 'room_pin', 'moderation_pin', 'auto_mute']:
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 Vidyo room for an event, given a VC room.
In order to create the Vidyo room, the function will try to do so with
all the available identities of the user based on the authenticators
defined in Vidyo plugin's settings, in that order.
:param vc_room: VCRoom -- The VC room from which to create the Vidyo
room
:param event: Event -- The event to the Vidyo room will be attached
"""
client = AdminClient(self.settings)
owner = retrieve_principal(vc_room.data['owner'])
login_gen = iter_user_identities(owner)
login = next(login_gen, None)
if login is None:
raise VCRoomError(_("No valid Vidyo account found for this user"), field='owner_user')
extension_gen = iter_extensions(self.settings.get('indico_room_prefix'), event.id)
extension = next(extension_gen)
while True:
room_mode = {
'isLocked': False,
'hasPIN': bool(vc_room.data['room_pin']),
'hasModeratorPIN': bool(vc_room.data['moderation_pin'])
}
if room_mode['hasPIN']:
room_mode['roomPIN'] = vc_room.data['room_pin']
if room_mode['hasModeratorPIN']:
room_mode['moderatorPIN'] = vc_room.data['moderation_pin']
room_obj = client.create_room_object(
name=vc_room.name,
RoomType='Public',
ownerName=login,
extension=extension,
groupName=self.settings.get('room_group_name'),
description=vc_room.data['description'],
RoomMode=room_mode)
if room_obj.RoomMode.hasPIN:
room_obj.RoomMode.roomPIN = vc_room.data['room_pin']
if room_obj.RoomMode.hasModeratorPIN:
room_obj.RoomMode.moderatorPIN = vc_room.data['moderation_pin']
try:
client.add_room(room_obj)
except APIException as err:
err_msg = err.message
if err_msg.startswith('Room exist for name'):
raise VCRoomError(_("Room name already in use"), field='name')
elif err_msg.startswith('Member not found for ownerName'):
login = next(login_gen, None)
if login is None:
raise VCRoomError(_("No valid Vidyo account found for this user"), field='owner_user')
elif err_msg.startswith('Room exist for extension'):
extension = next(extension_gen)
else:
raise
else:
# get room back, in order to fetch Vidyo-set parameters
created_room = client.find_room(extension)
if not created_room:
raise VCRoomNotFoundError(_("Could not find newly created room in Vidyo"))
vc_room.data.update({
'vidyo_id': str(created_room.roomID),
'url': created_room.RoomMode.roomURL,
'owner_identity': created_room.ownerName
})
flag_modified(vc_room, 'data')
vc_room.vidyo_extension = VidyoExtension(vc_room_id=vc_room.id, extension=int(created_room.extension),
owned_by_user=owner)
client.set_automute(created_room.roomID, vc_room.data['auto_mute'])
break
def update_room(self, vc_room, event):
client = AdminClient(self.settings)
try:
room_obj = self.get_room(vc_room)
except RoomNotFoundAPIException:
raise VCRoomNotFoundError(_("This room has been deleted from Vidyo"))
owner = retrieve_principal(vc_room.data['owner'])
changed_owner = room_obj.ownerName not in iter_user_identities(owner)
if changed_owner:
login_gen = iter_user_identities(owner)
login = next(login_gen, None)
if login is None:
raise VCRoomError(_("No valid Vidyo account found for this user"), field='owner_user')
room_obj.ownerName = login
room_obj.name = vc_room.name
room_obj.description = vc_room.data['description']
room_obj.RoomMode.hasPIN = bool(vc_room.data['room_pin'])
room_obj.RoomMode.hasModeratorPIN = bool(vc_room.data['moderation_pin'])
if room_obj.RoomMode.hasPIN:
room_obj.RoomMode.roomPIN = vc_room.data['room_pin']
if room_obj.RoomMode.hasModeratorPIN:
room_obj.RoomMode.moderatorPIN = vc_room.data['moderation_pin']
vidyo_id = vc_room.data['vidyo_id']
while True:
try:
client.update_room(vidyo_id, room_obj)
except RoomNotFoundAPIException:
raise VCRoomNotFoundError(_("This room has been deleted from Vidyo"))
except APIException as err:
err_msg = err.message
if err_msg.startswith('Room exist for name'):
raise VCRoomError(_("Room name already in use"), field='name')
elif err_msg.startswith('Member not found for ownerName'):
if changed_owner:
login = next(login_gen, None)
if not changed_owner or login is None:
raise VCRoomError(_("No valid Vidyo account found for this user"), field='owner_user')
room_obj.ownerName = login
else:
raise
else:
updated_room_obj = self.get_room(vc_room)
update_room_from_obj(self.settings, vc_room, updated_room_obj)
flag_modified(vc_room, 'data')
client.set_automute(vidyo_id, vc_room.data['auto_mute'])
break
def refresh_room(self, vc_room, event):
client = AdminClient(self.settings)
try:
room_obj = self.get_room(vc_room)
except RoomNotFoundAPIException:
raise VCRoomNotFoundError(_("This room has been deleted from Vidyo"))
update_room_from_obj(self.settings, vc_room, room_obj)
vc_room.data['auto_mute'] = client.get_automute(room_obj.roomID)
flag_modified(vc_room, 'data')
def delete_room(self, vc_room, event):
client = AdminClient(self.settings)
vidyo_id = vc_room.data['vidyo_id']
try:
client.delete_room(vidyo_id)
except RoomNotFoundAPIException:
pass
def get_room(self, vc_room):
client = AdminClient(self.settings)
return client.get_room(vc_room.data['vidyo_id'])
def get_blueprints(self):
return blueprint
def get_vc_room_form_defaults(self, event):
defaults = super().get_vc_room_form_defaults(event)
defaults.update({
'auto_mute': True,
'show_pin': False,
'show_autojoin': True,
'show_phone_numbers': True,
'owner_user': session.user
})
return defaults
def get_vc_room_attach_form_defaults(self, event):
defaults = super().get_vc_room_attach_form_defaults(event)
defaults.update({
'show_pin': False,
'show_autojoin': True,
'show_phone_numbers': True
})
return defaults
def can_manage_vc_room(self, user, room):
return user == room.vidyo_extension.owned_by_user or super().can_manage_vc_room(user, room)
def _merge_users(self, target, source, **kwargs):
super()._merge_users(target, source, **kwargs)
for ext in VidyoExtension.query.filter_by(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.vidyo_extension.owned_by_user.email}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -1,73 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
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.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.iterables import committing_iterator
from indico_vc_vidyo.api import APIException, RoomNotFoundAPIException
def find_old_vidyo_rooms(max_room_event_age):
"""Finds all Vidyo 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 == 'vidyo',
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.query.filter(VCRoom.status != VCRoomStatus.deleted, ~VCRoom.id.in_(recently_used)).all()
def notify_owner(plugin, vc_room):
"""Notifies about the deletion of a Vidyo room from the Vidyo server."""
user = vc_room.vidyo_extension.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_vidyo')
def vidyo_cleanup(dry_run=False):
from indico_vc_vidyo.plugin import VidyoPlugin
max_room_event_age = VidyoPlugin.settings.get('num_days_old')
VidyoPlugin.logger.info('Deleting Vidyo rooms that are not used or linked to events all older than %d days',
max_room_event_age)
candidate_rooms = find_old_vidyo_rooms(max_room_event_age)
VidyoPlugin.logger.info('%d rooms found', len(candidate_rooms))
if dry_run:
for vc_room in candidate_rooms:
VidyoPlugin.logger.info('Would delete Vidyo room %s from server', vc_room)
return
for vc_room in committing_iterator(candidate_rooms, n=20):
try:
VidyoPlugin.instance.delete_room(vc_room, None)
VidyoPlugin.logger.info('Room %s deleted from Vidyo server', vc_room)
notify_owner(VidyoPlugin.instance, vc_room)
vc_room.status = VCRoomStatus.deleted
except RoomNotFoundAPIException:
VidyoPlugin.logger.warning('Room %s had been already deleted from the Vidyo server', vc_room)
vc_room.status = VCRoomStatus.deleted
except APIException:
VidyoPlugin.logger.exception('Impossible to delete Vidyo room %s', vc_room)

View File

@ -1,21 +0,0 @@
{% macro render_make_me_owner(event, vc_room, event_vc_room, extra_classes='') %}
{% if session.user != vc_room.vidyo_extension.owned_by_user and event.can_manage(session.user) %}
<a class="i-button highlight arrow {{ extra_classes }}" data-toggle="dropdown"></a>
<ul class="i-dropdown" data-level="level1">
<li>
<a href="#"
title="{% trans name=vc_room.data.owner_identity %}You will be the owner of this Vidyo room, replacing {{name}}.{% endtrans %}"
class="action-make-owner" data-href="{{ url_for_plugin('vc_vidyo.set_room_owner', event_vc_room) }}">
{% trans %}Make me owner{% endtrans %}
</a>
</li>
</ul>
{% endif %}
{% endmacro %}
{% macro render_join_button(vc_room, extra_classes="") %}
<a class="i-button highlight {{ extra_classes }}"
href="{{ vc_room.vidyo_extension.join_url }}" target="_blank">
{% trans %}Join{% endtrans %}
</a>
{% endmacro %}

View File

@ -1,16 +0,0 @@
{% extends 'vc/emails/created.html' %}
{% block plugin_specific_info %}
<li>
<strong>Auto-join URL</strong>:
<a href="{{ vc_room.vidyo_extension.join_url }}">{{ vc_room.vidyo_extension.join_url }}</a>
</li>
<li><strong>Owner:</strong> {{ vc_room.data.owner_identity }}</li>
{% endblock %}
{% block custom_footer %}
{% if plugin.settings.get('creation_email_footer') %}
<hr>
{{ plugin.settings.get('creation_email_footer') | sanitize_html }}
{% endif %}
{% endblock %}

View File

@ -1 +0,0 @@
{% extends 'vc/emails/deleted.html' %}

View File

@ -1,16 +0,0 @@
{% extends 'emails/base.html' %}
{% block subject -%}
[{{ plugin.friendly_name }}] Room deleted from server: {{ vc_room.name }}
{%- endblock %}
{% block header -%}
<p>
The Vidyo room "{{ vc_room.name }}" has been deleted from the Vidyo server since it has not been used by any recent event.
</p>
<p>
You won't be able to attach it to any future events. If you need to do so, please create a new room.
</p>
{% block custom_footer %}{% endblock %}
{%- endblock %}

View File

@ -1,7 +0,0 @@
{% extends 'vc/event_buttons.html' %}
{% from 'vc_vidyo:buttons.html' import render_join_button, render_make_me_owner %}
{% block buttons %}
{{ render_join_button(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 %}

View File

@ -1,37 +0,0 @@
{% from '_clipboard_input.html' import clipboard_input %}
{% set owner = vc_room.vidyo_extension.owned_by_user %}
{% set phone_link = settings.get('vidyo_phone_link') %}
<dl>
<dt>{% trans %}Name{% endtrans %}</dt>
<dd>{{ vc_room.name }}</dd>
<dt>{% trans %}Description{% endtrans %}</dt>
<dd>{{ vc_room.data.description }}</dd>
{% if vc_room.vidyo_extension %}
<dt>{% trans %}Extension{% endtrans %}</dt>
<dd>{{ vc_room.vidyo_extension.extension }}</dd>
{% endif %}
{% if owner %}
<dt>{% trans %}Owner{% endtrans %}</dt>
<dd>{{ owner.full_name }}</dd>
{% endif %}
{% if event_vc_room.data.show_pin and vc_room.data.room_pin %}
<dt>{% trans %}Room PIN{% endtrans %}</dt>
<dd>{{ vc_room.data.room_pin }}</dd>
{% endif %}
{% if event_vc_room.data.show_autojoin %}
<dt class="large-row">{% trans %}Auto-join URL{% endtrans %}</dt>
<dd class="large-row">
{{ clipboard_input(vc_room.vidyo_extension.join_url, name="vc-room-url-%s"|format(event_vc_room.id)) }}
</dd>
{% endif %}
{% if event_vc_room.data.show_phone_numbers and phone_link %}
<dt>
{% trans %}Useful links{% endtrans %}
</dt>
<dd>
<a href="{{ phone_link }}" target="_blank">
{% trans %}Phone numbers{% endtrans %}
</a>
</dd>
{% endif %}
</dl>

View File

@ -1,55 +0,0 @@
{% from '_password.html' import password %}
{% from '_clipboard_input.html' import clipboard_input %}
{% set owner = vc_room.vidyo_extension.owned_by_user %}
{% set phone_link = settings.get('vidyo_phone_link') %}
<dl class="details-container">
<dt>{% trans %}Description{% endtrans %}</dt>
<dd>{{ vc_room.data.description }}</dd>
<dt>{% trans %}Extension{% endtrans %}</dt>
<dd>{{ vc_room.vidyo_extension.extension }}</dd>
<dt>{% trans %}Owner{% endtrans %}</dt>
<dd>
{% if owner %}
{{ owner.full_name }}
{% else %}
{{ vc_room.data.owner_account }} <em>(deleted)</em>
{% endif %}
</dd>
<dt>{% trans %}Linked to{% endtrans %}</dt>
<dd>
{% set obj = event_vc_room.link_object %}
{% if obj is none %}
<em>(missing {{ event_vc_room.link_type.name }})</em>
{% 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 %}
</dd>
{% if vc_room.data.room_pin %}
<dt>{% trans %}Room PIN{% endtrans %}</dt>
<dd>
{{ password('vc-room-pin-%s'|format(event_vc_room.id), value=vc_room.data.room_pin, toggle=True,
readonly=true) }}
</dd>
{% endif %}
{% if vc_room.data.moderation_pin %}
<dt>{% trans %}Moderation PIN{% endtrans %}</dt>
<dd>
{{ password('vc-moderation-pin-%s'|format(event_vc_room.id), value=vc_room.data.moderation_pin,
toggle=True, readonly=true) }}
</dd>
{% endif %}
<dt>{% trans %}Auto-join URL{% endtrans %}</dt>
<dd>
{{ clipboard_input(vc_room.vidyo_extension.join_url, name="vc-room-url") }}
</dd>
<dt>{% trans %}Created on{% endtrans %}</dt>
<dd>{{ vc_room.created_dt | format_datetime(timezone=event.tzinfo) }}</dd>
{% if vc_room.modified_dt %}
<dt>{% trans %}Modified on{% endtrans %}</dt>
<dd>{{ vc_room.modified_dt | format_datetime(timezone=event.tzinfo) }}</dd>
{% endif %}
</dl>

View File

@ -1,7 +0,0 @@
{% extends 'vc/management_buttons.html' %}
{% from 'vc_vidyo:buttons.html' import render_join_button, render_make_me_owner %}
{% block buttons %}
{{ render_join_button(vc_room, extra_classes="icon-play") }}
{{ render_make_me_owner(event_vc_room.event, vc_room, event_vc_room) }}
{% endblock %}

View File

@ -1,8 +0,0 @@
{% extends 'vc/vc_room_timetable_buttons.html' %}
{% from 'vc_vidyo: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, "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 %}

View File

@ -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 <thomas.baron@cern.ch>, 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 <thomas.baron@cern.ch>\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"

View File

@ -1,282 +0,0 @@
# Translations template for PROJECT.
# Copyright (C) 2021 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
# Adrian Mönnich, 2021
# Thomas Baron <thomas.baron@cern.ch>, 2015,2017
msgid ""
msgstr ""
"Project-Id-Version: Indico\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\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.8.0\n"
"Language: fr_FR\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
#: 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:23
msgid "The PIN must be a number"
msgstr "Le code confidentiel doit être un nombre entier"
#: indico_vc_vidyo/forms.py:28
msgid "Show PIN"
msgstr "Afficher le code confidentiel"
#: 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:31
msgid "Show Auto-join URL"
msgstr "Afficher l'URL de connexion"
#: 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:34
msgid "Show Phone Access numbers"
msgstr "Afficher les numéros d'accès téléphonique"
#: 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: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:49
msgid "The description of the room"
msgstr "La description de la salle"
#: 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:50
msgid "The owner of the room"
msgstr "Le responsable de la salle"
#: 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: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: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: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:56
msgid "Auto mute"
msgstr "Coupure automatique des périphériques d'entrée"
#: 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:73
msgid "Unable to find this user in Indico."
msgstr "Impossible de trouver cet utilisateur dans Indico."
#: 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:40
msgid "Vidyo email support"
msgstr "Adresse électronique de l'assistance Vidyo"
#: indico_vc_vidyo/plugin.py:41
msgid "Username"
msgstr "Identifiant"
#: indico_vc_vidyo/plugin.py:41
msgid "Indico username for Vidyo"
msgstr "Identifiant Indico pour Vidyo"
#: indico_vc_vidyo/plugin.py:42
msgid "Password"
msgstr "Mot de passe"
#: indico_vc_vidyo/plugin.py:43
msgid "Indico password for Vidyo"
msgstr "Mot de passe utilisateur pour Vidyo"
#: indico_vc_vidyo/plugin.py:44
msgid "Admin API WSDL URL"
msgstr "URL WSDL pour l'API admin"
#: indico_vc_vidyo/plugin.py:45
msgid "User API WSDL URL"
msgstr "URL WSDL pour l'API utilisateur"
#: indico_vc_vidyo/plugin.py:46
msgid "Indico tenant prefix"
msgstr "Préfixe de tenant pour Indico"
#: 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:48
msgid "Public rooms' group name"
msgstr "Nom du groupe Vidyo pour les salles Vidyo"
#: 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:50
msgid "Authenticators"
msgstr "Services d'authentification"
#: 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:52
msgid "VC room age threshold"
msgstr "Limite d'âge pour les salles Vidyo"
#: 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:55
msgid "Max. num. VC rooms before warning"
msgstr "Nombre maximum de salles Vidyo avant un message d'alerte"
#: 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:57
msgid "VidyoVoice phone number"
msgstr "Numéros de téléphone VidyoVoice"
#: 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:59
msgid "Client Chooser URL"
msgstr "URL de sélection du client"
#: 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:62
msgid "Creation email footer"
msgstr "Pied de page du courriel de création"
#: 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: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: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:204
msgid "Could not find newly created room in Vidyo"
msgstr "Impossible de trouver la nouvelle salle dans Vidyo"
#: 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"
#: indico_vc_vidyo/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_vidyo/templates/buttons.html:9
msgid "Make me owner"
msgstr "Nommez moi responsable"
#: indico_vc_vidyo/templates/buttons.html:19
msgid "Join"
msgstr "Rejoindre"
#: indico_vc_vidyo/templates/info_box.html:5
msgid "Name"
msgstr "Nom"
#: indico_vc_vidyo/templates/info_box.html:10
#: indico_vc_vidyo/templates/manage_event_info_box.html:8
msgid "Extension"
msgstr "Extension"
#: indico_vc_vidyo/templates/info_box.html:22
#: indico_vc_vidyo/templates/manage_event_info_box.html:45
msgid "Auto-join URL"
msgstr "URL pour connexion à la salle"
#: indico_vc_vidyo/templates/info_box.html:29
msgid "Useful links"
msgstr "Liens utiles"
#: indico_vc_vidyo/templates/info_box.html:33
msgid "Phone numbers"
msgstr "Numéros de téléphone"
#: indico_vc_vidyo/templates/manage_event_info_box.html:18
msgid "Linked to"
msgstr "attachée à"
#: indico_vc_vidyo/templates/manage_event_info_box.html:24
msgid "the whole event"
msgstr "l'événement entier"
#: indico_vc_vidyo/templates/manage_event_info_box.html:26
msgid "Contribution"
msgstr "La contribution"
#: indico_vc_vidyo/templates/manage_event_info_box.html:28
msgid "Session"
msgstr "La session"
#: indico_vc_vidyo/templates/manage_event_info_box.html:49
msgid "Created on"
msgstr "Créée le "
#: indico_vc_vidyo/templates/manage_event_info_box.html:52
msgid "Modified on"
msgstr "Modifiée le "

View File

@ -1,280 +0,0 @@
# Translations template for PROJECT.
# Copyright (C) 2021 ORGANIZATION
# This file is distributed under the same license as the PROJECT project.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2021.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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_vidyo/controllers.py:29
msgid "You are now the owner of the room '{room}'"
msgstr ""
#: indico_vc_vidyo/forms.py:23
msgid "The PIN must be a number"
msgstr ""
#: indico_vc_vidyo/forms.py:28
msgid "Show PIN"
msgstr ""
#: indico_vc_vidyo/forms.py:30
msgid "Show the VC Room PIN on the event page (insecure!)"
msgstr ""
#: indico_vc_vidyo/forms.py:31
msgid "Show Auto-join URL"
msgstr ""
#: indico_vc_vidyo/forms.py:33
msgid "Show the auto-join URL on the event page"
msgstr ""
#: indico_vc_vidyo/forms.py:34
msgid "Show Phone Access numbers"
msgstr ""
#: indico_vc_vidyo/forms.py:36
msgid "Show a link to the list of phone access numbers"
msgstr ""
#: 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 ""
#: indico_vc_vidyo/forms.py:49
msgid "The description of the room"
msgstr ""
#: 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 ""
#: indico_vc_vidyo/forms.py:50
msgid "The owner of the room"
msgstr ""
#: indico_vc_vidyo/forms.py:51
#: indico_vc_vidyo/templates/manage_event_info_box.html:39
msgid "Moderation PIN"
msgstr ""
#: indico_vc_vidyo/forms.py:52
msgid "Used to moderate the VC Room. Only digits allowed."
msgstr ""
#: 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 ""
#: 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 ""
#: indico_vc_vidyo/forms.py:56
msgid "Auto mute"
msgstr ""
#: indico_vc_vidyo/forms.py:58
msgid ""
"The VidyoDesktop clients will join the VC room muted by default (audio "
"and video)"
msgstr ""
#: indico_vc_vidyo/forms.py:73
msgid "Unable to find this user in Indico."
msgstr ""
#: indico_vc_vidyo/forms.py:75
msgid "This user does not have a suitable account to use Vidyo."
msgstr ""
#: indico_vc_vidyo/plugin.py:40
msgid "Vidyo email support"
msgstr ""
#: indico_vc_vidyo/plugin.py:41
msgid "Username"
msgstr ""
#: indico_vc_vidyo/plugin.py:41
msgid "Indico username for Vidyo"
msgstr ""
#: indico_vc_vidyo/plugin.py:42
msgid "Password"
msgstr ""
#: indico_vc_vidyo/plugin.py:43
msgid "Indico password for Vidyo"
msgstr ""
#: indico_vc_vidyo/plugin.py:44
msgid "Admin API WSDL URL"
msgstr ""
#: indico_vc_vidyo/plugin.py:45
msgid "User API WSDL URL"
msgstr ""
#: indico_vc_vidyo/plugin.py:46
msgid "Indico tenant prefix"
msgstr ""
#: indico_vc_vidyo/plugin.py:47
msgid "The tenant prefix for Indico rooms created on this server"
msgstr ""
#: indico_vc_vidyo/plugin.py:48
msgid "Public rooms' group name"
msgstr ""
#: indico_vc_vidyo/plugin.py:49
msgid "Group name for public videoconference rooms created by Indico"
msgstr ""
#: indico_vc_vidyo/plugin.py:50
msgid "Authenticators"
msgstr ""
#: indico_vc_vidyo/plugin.py:51
msgid "Identity providers to convert Indico users to Vidyo accounts"
msgstr ""
#: indico_vc_vidyo/plugin.py:52
msgid "VC room age threshold"
msgstr ""
#: indico_vc_vidyo/plugin.py:53
msgid ""
"Number of days after an Indico event when a videoconference room is "
"considered old"
msgstr ""
#: indico_vc_vidyo/plugin.py:55
msgid "Max. num. VC rooms before warning"
msgstr ""
#: indico_vc_vidyo/plugin.py:56
msgid "Maximum number of rooms until a warning is sent to the managers"
msgstr ""
#: indico_vc_vidyo/plugin.py:57
msgid "VidyoVoice phone number"
msgstr ""
#: indico_vc_vidyo/plugin.py:58
msgid "Link to the list of VidyoVoice phone numbers"
msgstr ""
#: indico_vc_vidyo/plugin.py:59
msgid "Client Chooser URL"
msgstr ""
#: 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 ""
#: indico_vc_vidyo/plugin.py:62
msgid "Creation email footer"
msgstr ""
#: indico_vc_vidyo/plugin.py:63
msgid "Footer to append to emails sent upon creation of a VC room"
msgstr ""
#: 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 ""
#: indico_vc_vidyo/plugin.py:189 indico_vc_vidyo/plugin.py:254
msgid "Room name already in use"
msgstr ""
#: indico_vc_vidyo/plugin.py:204
msgid "Could not find newly created room in Vidyo"
msgstr ""
#: 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 ""
#: indico_vc_vidyo/templates/buttons.html:7
#, python-format
msgid "You will be the owner of this Vidyo room, replacing %(name)s."
msgstr ""
#: indico_vc_vidyo/templates/buttons.html:9
msgid "Make me owner"
msgstr ""
#: indico_vc_vidyo/templates/buttons.html:19
msgid "Join"
msgstr ""
#: indico_vc_vidyo/templates/info_box.html:5
msgid "Name"
msgstr ""
#: indico_vc_vidyo/templates/info_box.html:10
#: indico_vc_vidyo/templates/manage_event_info_box.html:8
msgid "Extension"
msgstr ""
#: indico_vc_vidyo/templates/info_box.html:22
#: indico_vc_vidyo/templates/manage_event_info_box.html:45
msgid "Auto-join URL"
msgstr ""
#: indico_vc_vidyo/templates/info_box.html:29
msgid "Useful links"
msgstr ""
#: indico_vc_vidyo/templates/info_box.html:33
msgid "Phone numbers"
msgstr ""
#: indico_vc_vidyo/templates/manage_event_info_box.html:18
msgid "Linked to"
msgstr ""
#: indico_vc_vidyo/templates/manage_event_info_box.html:24
msgid "the whole event"
msgstr ""
#: indico_vc_vidyo/templates/manage_event_info_box.html:26
msgid "Contribution"
msgstr ""
#: indico_vc_vidyo/templates/manage_event_info_box.html:28
msgid "Session"
msgstr ""
#: indico_vc_vidyo/templates/manage_event_info_box.html:49
msgid "Created on"
msgstr ""
#: indico_vc_vidyo/templates/manage_event_info_box.html:52
msgid "Modified on"
msgstr ""

View File

@ -1,92 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
import re
from flask_multipass import IdentityRetrievalFailed
from indico.core.auth import multipass
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 Vidyo"""
from indico_vc_vidyo.plugin import VidyoPlugin
providers = authenticators_re.split(VidyoPlugin.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.query.filter(Identity.provider.in_(providers), Identity.identifier == identifier).all()
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.query.filter(~User.is_deleted, User.all_emails.in_(list(emails))).first()
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 = f'{prefix}{event_id}'
yield extension
suffix = 1
while True:
yield f'{extension}{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.vidyo_extension.owned_by_user = owner
vc_room.data.update({
'description': room_obj.description,
'vidyo_id': str(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.vidyo_extension.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(f'Unexpected type: {type_}')

View File

@ -1,31 +0,0 @@
[metadata]
name = indico-plugin-vc-vidyo
version = 3.0-dev
description = Vidyo video-conferencing plugin for Indico
url = https://github.com/indico/indico-plugins
license = MIT
author = Indico Team
author_email = indico-team@cern.ch
classifiers =
Environment :: Plugins
Environment :: Web Environment
License :: OSI Approved :: MIT License
Programming Language :: Python :: 3.9
[options]
packages = find:
zip_safe = false
include_package_data = true
python_requires = ~=3.9
install_requires =
indico>=3.0.dev0
zeep>=4.0.0,<5
[options.entry_points]
indico.plugins =
vc_vidyo = indico_vc_vidyo.plugin:VidyoPlugin
[pydocstyle]
ignore = D100,D101,D102,D103,D104,D105,D107,D203,D213

View File

@ -1,11 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from setuptools import setup
setup()

View File

@ -1,68 +0,0 @@
# This file is part of the Indico plugins.
# 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;
# see the LICENSE file for more details.
from datetime import datetime
import pytest
from pytz import utc
from indico.modules.vc.models.vc_rooms import VCRoom, VCRoomEventAssociation, VCRoomStatus
from indico_vc_vidyo.models.vidyo_extensions import VidyoExtension
@pytest.fixture
def create_dummy_room(db, dummy_user):
"""Returns a callable which lets you create dummy Vidyo room occurrences"""
def _create_room(name, extension, data, **kwargs):
vc_room = VCRoom(
name=name,
data=data,
type='vidyo',
status=kwargs.pop('status', VCRoomStatus.created),
created_by_user=dummy_user,
**kwargs
)
db.session.add(vc_room)
db.session.flush()
extension = VidyoExtension(
vc_room_id=vc_room.id,
extension=extension,
owned_by_user=dummy_user
)
vc_room.vidyo_extension = extension
return vc_room
return _create_room
def test_room_cleanup(create_event, create_dummy_room, freeze_time, db):
"""Test that 'old' Vidyo rooms are correctly detected"""
freeze_time(datetime(2015, 2, 1))
events = {}
for id_, (evt_name, end_date) in enumerate((('Event one', datetime(2012, 1, 1, tzinfo=utc)),
('Event two', datetime(2013, 1, 1, tzinfo=utc)),
('Event three', datetime(2014, 1, 1, tzinfo=utc)),
('Event four', datetime(2015, 1, 1, tzinfo=utc))), start=1):
events[id_] = create_event(id_, title=evt_name, end_dt=end_date, start_dt=end_date)
for id_, (vidyo_id, extension, evt_ids) in enumerate(((1234, 5678, (1, 2, 3, 4)),
(1235, 5679, (1, 2)),
(1235, 5679, (2,)),
(1236, 5670, (4,)),
(1237, 5671, ())), start=1):
room = create_dummy_room(f'test_room_{id_}', extension, {
'vidyo_id': vidyo_id
})
for evt_id in evt_ids:
VCRoomEventAssociation(vc_room=room, linked_event=events[evt_id], data={})
db.session.flush()
from indico_vc_vidyo.task import find_old_vidyo_rooms
assert {r.id for r in find_old_vidyo_rooms(180)} == {2, 3, 5}

View File

@ -1,5 +0,0 @@
{
"entry": {
"main": "./index.js"
}
}