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 %}