def flash_if_unregistered(event, get_person_links): """Flash message when adding users with no indico 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 Indico account.', 'You have added {} users with no Indico account.', added_non_users).format(added_non_users) msg = _( 'An Indico 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')
def flash_if_unregistered(event, get_person_links): """Flash message when adding users with no indico 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 Indico account.', 'You have added {} users with no Indico account.', added_non_users).format(added_non_users) msg = _('An Indico 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')
def __call__(self, form, field): count = len(re.split(r'\s+', field.data, flags=re.UNICODE)) if field.data else 0 if count < self.min or self.max != -1 and count > self.max: if self.max == -1: message = ngettext('Field must contain at least {min} word.', 'Field must contain at least {min} words.', self.min) elif self.min == -1: message = ngettext('Field cannot contain more than {max} word.', 'Field cannot contain more than {max} words.', self.max) else: message = _('Field must contain between {min} and {max} words.') raise ValidationError(message.format(min=self.min, max=self.max, length=count))
def __call__(self, form, field): count = len(re.findall(r'\w+', field.data)) if field.data else 0 if count < self.min or self.max != -1 and count > self.max: if self.max == -1: message = ngettext('Field must contain at least {min} word.', 'Field must contain at least {min} words.', self.min) elif self.min == -1: message = ngettext('Field cannot contain more than {max} word.', 'Field cannot contain more than {max} words.', self.max) else: message = _('Field must have between {min} and {max} words.') raise ValidationError(message.format(min=self.min, max=self.max, length=count))
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))
def _convert_email_principals(user, **kwargs): from indico.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')
def _associate_registrations(user, **kwargs): from indico.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')
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)
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())
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)
def _process(self): files = request.files.getlist("image") 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) if image_type not in {"jpeg", "gif", "png"}: continue content_type = "image/" + image_type image = ImageFile(event_new=self.event_new, filename=filename, content_type=content_type) image.save(data) 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", len(files)).format( count=len(files) ), "success", ) return jsonify_data(image_list=_render_image_list(self.event_new))
def _getContribHTML(self,contrib): sdate = "" if contrib.getAdjustedStartDate() is not None: sdate=contrib.getAdjustedStartDate().strftime("%Y-%b-%d %H:%M" ) strdur = "" if contrib.getDuration() is not None and contrib.getDuration().seconds != 0: strdur = (datetime(1900,1,1)+ contrib.getDuration()).strftime("%Hh%M'") dur = contrib.getDuration() self._totaldur = self._totaldur + dur title = """<a href=%s>%s</a>"""%( quoteattr( str( urlHandlers.UHContributionModification.getURL( contrib ) ) ), self.htmlText( contrib.getTitle() )) l = [] for spk in contrib.getSpeakerList(): l.append( self.htmlText( spk.getFullName() ) ) speaker = "<br>".join( l ) track = "" if contrib.getTrack(): track = self.htmlText( contrib.getTrack().getCode() ) cType="" if contrib.getType() is not None: cType=contrib.getType().getName() status=ContribStatusList().getCode(contrib.getCurrentStatus().__class__) attached_items = contrib.attached_items materials = None if attached_items: num_files = len(attached_items['files']) + sum(len(f.attachments) for f in attached_items['folders']) materials = '<a href="{}">{}</a>'.format( url_for('attachments.management', contrib), ngettext('1 file', '{num} files', num_files).format(num=num_files) ) editURL=urlHandlers.UHSessionModContribListEditContrib.getURL(contrib) if self._currentSorting!="": editURL.addParam("sortBy",self._currentSorting) editIconURL=Config.getInstance().getSystemIconURL("modify") html = """ <tr> <td><input type="checkbox" name="contributions" value=%s></td> <td valign="top" class="abstractLeftDataCell" nowrap>%s</td> <td valign="top" nowrap class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell"><a href=%s><img src=%s border="0" alt=""></a>%s</td> <td valign="top" class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell">%s</td> <td valign="top" class="abstractDataCell">%s</td> </tr> """%(quoteattr(str(contrib.getId())), self.htmlText(contrib.getId()), sdate or " ", strdur or " ", cType or " ", quoteattr(str(editURL)), quoteattr(str(editIconURL)),title or " ", speaker or " ", track or " ", status or " ", materials or " ", self.htmlText(contrib.getBoardNumber()) or " ") return html
def _process(self): files = request.files.getlist('file') 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) if image_type not in {'jpeg', 'gif', 'png'}: continue content_type = 'image/' + image_type image = ImageFile(event_id=self._conf.id, filename=filename, content_type=content_type) image.save(data) db.session.add(image) db.session.flush() logger.info('Image {} uploaded by {}'.format(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", len(files)) .format(count=len(files)), 'success') return jsonify_data(image_list=_render_image_list(self._conf))
def _convert_email_principals(user, **kwargs): from indico.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')
def _convert_email_principals(user, **kwargs): from indico.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')
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())
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)
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))
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) 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()
def __call__(self, form, field): if field.data is None: return if any(form[f].data is not None for f in self.fields): field_names = sorted(unicode(form[f].label.text) for f in self.fields) msg = ngettext(u'This field is mutually exclusive with another field: {}', u'This field is mutually exclusive with other fields: {}', len(field_names)) raise ValidationError(msg.format(u', '.join(field_names)))
def _getMaterialsHTML(self, contrib, modify): attached_items = contrib.attached_items if not attached_items: return '' num_files = len(attached_items['files']) + sum(len(f.attachments) for f in attached_items['folders']) return '<a href="{}">{}</a>'.format( url_for('attachments.management' if modify else 'event.sessionDisplay', contrib), ngettext('1 file', '{num} files', num_files).format(num=num_files) )
def _getMaterialsHTML(self, contrib, modify): attached_items = contrib.attached_items if not attached_items: return "" num_files = len(attached_items["files"]) + sum(len(f.attachments) for f in attached_items["folders"]) return '<a href="{}">{}</a>'.format( url_for("attachments.management" if modify else "event.sessionDisplay", contrib), ngettext("1 file", "{num} files", num_files).format(num=num_files), )
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)]
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)
def _process(self): form = BulkAbstractJudgmentForm(event=self.event_new, 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, submit=_('Judge'), disabled_until_change=False)
def _process(self): tpl = get_template_module('events/registration/emails/custom_email_default.html', event=self.event) default_body = tpl.get_html_body() form = EmailRegistrantsForm(body=default_body, regform=self.regform) 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)
def _getReviewerStatus(self, status): if self.anyReviewerHasGivenAdvice(): advices = defaultdict(int) for reviewer in self._reviewManager.getReviewersList(): judgement = self._reviewManager.getLastReview().getReviewerJudgement(reviewer).getJudgement() if judgement != None: advices[judgement] += 1 resume = "(%s)" % ", ".join("%s %s" % (v, k.lower()) for k, v in advices.iteritems()) status.append(_("Content assessed by %s %s %s") % ( sum(advices.values()), ngettext("reviewer", "reviewers", sum(advices.values())), resume)) else: status.append(_("No content reviewers have decided yet"))
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()
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))
def _process(self): person_ids = request.form.getlist('person_id') recipients = {p.email for p in self._find_event_persons(person_ids) if p.email} form = EmailEventPersonsForm(person_id=person_ids, recipients=', '.join(recipients)) if form.validate_on_submit(): for recipient in recipients: email = make_email(to_list=recipient, from_address=form.from_address.data, subject=form.subject.data, body=form.body.data, html=True) send_email(email, self.event_new, 'Event Persons') num = len(recipients) flash(ngettext('Your email has been sent.', '{} emails have been sent.', num).format(num)) return jsonify_data() return jsonify_form(form, submit=_('Send'))
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=self._format_feature_names(changed)), 'warning') logger.info("Feature '%s' for event %s disabled by %s", feature, 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))
def _process_PUT(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, True): current = get_enabled_features(self.event) changed = current - prev flash(ngettext('Feature enabled: {features}', 'Features enabled: {features}', len(changed)) .format(features=self._format_feature_names(changed)), 'success') logger.info("Feature '%s' for event %s enabled by %s", feature, 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))