コード例 #1
0
def flash_if_unregistered(event, get_person_links):
    """Flash message when adding users with no fossir account

    :param event: Current event
    :param get_person_links: Callable returning list of person links to
                             check
    """
    old_non_users = {pl for pl in get_person_links() if pl.person.user is None}
    yield
    new_non_users = {pl for pl in get_person_links() if pl.person.user is None}
    added_non_users = len(new_non_users - old_non_users)
    if not added_non_users:
        return
    warning = ngettext('You have added a user with no fossir account.',
                       'You have added {} users with no fossir account.',
                       added_non_users).format(added_non_users)
    msg = _(
        'An fossir account may be needed to upload materials and/or manage contents.'
    )
    if event.can_manage(session.user):
        continue_msg = (escape(
            _('To invite them, please go to the {link_start}Roles page{link_end}'
              )).format(link_start=Markup('<a href="{}">').format(
                  url_for('persons.person_list', event)),
                        link_end=Markup('</a>')))
    else:
        continue_msg = ngettext(
            'Please contact the manager if you think this user should be able to access these '
            'features.',
            'Please contact the manager if you think these users should be able to access '
            'these features.', added_non_users)
    flash(Markup(' ').join([warning, msg, continue_msg]), 'warning')
コード例 #2
0
 def _process(self):
     tpl = get_template_module(
         'events/registration/emails/invitation_default.html',
         event=self.event)
     form_cls = InvitationFormExisting if request.args.get(
         'existing') == '1' else InvitationFormNew
     defaults = FormDefaults(email_body=tpl.get_html_body(),
                             email_subject=tpl.get_subject())
     form = form_cls(obj=defaults, regform=self.regform)
     skip_moderation = form.skip_moderation.data if 'skip_moderation' in form else False
     if form.validate_on_submit():
         for user in form.users.data:
             self._create_invitation(user, skip_moderation,
                                     form.email_from.data,
                                     form.email_subject.data,
                                     form.email_body.data)
         num = len(form.users.data)
         flash(
             ngettext("The invitation has been sent.",
                      "{n} invitations have been sent.", num).format(n=num),
             'success')
         return jsonify_data(
             invitation_list=_render_invitation_list(self.regform))
     return jsonify_template(
         'events/registration/management/regform_invite.html',
         regform=self.regform,
         form=form)
コード例 #3
0
    def _process(self):
        cfp = self.event.cfp
        form_data = {
            'managers': cfp.managers,
            'judges': cfp.judges,
            'content_reviewers': cfp.content_reviewers,
            'layout_reviewers': cfp.layout_reviewers
        }

        form = PaperTeamsForm(event=self.event, **form_data)
        if form.validate_on_submit():
            teams = {
                'managers': form.managers.data,
                'judges': form.judges.data
            }
            if cfp.content_reviewing_enabled:
                teams['content_reviewers'] = form.content_reviewers.data
            if cfp.layout_reviewing_enabled:
                teams['layout_reviewers'] = form.layout_reviewers.data
            unassigned_contribs = update_team_members(self.event, **teams)
            flash(_("The members of the teams were updated successfully"),
                  'success')
            if unassigned_contribs:
                flash(
                    ngettext("Users have been removed from 1 contribution",
                             "Users have been removed from {} contributions",
                             len(unassigned_contribs)).format(
                                 len(unassigned_contribs)), 'warning')
            return jsonify_data()
        return jsonify_template('events/papers/management/teams.html',
                                form=form)
コード例 #4
0
def _associate_registrations(user, **kwargs):
    from fossir.modules.events.registration.models.registrations import Registration
    reg_alias = db.aliased(Registration)
    subquery = db.session.query(reg_alias).filter(
        reg_alias.user_id == user.id,
        reg_alias.registration_form_id == Registration.registration_form_id,
        ~reg_alias.is_deleted)
    registrations = (
        Registration.find(
            Registration.user_id == None,  # noqa
            Registration.email.in_(user.all_emails),
            ~subquery.exists(),
            ~Registration.is_deleted).order_by(
                Registration.submitted_dt.desc()).all())
    if not registrations:
        return
    done = set()
    for registration in registrations:
        if registration.registration_form_id in done:
            continue
        logger.info('Associating %s with %s', registration, user)
        registration.user = user
        done.add(registration.registration_form_id)
    db.session.flush()
    num = len(done)
    flash(
        ngettext("A registration has been linked to your account.",
                 "{n} registrations have been linked to your account.",
                 num).format(n=num), 'info')
コード例 #5
0
def _convert_email_principals(user, **kwargs):
    from fossir.modules.events.sessions.models.principals import SessionPrincipal
    sessions = SessionPrincipal.replace_email_with_user(user, 'session')
    if sessions:
        num = len(sessions)
        flash(ngettext("You have been granted manager/coordination privileges for a session.",
                       "You have been granted manager/coordination privileges for {} sessions.", num).format(num),
              'info')
コード例 #6
0
 def _process(self):
     for contrib in self.contribs:
         delete_contribution(contrib)
     deleted_count = len(self.contribs)
     flash(
         ngettext("The contribution has been deleted.",
                  "{count} contributions have been deleted.",
                  deleted_count).format(count=deleted_count), 'success')
     return jsonify_data(**self.list_generator.render_list())
コード例 #7
0
def format_human_timedelta(delta, granularity='seconds', narrow=False):
    """Formats a timedelta in a human-readable way

    :param delta: the timedelta to format
    :param granularity: the granularity, i.e. the lowest unit that is
                        still displayed. when set e.g. to 'minutes',
                        the output will never contain seconds unless
                        the whole timedelta spans less than a minute.
                        Accepted values are 'seconds', 'minutes',
                        'hours' and 'days'.
    :param narrow: if true, only the short unit names will be used
    """
    field_order = ('days', 'hours', 'minutes', 'seconds')
    long_names = {
        'seconds':
        lambda n: ngettext(u'{0} second', u'{0} seconds', n).format(n),
        'minutes':
        lambda n: ngettext(u'{0} minute', u'{0} minutes', n).format(n),
        'hours': lambda n: ngettext(u'{0} hour', u'{0} hours', n).format(n),
        'days': lambda n: ngettext(u'{0} day', u'{0} days', n).format(n),
    }
    short_names = {
        'seconds': lambda n: ngettext(u'{0}s', u'{0}s', n).format(n),
        'minutes': lambda n: ngettext(u'{0}m', u'{0}m', n).format(n),
        'hours': lambda n: ngettext(u'{0}h', u'{0}h', n).format(n),
        'days': lambda n: ngettext(u'{0}d', u'{0}d', n).format(n),
    }
    if narrow:
        long_names = short_names
    values = OrderedDict((key, 0) for key in field_order)
    values['seconds'] = delta.total_seconds()
    values['days'], values['seconds'] = divmod(values['seconds'], 86400)
    values['hours'], values['seconds'] = divmod(values['seconds'], 3600)
    values['minutes'], values['seconds'] = divmod(values['seconds'], 60)
    for key, value in values.iteritems():
        values[key] = int(value)
    # keep all fields covered by the granularity, and if that results in
    # no non-zero fields, include otherwise excluded ones
    used_fields = set(field_order[:field_order.index(granularity) + 1])
    available_fields = [x for x in field_order if x not in used_fields]
    used_fields -= {k for k, v in values.iteritems() if not v}
    while not sum(values[x] for x in used_fields) and available_fields:
        used_fields.add(available_fields.pop(0))
    for key in available_fields:
        values[key] = 0
    nonzero = OrderedDict((k, v) for k, v in values.iteritems() if v)
    if not nonzero:
        return long_names[granularity](0)
    elif len(nonzero) == 1:
        key, value = nonzero.items()[0]
        return long_names[key](value)
    else:
        parts = [short_names[key](value) for key, value in nonzero.iteritems()]
        return u' '.join(parts)
コード例 #8
0
def _convert_email_principals(user, **kwargs):
    from fossir.modules.events.models.principals import EventPrincipal
    events = EventPrincipal.replace_email_with_user(user, 'event')
    if events:
        num = len(events)
        flash(
            ngettext(
                "You have been granted manager/submission privileges for an event.",
                "You have been granted manager/submission privileges for {} events.",
                num).format(num), 'info')
コード例 #9
0
 def _process(self):
     for event in self.events:
         event.move(self.target_category)
     flash(
         ngettext('You have moved one event to the category "{cat}"',
                  'You have moved {count} events to the category "{cat}"',
                  len(self.events)).format(count=len(self.events),
                                           cat=self.target_category.title),
         'success')
     return jsonify_data(flash=False)
コード例 #10
0
 def _process(self):
     for subcategory in self.subcategories:
         move_category(subcategory, self.target_category)
     flash(
         ngettext('{0} category moved to "{1}".',
                  '{0} categories moved to "{1}".',
                  len(self.subcategories)).format(
                      len(self.subcategories), self.target_category.title),
         'success')
     return jsonify_data(flash=False)
コード例 #11
0
 def validators(self):
     min_choices = self.object.field_data.get('min_choices')
     max_choices = self.object.field_data.get('max_choices')
     if min_choices is None and max_choices is None:
         return
     if min_choices is None:
         min_choices = -1
     if max_choices is None:
         max_choices = -1
     if max_choices == -1:
         message = ngettext('Please select at least %(min)d option.',
                            'Please select at least %(min)d options.',
                            min_choices)
     elif min_choices == -1:
         message = ngettext('Please select no more than %(max)d option.',
                            'Please select no more than %(max)d options.',
                            max_choices)
     else:
         message = _('Please select between %(min)d and %(max)d options.')
     return [Length(min=min_choices, max=max_choices, message=message)]
コード例 #12
0
def _convert_email_principals(user, **kwargs):
    from fossir.modules.events.contributions.models.principals import ContributionPrincipal
    contributions = ContributionPrincipal.replace_email_with_user(
        user, 'contribution')
    if contributions:
        num = len(contributions)
        flash(
            ngettext(
                "You have been granted manager/submission privileges for a contribution.",
                "You have been granted manager/submission privileges for {} contributions.",
                num).format(num), 'info')
コード例 #13
0
 def _process(self):
     for registration in self.registrations:
         registration.is_deleted = True
         signals.event.registration_deleted.send(registration)
         logger.info('Registration %s deleted by %s', registration, session.user)
         self.event.log(EventLogRealm.management, EventLogKind.negative, 'Registration',
                        'Registration deleted: {}'.format(registration.full_name),
                        session.user, data={'Email': registration.email})
     num_reg_deleted = len(self.registrations)
     flash(ngettext("Registration was deleted.",
                    "{num} registrations were deleted.", num_reg_deleted).format(num=num_reg_deleted), 'success')
     return jsonify_data()
コード例 #14
0
 def _process(self):
     form = BulkAbstractJudgmentForm(
         event=self.event,
         abstract_id=[a.id for a in self.abstracts],
         judgment=request.form.get('judgment'))
     if form.validate_on_submit():
         judgment_data, abstract_data = form.split_data
         submitted_abstracts = {
             abstract
             for abstract in self.abstracts
             if abstract.state == AbstractState.submitted
         }
         for abstract in submitted_abstracts:
             judge_abstract(abstract,
                            abstract_data,
                            judge=session.user,
                            **judgment_data)
         num_judged_abstracts = len(submitted_abstracts)
         num_prejudged_abstracts = len(
             self.abstracts) - num_judged_abstracts
         if num_judged_abstracts:
             flash(
                 ngettext(
                     "One abstract has been judged.",
                     "{num} abstracts have been judged.",
                     num_judged_abstracts).format(num=num_judged_abstracts),
                 'success')
         if num_prejudged_abstracts:
             flash(
                 ngettext(
                     "One abstract has been skipped since it is already judged.",
                     "{num} abstracts have been skipped since they are already judged.",
                     num_prejudged_abstracts).format(
                         num=num_prejudged_abstracts), 'warning')
         return jsonify_data(**self.list_generator.render_list())
     return jsonify_form(form=form,
                         fields=form._order,
                         submit=_('Judge'),
                         disabled_until_change=False)
コード例 #15
0
 def _process(self):
     delete_contribs = request.values.get('delete_contribs') == '1'
     deleted_contrib_count = 0
     for abstract in self.abstracts:
         if delete_contribs and abstract.contribution:
             deleted_contrib_count += 1
         delete_abstract(abstract, delete_contribs)
     deleted_abstract_count = len(self.abstracts)
     flash(
         ngettext(
             "The abstract has been deleted.",
             "{count} abstracts have been deleted.",
             deleted_abstract_count).format(count=deleted_abstract_count),
         'success')
     if deleted_contrib_count:
         flash(
             ngettext(
                 "The linked contribution has been deleted.",
                 "{count} linked contributions have been deleted.",
                 deleted_contrib_count).format(count=deleted_contrib_count),
             'success')
     return jsonify_data(**self.list_generator.render_list())
コード例 #16
0
 def _process(self):
     is_submitted = 'confirmed' in request.form
     if not is_submitted:
         return jsonify_template('events/management/delete_events.html',
                                 events=self.events)
     for ev in self.events[:]:
         ev.delete('Bulk-deleted by category manager', session.user)
     flash(
         ngettext('You have deleted one event',
                  'You have deleted {} events',
                  len(self.events)).format(len(self.events)), 'success')
     return jsonify_data(flash=False,
                         redirect=url_for('.manage_content', self.category))
コード例 #17
0
 def _process(self):
     count = 0
     for sess in self.event.sessions:
         for convener in sess.conveners:
             principal = convener.person.principal
             if principal:
                 sess.update_principal(principal, full_access=True)
                 count += 1
     self.event.log(EventLogRealm.management, EventLogKind.positive, 'Protection',
                    'Modification rights have been granted to all session conveners', session.user)
     flash(ngettext('Session modification rights have been granted to one session convener',
                    'Session modification rights have been granted to {} session conveners', count).format(count))
     return redirect(url_for('.person_list', self.event))
コード例 #18
0
 def _process(self):
     form = BulkPaperJudgmentForm(
         event=self.event,
         judgment=request.form.get('judgment'),
         contribution_id=[c.id for c in self.contributions])
     if form.validate_on_submit():
         submitted_papers = [
             c.paper for c in self.contributions if c.paper
             and c.paper.last_revision.state == PaperRevisionState.submitted
         ]
         for submitted_paper in submitted_papers:
             judge_paper(submitted_paper,
                         form.judgment.data,
                         form.judgment_comment.data,
                         judge=session.user)
         num_submitted_papers = len(submitted_papers)
         num_not_submitted_papers = len(
             self.contributions) - num_submitted_papers
         if num_submitted_papers:
             flash(
                 ngettext(
                     "One paper has been judged.",
                     "{num} papers have been judged.",
                     num_submitted_papers).format(num=num_submitted_papers),
                 'success')
         if num_not_submitted_papers:
             flash(
                 ngettext(
                     "One contribution has been skipped since it has no paper submitted yet or it is in "
                     "a final state.",
                     "{num} contributions have been skipped since they have no paper submitted yet or they "
                     "are in a final state.",
                     num_not_submitted_papers).format(
                         num=num_not_submitted_papers), 'warning')
         return jsonify_data(**self.list_generator.render_list())
     return jsonify_form(form=form,
                         submit=_('Judge'),
                         disabled_until_change=False)
コード例 #19
0
 def _process(self):
     tpl = get_template_module(
         'events/surveys/emails/survey_link_email.html', event=self.event)
     form = InvitationForm(body=tpl.get_html_body(),
                           subject=tpl.get_subject(),
                           event=self.event)
     if form.validate_on_submit():
         self._send_emails(form, form.recipients.data)
         num = len(form.recipients.data)
         flash(
             ngettext('Your email has been sent.',
                      '{} emails have been sent.', num).format(num))
         return jsonify_data(flash=True)
     return jsonify_form(form)
コード例 #20
0
 def _process(self):
     count = 0
     for cont in self.event.contributions:
         for entry in set(cont.acl_entries):
             cont.update_principal(entry.principal, del_roles={'submit'})
             count += 1
     for entry in set(self.event.acl_entries):
         self.event.update_principal(entry.principal, del_roles={'submit'})
         count += 1
     self.event.log(EventLogRealm.management, EventLogKind.negative, 'Protection',
                    'Submission privileges have been revoked from event submitters', session.user)
     flash(ngettext('Submission rights have been revoked from one user',
                    'Submission rights have been revoked from {} users', count).format(count))
     return redirect(url_for('.person_list', self.event))
コード例 #21
0
 def _process(self):
     tpl = get_template_module('events/registration/emails/custom_email_default.html')
     default_body = tpl.get_html_body()
     registration_ids = request.form.getlist('registration_id')
     form = EmailRegistrantsForm(body=default_body, regform=self.regform, registration_id=registration_ids,
                                 recipients=[x.email for x in self.registrations])
     if not self.regform.tickets_enabled:
         del form.attach_ticket
     if form.validate_on_submit():
         self._send_emails(form)
         num_emails_sent = len(self.registrations)
         flash(ngettext("The email was sent.",
                        "{num} emails were sent.", num_emails_sent).format(num=num_emails_sent), 'success')
         return jsonify_data()
     return jsonify_template('events/registration/management/email.html', form=form, regform=self.regform)
コード例 #22
0
 def _process(self):
     count = 0
     for cont in self.event.contributions:
         speakers = cont.speakers[:]
         for subcontrib in cont.subcontributions:
             speakers += subcontrib.speakers
         for speaker in speakers:
             principal = speaker.person.principal
             if principal:
                 cont.update_principal(principal, add_roles={'submit'})
                 count += 1
     self.event.log(EventLogRealm.management, EventLogKind.positive, 'Protection',
                    'Contribution speakers have been granted with submission rights', session.user)
     flash(ngettext('Submission rights have been granted to one speaker',
                    'Submission rights have been granted to {} speakers', count).format(count))
     return redirect(url_for('.person_list', self.event))
コード例 #23
0
def _event_type_changed(event, **kwargs):
    from fossir.modules.events.features.util import (get_enabled_features,
                                                     get_disallowed_features,
                                                     set_feature_enabled,
                                                     format_feature_names)
    conflicting = get_enabled_features(
        event, only_explicit=True) & get_disallowed_features(event)
    if conflicting:
        for feature in conflicting:
            set_feature_enabled(event, feature, False)
        if request.endpoint != 'api.jsonrpc':
            # XXX: we cannot flash a message in the legacy js ajax editor for the event type.
            # remove this check once we don't use it anymore (on the general settings page)
            flash(
                ngettext(
                    'Feature disabled: {features} (not available for this event type)',
                    'Features disabled: {features} (not available for this event type)',
                    len(conflicting)).format(
                        features=format_feature_names(conflicting)), 'warning')
コード例 #24
0
 def _process(self):
     person_ids = request.form.getlist('person_id')
     user_ids = request.form.getlist('user_id')
     recipients = set(self._find_event_persons(person_ids, request.args.get('not_invited_only') == '1'))
     recipients |= set(self._find_users(user_ids))
     if self.no_account:
         tpl = get_template_module('events/persons/emails/invitation.html', event=self.event)
         disabled_until_change = False
     else:
         tpl = get_template_module('events/persons/emails/generic.html', event=self.event)
         disabled_until_change = True
     form = EmailEventPersonsForm(person_id=person_ids, user_id=user_ids,
                                  recipients=[x.email for x in recipients], body=tpl.get_html_body(),
                                  subject=tpl.get_subject(), register_link=self.no_account, event=self.event)
     if form.validate_on_submit():
         self._send_emails(form, recipients)
         num = len(recipients)
         flash(ngettext('Your email has been sent.', '{} emails have been sent.', num).format(num))
         return jsonify_data()
     return jsonify_template('events/persons/email_dialog.html', form=form,
                             disabled_until_change=disabled_until_change)
コード例 #25
0
 def _process_DELETE(self):
     prev = get_enabled_features(self.event)
     feature = get_feature_definition(request.view_args['feature'])
     changed = set()
     if set_feature_enabled(self.event, feature.name, False):
         current = get_enabled_features(self.event)
         changed = prev - current
         flash(
             ngettext('Feature disabled: {features}',
                      'Features disabled: {features}', len(changed)).format(
                          features=format_feature_names(changed)),
             'warning')
         logger.info("Feature '%s' for event %s disabled by %s",
                     feature.name, self.event, session.user)
         self.event.log(EventLogRealm.management, EventLogKind.negative,
                        'Features',
                        'Disabled {}'.format(feature.friendly_name),
                        session.user)
     return jsonify_data(enabled=False,
                         event_menu=self.render_event_menu(),
                         changed=list(changed))
コード例 #26
0
 def _process_PUT(self):
     prev = get_enabled_features(self.event)
     feature = get_feature_definition(request.view_args['feature'])
     if feature.name in get_disallowed_features(self.event):
         raise Forbidden('Feature not available')
     changed = set()
     if set_feature_enabled(self.event, feature.name, True):
         current = get_enabled_features(self.event)
         changed = current - prev
         flash(
             ngettext('Feature enabled: {features}',
                      'Features enabled: {features}', len(changed)).format(
                          features=format_feature_names(changed)),
             'success')
         logger.info("Feature '%s' for event %s enabled by %s",
                     feature.name, self.event, session.user)
         self.event.log(EventLogRealm.management, EventLogKind.positive,
                        'Features',
                        'Enabled {}'.format(feature.friendly_name),
                        session.user)
     return jsonify_data(enabled=True,
                         event_menu=self.render_event_menu(),
                         changed=list(changed))
コード例 #27
0
 def _process(self):
     files = request.files.getlist('image')
     num = 0
     for f in files:
         filename = secure_filename(f.filename, 'image')
         data = BytesIO()
         shutil.copyfileobj(f, data)
         data.seek(0)
         try:
             image_type = Image.open(data).format.lower()
         except IOError:
             # Invalid image data
             continue
         data.seek(0)
         # XXX: mpo is basically JPEG and JPEGs from some cameras are (wrongfully) detected as mpo
         if image_type == 'mpo':
             image_type = 'jpeg'
         elif image_type not in {'jpeg', 'gif', 'png'}:
             flash(
                 _("The image '{name}' has an invalid type ({type}); only JPG, GIF and PNG are allowed."
                   ).format(name=f.filename, type=image_type), 'error')
             continue
         content_type = 'image/' + image_type
         image = ImageFile(event=self.event,
                           filename=filename,
                           content_type=content_type)
         image.save(data)
         num += 1
         db.session.flush()
         logger.info('Image %s uploaded by %s', image, session.user)
         signals.event_management.image_created.send(image,
                                                     user=session.user)
     flash(
         ngettext("The image has been uploaded",
                  "{count} images have been uploaded",
                  num).format(count=len(files)), 'success')
     return jsonify_data(image_list=_render_image_list(self.event))
コード例 #28
0
 def _process(self):
     form = AddAttachmentFilesForm(linked_object=self.object)
     if form.validate_on_submit():
         files = form.files.data
         folder = form.folder.data or AttachmentFolder.get_or_create_default(linked_object=self.object)
         for f in files:
             filename = secure_filename(f.filename, 'attachment')
             attachment = Attachment(folder=folder, user=session.user, title=to_unicode(f.filename),
                                     type=AttachmentType.file, protection_mode=form.protection_mode.data)
             if attachment.is_self_protected:
                 attachment.acl = form.acl.data
             content_type = mimetypes.guess_type(f.filename)[0] or f.mimetype or 'application/octet-stream'
             attachment.file = AttachmentFile(user=session.user, filename=filename, content_type=content_type)
             attachment.file.save(f.stream)
             db.session.add(attachment)
             db.session.flush()
             logger.info('Attachment %s uploaded by %s', attachment, session.user)
             signals.attachments.attachment_created.send(attachment, user=session.user)
         flash(ngettext("The attachment has been uploaded", "{count} attachments have been uploaded", len(files))
               .format(count=len(files)), 'success')
         return jsonify_data(attachment_list=_render_attachment_list(self.object))
     return jsonify_template('attachments/upload.html', form=form, action=url_for('.upload', self.object),
                             protection_message=_render_protection_message(self.object),
                             folders_protection_info=_get_folders_protection_info(self.object))
コード例 #29
0
def test_ngettext():
    session.lang = 'fr_MP'

    assert ngettext(u'{} cow', u'{} cows', 1).format(1) == u'1 vache'
    assert ungettext(u'{} cow', u'{} cows', 42).format(42) == u'42 vaches'