class AVRequestManagerForm(RequestManagerForm):
    custom_webcast_url = URLField(
        _('Webcast URL'),
        description=_(
            "Custom URL to view the webcast. Can contain {event_id} which will be "
            "replaced with the ID of this event."))
    webcast_hidden = BooleanField(
        _('Hide webcast'),
        description=_('Do not show a link to the webcast on the event page'))
Exemple #2
0
 def _extend_top_menu(self, sender, **kwargs):
     if not session.user or not is_av_manager(session.user):
         return
     return TopMenuItem('services-cern-audiovisual',
                        _('Webcast/Recording'),
                        url_for_plugin('audiovisual.request_list'),
                        section='services')
 def _update_audiences(self):
     audiences = [
         ('', _("No restriction - everyone can watch the public webcast"))
     ]
     audiences += sorted(
         (x['audience'], x['audience'])
         for x in current_plugin.settings.get('webcast_audiences'))
     self.webcast_audience.choices = audiences
class TalkPlaceholder(Placeholder):
    name = 'talk_title'
    required = True
    description = _("The title of the user's talk")

    @classmethod
    def render(cls, definition, agreement):
        return _talk_info_from_agreement_data(agreement.event, agreement.data)[2]
class AVRequestForm(RequestFormBase):
    services = IndicoSelectMultipleCheckboxField(_('Services'), [DataRequired()], choices=SERVICES.items(),
                                                 widget=JinjaWidget('service_type_widget.html', 'audiovisual'),
                                                 description=_("Please choose whether you want a webcast, recording or "
                                                               "both."))
    all_contributions = BooleanField(_('All contributions'),
                                     description=_('Uncheck this if you want to select only certain contributions.'))
    contributions = IndicoSelectMultipleCheckboxField(_('Contributions'),
                                                      [UsedIf(lambda form, field: not form.all_contributions.data),
                                                       DataRequired()],
                                                      widget=JinjaWidget('contribution_list_widget.html',
                                                                         'audiovisual',
                                                                         SubContribution=SubContribution))
    webcast_audience = SelectField(_('Webcast Audience'),
                                   description=_("Select the audience to which the webcast will be restricted"))
    comments = TextAreaField(_('Comments'),
                             description=_('If you have any additional comments or instructions, please write them '
                                           'down here.'))

    def __init__(self, *args, **kwargs):
        super(AVRequestForm, self).__init__(*args, **kwargs)
        self._update_audiences()
        self._update_contribution_fields()

    def _update_audiences(self):
        audiences = [('', _("No restriction - everyone can watch the public webcast"))]
        audiences += sorted((x['audience'], x['audience']) for x in current_plugin.settings.get('webcast_audiences'))
        self.webcast_audience.choices = audiences

    def _update_contribution_fields(self):
        if self.event.type == 'lecture':
            # lectures don't have contributions
            del self.all_contributions
            del self.contributions
        else:
            choices = self.contributions.choices = []
            disabled_contribs = self.contributions._disabled_contributions = []
            contributions = self.contributions._contributions = {}
            is_manager = is_av_manager(session.user)
            selected = set(self.request.data.get('contributions', [])) if self.request else set()
            for contrib, capable, custom_room in get_contributions(self.event):
                is_subcontrib = isinstance(contrib, SubContribution)
                id_ = contribution_id(contrib)
                contributions[id_] = contrib
                line = Markup(render_template('audiovisual:contribution_list_entry.html', contrib=contrib,
                                              is_subcontrib=is_subcontrib, capable=capable, custom_room=custom_room))
                if not capable and not is_manager and contrib.id not in selected:
                    disabled_contribs.append((contrib, line))
                else:
                    choices.append((id_, line))
def _talk_info_from_agreement_data(event, data):
    if data['type'] == 'lecture_speaker':
        return 'lecture', event.url, event.title
    elif data['type'] != 'contribution':
        raise ValueError('Unexpected data type: {}'.format(data['type']))

    obj = contribution_by_id(event, data['contribution'])
    if not obj:
        raise RuntimeError(_('Contribution deleted'))
    if isinstance(obj, SubContribution):
        return 'subcontribution', url_for('contributions.display_subcontribution', obj), obj.title
    else:
        return 'contribution', url_for('contributions.display_contribution', obj), obj.title
Exemple #7
0
 def _get_breadcrumbs(self):
     return render_breadcrumbs(_('Webcast/Recording'))
Exemple #8
0
class PluginSettingsForm(IndicoForm):
    managers = PrincipalListField(
        _('Managers'),
        groups=True,
        description=_(
            'List of users who can manage recording/webcast requests.'))
    notification_emails = EmailListField(
        _('Notification email addresses'),
        description=_(
            'Notifications about recording/webcast requests are sent to '
            'these email addresses (one per line).'))
    webcast_audiences = MultipleItemsField(
        _('Webcast Audiences'),
        fields=[{
            'id': 'audience',
            'caption': _('Audience'),
            'required': True
        }],
        unique_field='audience',
        description=_('List of audiences for non-public webcasts.'))
    webcast_ping_url = URLField(
        _('Webcast Ping URL'),
        description=_(
            "A ping is sent via HTTP GET to this URL whenever a webcast request "
            "enters/leaves the 'accepted' state."))
    webcast_url = URLField(
        _('Webcast URL'), [DataRequired()],
        description=_(
            "The URL to watch the webcast for an event. Can contain {event_id} which "
            "will be replaced with the ID of the event."))
    agreement_paper_url = URLField(
        _('Agreement Paper URL'),
        description=_(
            "The URL to the agreement that can be printed and signed offline.")
    )
    recording_cds_url = URLField(
        _('CDS URL'),
        description=_(
            "The URL used when creating recording links. Must contain the {cds_id} "
            "placeholder."))

    def validate_recording_cds_url(self, field):
        if field.data and '{cds_id}' not in field.data:
            raise ValidationError('{cds_id} placeholder is missing')
class RequestListFilterForm(IndicoForm):
    direction = SelectField(_('Sort direction'), [DataRequired()],
                            choices=[('asc', _('Ascending')),
                                     ('desc', _('Descending'))])
    granularity = SelectField(_('Granularity'), [DataRequired()],
                              choices=[('events', _('Events')),
                                       ('talks', _('Talks'))])
    state = IndicoEnumSelectField(_('Request state'),
                                  enum=RequestState,
                                  skip={RequestState.withdrawn},
                                  none=_('Any state'))
    abs_start_date = IndicoDateField(
        _('Start Date'), [Optional(), Exclusive('rel_start_date')])
    abs_end_date = IndicoDateField(
        _('End Date'), [Optional(), Exclusive('rel_end_date')])
    rel_start_date = IntegerField(
        _('Days in the past'),
        [Optional(),
         Exclusive('abs_start_date'),
         NumberRange(min=0)])
    rel_end_date = IntegerField(
        _('Days in the future'),
        [Optional(), Exclusive('abs_end_date'),
         NumberRange(min=0)])

    @generated_data
    def start_date(self):
        if self.abs_start_date.data is None and self.rel_start_date.data is None:
            return None
        return self.abs_start_date.data or (
            date.today() - timedelta(days=self.rel_start_date.data))

    @generated_data
    def end_date(self):
        if self.abs_end_date.data is None and self.rel_end_date.data is None:
            return None
        return self.abs_end_date.data or (
            date.today() + timedelta(days=self.rel_end_date.data))
Exemple #10
0
 def _get_breadcrumbs(self):
     return render_breadcrumbs(_('Videoconference assistance'))
class AVRequest(RequestDefinitionBase):
    name = 'webcast-recording'
    title = _('Webcast / Recording')
    form = AVRequestForm
    manager_form = AVRequestManagerForm
    form_defaults = {'all_contributions': True}
    # needed for templates where we only have access to the definition
    util = {
        'count_capable_contributions': count_capable_contributions,
        'get_av_capable_rooms': get_av_capable_rooms,
        'event_has_empty_sessions': event_has_empty_sessions,
        'get_selected_contributions': get_selected_contributions,
        'get_selected_services': get_selected_services,
        'all_agreements_signed': all_agreements_signed
    }

    @classmethod
    def can_be_managed(cls, user):
        return is_av_manager(user)

    @classmethod
    def get_manager_notification_emails(cls):
        return set(current_plugin.settings.get('notification_emails'))

    @classmethod
    def get_notification_reply_email(cls):
        return (current_plugin.settings.get('notification_reply_email')
                or super(AVRequest, cls).get_notification_reply_email())

    @classmethod
    def get_notification_template(cls, name, **context):
        context['SubContribution'] = SubContribution
        return super(AVRequest, cls).get_notification_template(name, **context)

    @classmethod
    def render_form(cls, event, **kwargs):
        kwargs['default_webcast_url'] = cls.plugin.settings.get('webcast_url')
        return super(AVRequest, cls).render_form(event, **kwargs)

    @classmethod
    def create_manager_form(cls, req):
        form = super(AVRequest, cls).create_manager_form(req)
        if 'webcast' not in req.data['services']:
            del form.custom_webcast_url
            del form.webcast_hidden
        return form

    @classmethod
    def send(cls, req, data):
        if (req.id is not None and req.state == RequestState.accepted
                and ('webcast' in req.data['services']) !=
            ('webcast' in data['services'])):
            send_webcast_ping.delay()
        super(AVRequest, cls).send(req, data)
        req.data['identifiers'] = get_data_identifiers(req)
        flag_modified(req, 'data')

    @classmethod
    def withdraw(cls, req, notify_event_managers=True):
        if req.state == RequestState.accepted and 'webcast' in req.data[
                'services']:
            send_webcast_ping.delay()
        super(AVRequest, cls).withdraw(req, notify_event_managers)

    @classmethod
    def accept(cls, req, data, user):
        if 'webcast' in req.data['services']:
            send_webcast_ping.delay()
        super(AVRequest, cls).accept(req, data, user)

    @classmethod
    def reject(cls, req, data, user):
        if req.state == RequestState.accepted and 'webcast' in req.data[
                'services']:
            send_webcast_ping.delay()
        super(AVRequest, cls).reject(req, data, user)

    @classmethod
    def manager_save(cls, req, data):
        super(AVRequest, cls).manager_save(req, data)
        req.data['custom_webcast_url'] = data.get('custom_webcast_url')
        req.data['webcast_hidden'] = data.get('webcast_hidden', False)
        flag_modified(req, 'data')
class SpeakerReleaseAgreement(AgreementDefinitionBase):
    name = 'cern-speaker-release'
    title = _('Speaker Release')
    description = _(
        'For talks to be recorded, all involved speakers need to sign the speaker release form.'
    )
    form_template_name = 'agreement_form.html'
    disabled_reason = _(
        'There are no agreements to sign. This means that either no recording request has been '
        'done/accepted or there are no speakers assigned to the contributions in question.'
    )

    @classmethod
    def can_access_api(cls, user, event):
        return super(SpeakerReleaseAgreement, cls).can_access_api(
            user, event) or is_av_manager(user)

    @classmethod
    def extend_api_data(cls, event, person, agreement, data):
        data['speaker'] = {
            'id': person.data['id'],
            'person_id': person.data['person_id'],
            'name': person.name,
            'email': person.email
        }
        if person.data['type'] == 'lecture_speaker':
            data['contrib'] = unicode(event.id)
        elif person.data['type'] == 'contribution':
            data['contrib'] = person.data['contribution']

    @classproperty
    @classmethod
    @memoize_request
    def paper_form_url(cls):
        return cls.plugin.settings.get('agreement_paper_url')

    @classmethod
    def render_form(cls, agreement, form, **kwargs):
        event = agreement.event
        contrib = None
        is_subcontrib = False
        if agreement.data['type'] == 'contribution':
            talk_type = 'contribution'
            contrib = contribution_by_id(event, agreement.data['contribution'])
            if not contrib:
                raise NotFound
            is_subcontrib = isinstance(contrib, SubContribution)
        elif agreement.data['type'] == 'lecture_speaker':
            talk_type = 'lecture'
        else:
            raise ValueError('Unexpected type: {}'.format(
                agreement.data['type']))
        kwargs.update({
            'contrib': contrib,
            'is_subcontrib': is_subcontrib,
            'talk_type': talk_type,
            'event': event
        })
        return super(SpeakerReleaseAgreement,
                     cls).render_form(agreement, form, **kwargs)

    @classmethod
    def render_data(cls, event, data):
        try:
            type_, url, title = _talk_info_from_agreement_data(event, data)
        except RuntimeError as e:
            return ['({})'.format(e)]
        return [Markup('<a href="{}">{}</a>'.format(url, escape(title)))]

    @classmethod
    def iter_people(cls, event):
        req = Request.find_latest_for_event(event, AVRequest.name)
        if not req or req.state != RequestState.accepted or 'recording' not in req.data[
                'services']:
            return
        if event.type == 'lecture':
            for link in event.person_links:
                yield SpeakerPersonInfo(link.full_name,
                                        link.email or None,
                                        data={
                                            'type': 'lecture_speaker',
                                            'id': link.id,
                                            'person_id': link.person_id
                                        })
        else:
            contribs = [x[0] for x in get_selected_contributions(req)]
            for contrib in contribs:
                for link in contrib.person_links:
                    if not link.is_speaker:
                        continue
                    yield SpeakerPersonInfo(link.full_name,
                                            link.email or None,
                                            data={
                                                'type':
                                                'contribution',
                                                'contribution':
                                                contribution_id(contrib),
                                                'id':
                                                link.id,
                                                'person_id':
                                                link.person_id
                                            })
Exemple #13
0
class AVRequestManagerForm(RequestManagerForm):
    custom_webcast_url = URLField(_('Webcast URL'),
                                  description=_("Custom URL to view the webcast. Can contain {event_id} which will be "
                                                "replaced with the ID of this event."))
class PluginSettingsForm(IndicoForm):
    managers = PrincipalListField(_('Managers'), groups=True,
                                  description=_('List of users who can manage recording/webcast requests.'))
    notification_emails = EmailListField(_('Notification email addresses'),
                                         description=_('Notifications about recording/webcast requests are sent to '
                                                       'these email addresses (one per line).'))
    notification_reply_email = StringField(_('E-mail notification "reply" address'),
                                           [IndicoEmail()],
                                           description=_('Notifications that are sent to event managers will use '
                                                         'this address in their "Reply-To:" fields.'))
    webcast_audiences = MultipleItemsField(_('Webcast Audiences'),
                                           fields=[{'id': 'audience', 'caption': _('Audience'), 'required': True}],
                                           unique_field='audience',
                                           description=_('List of audiences for non-public webcasts.'))
    webcast_ping_url = URLField(_('Webcast Ping URL'),
                                description=_("A ping is sent via HTTP GET to this URL whenever a webcast request "
                                              "enters/leaves the 'accepted' state."))
    webcast_url = URLField(_('Webcast URL'), [DataRequired()],
                           description=_("The URL to watch the webcast for an event. Can contain {event_id} which "
                                         "will be replaced with the ID of the event."))
    agreement_paper_url = URLField(_('Agreement Paper URL'),
                                   description=_("The URL to the agreement that can be printed and signed offline."))
    recording_cds_url = URLField(_('CDS URL'),
                                 description=_("The URL used when creating recording links. Must contain the {cds_id} "
                                               "placeholder."))
    room_feature = QuerySelectField(_("Room feature"), [DataRequired()], allow_blank=True,
                                    query_factory=lambda: RoomFeature.query, get_label='title',
                                    description=_("The feature indicating that a room supports webcast/recording."))

    def validate_recording_cds_url(self, field):
        if field.data and '{cds_id}' not in field.data:
            raise ValidationError('{cds_id} placeholder is missing')