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 process_vc_room_association(plugin, event, vc_room, form, event_vc_room=None, allow_same_room=False): # disable autoflush, so that the new event_vc_room does not influence the result with db.session.no_autoflush: if event_vc_room is None: event_vc_room = VCRoomEventAssociation() plugin.update_data_association(event, vc_room, event_vc_room, form.data) existing = set() if event_vc_room.link_object is not None: # check whether there is a room-event association already present # for the given event, room and plugin q = VCRoomEventAssociation.find( VCRoomEventAssociation.event_new == event, VCRoomEventAssociation.link_object == event_vc_room.link_object, _join=VCRoom ) if allow_same_room: q = q.filter(VCRoom.id != vc_room.id) existing = {x.vc_room for x in q} if event_vc_room.link_type != VCRoomLinkType.event and existing: transaction.abort() flash(_("There is already a VC room attached to '{link_object_title}'.").format( link_object_title=resolve_title(event_vc_room.link_object)), 'error') return None elif event_vc_room.link_type == VCRoomLinkType.event and vc_room in existing: transaction.abort() flash(_("This {plugin_name} room is already attached to the event.").format(plugin_name=plugin.friendly_name), 'error') return None else: return event_vc_room
def _check_access(self): if not self.category.can_access(session.user): msg = [_("You are not authorized to access this category.")] if self.category.no_access_contact: msg.append(_("If you believe you should have access, please contact {}") .format(self.category.no_access_contact)) raise Forbidden(' '.join(msg))
def get_visibility_options(category_or_event, allow_invisible=True): """Return the visibility options available for the category or event.""" if isinstance(category_or_event, Event): category = category_or_event.category event = category_or_event else: category = category_or_event event = None def _category_above_message(number): return ngettext('From the category above', 'From {} categories above', number).format(number) options = [(n + 1, ('{} \N{RIGHTWARDS ARROW} "{}"'.format(_category_above_message(n).format(n), title))) for n, title in enumerate(category.chain_titles[::-1])] if event is None: options[0] = (1, _("From this category only")) else: options[0] = (1, '{} \N{RIGHTWARDS ARROW} "{}"'.format(_("From the current category only"), category.title)) options[-1] = ('', _("From everywhere")) if allow_invisible: options.insert(0, (0, _("Invisible"))) # In case the current visibility is higher than the distance to the root category if category_or_event.visibility is not None and not any(category_or_event.visibility == x[0] for x in options): options.append((category_or_event.visibility, '({} \N{RIGHTWARDS ARROW} {})'.format(_category_above_message(category_or_event.visibility), _("Everywhere")))) return options
def _getBody(self, params): params['period_options'] = [ ('pastmonth', _('Past month')), ('thisyear', _('This year')), ('sinceever', _('Since ever')) ] return WTemplated('RoomBookingRoomStats').getHTML(params)
def _checkSessionUser(self): if session.user is None: raise Forbidden(response=redirect_to_login(reason=_('You are trying to sign an agreement that requires ' 'you to be logged in'))) if self.agreement.user != session.user: raise Forbidden(_('Please log in as {name} to sign this agreement.') .format(name=self.agreement.user.full_name))
def _process(self): f = request.files['logo'] try: img = Image.open(f) except IOError: flash(_('You cannot upload this file as a logo.'), 'error') return jsonify_data(content=None) if img.format.lower() not in {'jpeg', 'png', 'gif'}: flash(_('The file has an invalid format ({format})').format(format=img.format), 'error') return jsonify_data(content=None) if img.mode == 'CMYK': flash(_('The logo you uploaded is using the CMYK colorspace and has been converted to RGB. Please check if ' 'the colors are correct and convert it manually if necessary.'), 'warning') img = img.convert('RGB') image_bytes = BytesIO() img.save(image_bytes, 'PNG') image_bytes.seek(0) content = image_bytes.read() self.event.logo = content self.event.logo_metadata = { 'hash': crc32(content), 'size': len(content), 'filename': os.path.splitext(secure_filename(f.filename, 'logo'))[0] + '.png', 'content_type': 'image/png' } flash(_('New logo saved'), 'success') logger.info("New logo '%s' uploaded by %s (%s)", f.filename, session.user, self.event) return jsonify_data(content=get_logo_data(self.event))
def __init__(self, *args, **kwargs): super(SplitCategoryForm, self).__init__(*args, **kwargs) if self.all_selected.data: self.event_id.data = [] self.first_category.label.text = _('Category name') self.first_category.description = _('The events will be moved into a new sub-category with this title.') del self.second_category
def _process(self): if self.verification_email_sent and 'token' in request.args: email = secure_serializer.loads(request.args['token'], max_age=3600, salt='link-identity-email') if email not in self.emails: raise BadData('Emails do not match') session['login_identity_info']['email_verified'] = True session.modified = True flash(_('You have successfully validated your email address and can now proceed with the login.'), 'success') return redirect(url_for('.link_account', provider=self.identity_info['provider'])) if self.must_choose_email: form = SelectEmailForm() form.email.choices = zip(self.emails, self.emails) else: form = IndicoForm() if form.validate_on_submit(): if self.email_verified: return self._create_identity() elif not self.verification_email_sent: return self._send_confirmation(form.email.data if self.must_choose_email else self.emails[0]) else: flash(_('The validation email has already been sent.'), 'warning') return WPAuth.render_template('link_identity.html', identity_info=self.identity_info, user=self.user, email_sent=self.verification_email_sent, emails=' / '.join(self.emails), form=form, must_choose_email=self.must_choose_email)
def _createTabCtrl(self): self._tabCtrl = wcomponents.TabControl() self._subTabConfiguration = self._tabCtrl.newTab("configuration", _("Configuration"), urlHandlers.UHAdminsSystem.getURL()) self._subTabMaintenance = self._tabCtrl.newTab("maintenance", _("Maintenance"), urlHandlers.UHMaintenance.getURL())
def _processForbidden(self, e): message = _("Access Denied") if e.description == Forbidden.description: explanation = _("You are not allowed to access this page.") else: explanation = e.description return WErrorWSGI((message, explanation)).getHTML()
def _process(self): quiet = request.form.get('quiet') == '1' force = request.form.get('force') == '1' persistent = request.form.get('persistent') == '1' and api_settings.get('allow_persistent') old_key = self.user.api_key if old_key: if not force: raise BadRequest('There is already an API key for this user') if old_key.is_blocked and not session.user.is_admin: raise Forbidden old_key.is_active = False db.session.flush() key = APIKey(user=self.user) db.session.add(key) if persistent: key.is_persistent_allowed = persistent elif old_key: key.is_persistent_allowed = old_key.is_persistent_allowed if not quiet: if old_key: flash(_('Your API key has been successfully replaced.'), 'success') if old_key.use_count: flash(_('Please update any applications which use old key.'), 'warning') else: flash(_('Your API key has been successfully created.'), 'success') db.session.flush() return redirect_or_jsonify(url_for('api.user_profile'), flash=not quiet, is_persistent_allowed=key.is_persistent_allowed)
def test_translation_plugins(app, tmpdir): session.lang = 'fr_FR' plugin = MockPlugin(plugin_engine, app) app.extensions['pluginengine'].plugins['dummy'] = plugin plugin.root_path = tmpdir.strpath french_core_str = DICTIONARIES['fr_FR']['This is not a string'] french_plugin_str = "This is not le french string" trans_dir = os.path.join(plugin.root_path, 'translations', 'fr_FR', 'LC_MESSAGES') os.makedirs(trans_dir) # Create proper *.mo file for plugin translation with open(os.path.join(trans_dir, 'messages.mo'), 'wb') as f: catalog = Catalog(locale='fr_FR', domain='plugin') catalog.add("This is not a string", "This is not le french string") write_mo(f, catalog) gettext_plugin = make_bound_gettext('dummy') assert _(u'This is not a string') == french_core_str assert gettext_context(u"This is not a string") == french_core_str assert gettext_plugin(u"This is not a string") == french_plugin_str with plugin.plugin_context(): assert _(u'This is not a string') == french_core_str assert gettext_context(u"This is not a string") == french_plugin_str assert gettext_plugin(u"This is not a string") == french_plugin_str
def _check_currencies(self, form): """Checks if the currencies are valid. :return: `(auto_currency, invalid_currency)` - tuple containing the currency that should be automatically set on the event and a flag if the currency issues cannot be resolved automatically and require user interaction (i.e. saving the plugin settings is disallowed) """ messages = [] event = self._conf valid_currencies = self.plugin.valid_currencies currency = event_settings.get(event, 'currency') if valid_currencies is None or currency in valid_currencies: return None, False, messages if len(valid_currencies) == 1: auto_currency = list(valid_currencies)[0] for plugin in get_active_payment_plugins(event).itervalues(): if plugin.valid_currencies is not None and auto_currency not in plugin.valid_currencies: messages.append(('error', _("This payment method only supports {}, but the payment method " "'{}' doesn't.").format(auto_currency, plugin.title))) return None, True, messages if not form.is_submitted(): messages.append(('warning', _("This payment method only supports {0}. Enabling it will automatically " "change the currency of the event to {0}!").format(auto_currency))) return auto_currency, False, messages if not form.is_submitted(): messages.append(('error', _("To enable this payment method, please use one of the following " "currencies: {}").format(', '.join(valid_currencies)))) return None, True, messages
def _getNavigationDrawer(self): if "user_id" in request.view_args: user = User.get(request.view_args["user_id"]) profile_breadcrumb = _("Profile of {name}").format(name=user.full_name) else: profile_breadcrumb = _("My Profile") return WSimpleNavigationDrawer(profile_breadcrumb)
def _process(self): query = LocalGroup.query.options(joinedload(LocalGroup.members)).order_by(db.func.lower(LocalGroup.name)) groups = [g.proxy for g in query] providers = [p for p in multipass.identity_providers.itervalues() if p.supports_groups] form = SearchForm(obj=FormDefaults(exact=True)) if not providers: del form.provider else: form.provider.choices = [("", _("All")), ("indico", _("Local Groups"))] + [ (p.name, p.title) for p in sorted(providers, key=attrgetter("title")) ] search_results = None if form.validate_on_submit(): search_providers = None if not providers or not form.provider.data else {form.provider.data} search_results = GroupProxy.search(form.name.data, exact=form.exact.data, providers=search_providers) search_results.sort(key=attrgetter("provider", "name")) provider_titles = {p.name: p.title for p in multipass.identity_providers.itervalues()} provider_titles[None] = _("Local") return WPGroupsAdmin.render_template( "groups.html", groups=groups, providers=providers, form=form, search_results=search_results, provider_titles=provider_titles, )
def validate_email(self, field): user = self.user if user is None: raise ValidationError(_('There is no profile with this email address.')) elif not user.local_identities: # XXX: Should we allow creating a new identity instead? Would be user-friendly for sure! raise ValidationError(_('This profile has no local account.'))
def get_time_changes_notifications(changes, tzinfo, entry=None): notifications = [] for obj, change in changes.iteritems(): if entry: if entry.object == obj: continue if not isinstance(obj, Event) and obj.timetable_entry in entry.children: continue msg = None if isinstance(obj, Event): if 'start_dt' in change: new_time = change['start_dt'][1] msg = _("Event start time changed to {}") elif 'end_dt' in change: new_time = change['end_dt'][1] msg = _("Event end time changed to {}") else: raise ValueError("Invalid change in event.") elif isinstance(obj, SessionBlock): if 'start_dt' in change: new_time = change['start_dt'][1] msg = _("Session block start time changed to {}") elif 'end_dt' in change: new_time = change['end_dt'][1] msg = _("Session block end time changed to {}") else: raise ValueError("Invalid change in session block.") if msg: notifications.append(msg.format(format_time(new_time, timezone=tzinfo))) return notifications
def _checkParams(self, params): l = locators.CategoryWebLocator(params) self._target = l.getObject() if self._target is None: raise NotFoundError(_("The category with id '{}' does not exist or has been deleted").format( params["categId"]), title=_("Category not found"))
def _extend_event_menu(sender, **kwargs): from indico.modules.events.registration.models.forms import RegistrationForm from indico.modules.events.registration.models.registrations import Registration def _visible_registration(event): if not event.has_feature('registration'): return False if RegistrationForm.query.with_parent(event).filter(RegistrationForm.is_scheduled).has_rows(): return True if not session.user: return False return (Registration.query.with_parent(event) .join(Registration.registration_form) .filter(Registration.user == session.user, ~Registration.is_deleted, ~RegistrationForm.is_deleted) .has_rows()) def _visible_participant_list(event): return event.has_feature('registration') yield MenuEntryData(_('Registration'), 'registration', 'event_registration.display_regform_list', position=10, visible=_visible_registration) yield MenuEntryData(_('Participant List'), 'participants', 'event_registration.participant_list', position=11, visible=_visible_participant_list, static_site=True)
def _sidemenu_sections(sender, **kwargs): user_has_rooms = session.user is not None and Room.user_owns_rooms(session.user) yield SideMenuSection('search', _("Search"), 40, icon='search', active=True) if user_has_rooms: yield SideMenuSection('my_rooms', _("My Rooms"), 30, icon='user') yield SideMenuSection('blocking', _("Room Blocking"), 20, icon='lock')
def event_or_shorturl(confId, shorturl_namespace=False, force_overview=False): func = None event_ = Event.get(int(confId)) if confId.isdigit() else None if event_ and event_.is_deleted: raise NotFound(_('This event has been deleted.')) elif event_: # For obvious reasons an event id always comes first. # If it's used within the short url namespace we redirect to the event namespace, otherwise # we call the RH to display the event if shorturl_namespace: func = lambda: redirect(event_.url) else: request.view_args['confId'] = int(request.view_args['confId']) func = lambda: RHDisplayEvent().process() else: shorturl_event = (Event.query .filter(db.func.lower(Event.url_shortcut) == confId.lower(), ~Event.is_deleted) .one_or_none()) if (shorturl_namespace or config.ROUTE_OLD_URLS) and shorturl_event: if shorturl_namespace: # Correct namespace => redirect to the event func = lambda: redirect(shorturl_event.url) else: # Old event namespace => 301-redirect to the new shorturl first to get Google etc. to update it func = lambda: redirect(shorturl_event.short_url, 301) elif is_legacy_id(confId): mapping = LegacyEventMapping.find_first(legacy_event_id=confId) if mapping is not None: url = url_for('events.display', confId=mapping.event_id) func = lambda: redirect(url, 301) if func is None: raise NotFound(_('An event with this ID/shortcut does not exist.')) return func()
def _getBody(self, params): params["period_options"] = [ ("pastmonth", _("Past month")), ("thisyear", _("This year")), ("sinceever", _("Since ever")), ] return WTemplated("RoomBookingRoomStats").getHTML(params)
def _getNavigationDrawer(self): if 'user_id' in request.view_args: user = User.get(request.view_args['user_id']) profile_breadcrumb = _('Profile of {name}').format(name=user.full_name) else: profile_breadcrumb = _('My Profile') return WSimpleNavigationDrawer(profile_breadcrumb)
def pre_validate(self, form): if self.best_unit in self.units: return if self.object_data is None: raise ValueError(_('Please choose a valid unit.')) if self.object_data != self.data: raise ValueError(_('Please choose a different unit or keep the previous value.'))
def process_form(self): form = self.form if not form.validate_on_submit(): return if not self.request or not self.request.can_be_modified: req = Request(event=self.event, definition=self.definition, created_by_user=session.user) new = True else: req = self.request new = False try: with db.session.no_autoflush: self.definition.send(req, form.data) except RequestModuleError: self.commit = False flash_msg = _('There was a problem sending your request ({0}). Please contact support.') flash(flash_msg.format(self.definition.title), 'error') else: if new: flash_msg = (_("Your request ({0}) has been accepted.") if req.state == RequestState.accepted else _("Your request ({0}) has been sent.")) else: flash_msg = _("Your request ({0}) has been modified.") flash(flash_msg.format(self.definition.title), 'success') if self.is_manager: return redirect(url_for('.event_requests_details', self.event, type=self.definition.name)) else: return redirect(url_for('.event_requests', self.event))
def process_form(self): form = self.manager_form if self.request.state == RequestState.withdrawn: return elif not form.validate_on_submit(): # very unlikely, unless the definition uses a custom form return if 'action_accept' in form and form.action_accept.data: action = 'accept' elif 'action_reject' in form and form.action_reject.data: action = 'reject' elif 'action_save' in form and form.action_save.data: action = 'save' else: # This happens when the request was already processed, e.g. in another # tab or if you simply click the submit button twice. No nee to fail; # just don't do anything. return redirect(url_for('.event_requests_details', self.request)) if action == 'accept': self.definition.accept(self.request, self.manager_form.data, session.user) flash(_('You have accepted this request.'), 'info') elif action == 'reject': self.definition.reject(self.request, self.manager_form.data, session.user) flash(_('You have rejected this request.'), 'info') elif action == 'save': self.definition.manager_save(self.request, self.manager_form.data) flash(_("You have updated the request (only management-specific data)."), 'info') return redirect(url_for('.event_requests_details', self.request))
def _process(self): if session.user: return redirect(url_for('misc.index')) handler = MultipassRegistrationHandler(self) if self.identity_info else LocalRegistrationHandler(self) verified_email = self._get_verified_email() if verified_email is not None: handler.email_verified(verified_email) flash(_('You have successfully validated your email address and can now proceeed with the registration.'), 'success') return redirect(url_for('.register', provider=self.provider_name)) form = handler.create_form() # Check for pending users if we have verified emails pending = None if not handler.must_verify_email: pending = User.find_first(~User.is_deleted, User.is_pending, User.all_emails.contains(db.func.any(list(handler.get_all_emails(form))))) if form.validate_on_submit(): if handler.must_verify_email: return self._send_confirmation(form.email.data) else: return self._create_user(form, handler, pending) elif not form.is_submitted() and pending: # If we have a pending user, populate empty fields with data from that user for field in form: value = getattr(pending, field.short_name, '') if value and not field.data: field.data = value if pending: flash(_("There is already some information in Indico that concerns you. " "We are going to link it automatically."), 'info') return WPAuth.render_template('register.html', form=form, local=(not self.identity_info), must_verify_email=handler.must_verify_email, widget_attrs=handler.widget_attrs, email_sent=session.pop('register_verification_email_sent', False))
def __call__(self, form, field): if field.data is None: return field_dt = as_utc(field.data) earliest_dt = self.get_earliest(form, field) latest_dt = self.get_latest(form, field) if field_dt != field.object_data: if earliest_dt and field_dt < earliest_dt: if self.earliest_now: msg = _("'{}' can't be in the past ({})").format( field.label, field.timezone) else: dt = format_datetime(earliest_dt, timezone=field.timezone) msg = _("'{}' can't be before {} ({})").format( field.label, dt, field.timezone) raise ValidationError(msg) if latest_dt and field_dt > latest_dt: if self.latest_now: msg = _("'{}' can't be in the future ({})").format( field.label, field.timezone) else: dt = format_datetime(latest_dt, timezone=field.timezone) msg = _("'{}' can't be after {} ({})").format( field.label, dt, field.timezone) raise ValidationError(msg)
def _checkProtection(self): LoggedOnlyService._checkProtection(self) if self._aw.getUser(): if not self._target.canModify(self._aw): raise ServiceError("ERR-U6", _("You are not allowed to perform this request")) else: raise ServiceError("ERR-U7", _("You are currently not authenticated. Please log in again."))
class RegistrationFullNameNoTitlePlaceholderD(FullNamePlaceholderBase): name = 'full_name_no_title_d' description = _("Full Name D (abbrev., no title)") with_title = False name_options = {'last_name_upper': True, 'abbrev_first_name': True}
class RegistrationAffiliationPlaceholder(RegistrationPDPlaceholder): name = 'affiliation' description = _("Institution") field = 'affiliation'
class RegistrationAmountPlaceholder(RegistrationPlaceholder): name = 'amount' description = _("Amount") field = 'price'
class RegistrationEmailPlaceholder(RegistrationPlaceholder): name = 'email' description = _("E-mail") field = 'email'
class RegistrationLastNamePlaceholder(RegistrationPlaceholder): name = 'last_name' description = _("Last Name") field = 'last_name'
class RegistrationFirstNamePlaceholder(RegistrationPlaceholder): name = 'first_name' description = _("First Name") field = 'first_name'
class RegistrationTitlePlaceholder(RegistrationPDPlaceholder): name = 'title' description = _("Title") field = 'title'
class RegistrationFullNamePlaceholderC(FullNamePlaceholderBase): name = 'full_name_c' description = _("Full Name C") with_title = True name_options = {'last_name_first': False, 'last_name_upper': True}
class RegistrationFullNamePlaceholderB(FullNamePlaceholderBase): name = 'full_name_b' description = _("Full Name B") with_title = True name_options = {'last_name_first': False}
class RegistrationFullNameNoTitlePlaceholderC(FullNamePlaceholderBase): name = 'full_name_no_title_c' description = _("Full Name C (no title)") with_title = False name_options = {'last_name_upper': True}
class RegistrationFullNamePlaceholder(FullNamePlaceholderBase): name = 'full_name' description = _("Full Name") with_title = True name_options = {}
class RegistrationFullNameNoTitlePlaceholderB(FullNamePlaceholderBase): name = 'full_name_b_no_title' description = _("Full Name B (no title)") with_title = False name_options = {'last_name_first': False}
def _extend_admin_menu(sender, **kwargs): if session.user.is_admin: return SideMenuItem('groups', _('Groups'), url_for('groups.groups'), section='user_management')
class RegistrationFullNameNoTitlePlaceholder(FullNamePlaceholderBase): name = 'full_name_no_title' description = _("Full Name (no title)") with_title = False name_options = {}
def validate_url_template(self, field): if field.data and '{value}' not in field.data: raise ValidationError( _("The URL template must contain the placeholder '{value}'."))
'RegistrationFullNamePlaceholderC', 'RegistrationFullNameNoTitlePlaceholderC', 'RegistrationFullNamePlaceholderD', 'RegistrationFullNameNoTitlePlaceholderD', 'RegistrationTitlePlaceholder', 'RegistrationFirstNamePlaceholder', 'RegistrationLastNamePlaceholder', 'RegistrationTicketQRPlaceholder', 'RegistrationEmailPlaceholder', 'RegistrationAmountPlaceholder', 'RegistrationAffiliationPlaceholder', 'RegistrationPositionPlaceholder', 'RegistrationAddressPlaceholder', 'RegistrationCountryPlaceholder', 'RegistrationPhonePlaceholder', 'EventTitlePlaceholder', 'CategoryTitlePlaceholder', 'EventRoomPlaceholder', 'EventVenuePlaceholder', 'EventSpeakersPlaceholder') GROUP_TITLES = {'registrant': _("Registrant Data"), 'event': _("Event Data")} class RegistrationPlaceholder(Placeholder): group = 'registrant' @classmethod def render(cls, registration): return getattr(registration, cls.field) class RegistrationPDPlaceholder(Placeholder): group = 'registrant' @classmethod def render(cls, registration):
def _check_for_correct_filename_template(self, template): if template is not None and '.' in template: raise ValidationError(_('Filename template cannot include dots'))
def validate_category(self, field): if not field.data.can_create_events(session.user): raise ValidationError( _('You are not allowed to create events in this category.'))
def _process_args(self): RHManageCategorySelectedEventsBase._process_args(self) self.target_category = Category.get_one(int(request.form['target_category_id']), is_deleted=False) if not self.target_category.can_create_events(session.user): raise Forbidden(_("You may only move events to categories where you are allowed to create events."))
def _check_for_correct_extensions_format(self, extensions): for extension in extensions: if re.match(r'^[*.]+', extension): raise ValidationError(_('Extensions cannot have leading dots'))
def create_mock_abstract(event): """Create a mock abstract that can be used in previews. Brace for geek references. """ User = namedtuple('Author', ['first_name', 'last_name', 'title', 'full_name']) Track = namedtuple('Track', ['title']) Session = namedtuple('Session', ['title']) ContributionType = namedtuple('ContributionType', ['name']) Contribution = namedtuple('Contribution', ['title', 'track', 'session', 'type', 'locator']) Abstract = namedtuple('Abstract', [ 'friendly_id', 'title', 'event', 'submitter', 'contribution', 'primary_authors', 'secondary_authors', 'locator', 'judgment_comment', 'accepted_track', 'accepted_contrib_type', 'state', 'merged_into' ]) englert = User(full_name="Fran\xe7ois Englert", first_name="Fran\xe7ois", last_name="Englert", title="Prof.") brout = User(full_name="Robert Brout", first_name="Robert", last_name="Brout", title="Prof.") guralnik = User(full_name="Gerald Guralnik", first_name="Gerald", last_name="Guralnik", title="Prof.") hagen = User(full_name="Carl Hagen", first_name="Carl", last_name="Hagen", title="Prof.") kibble = User(full_name="Tom Kibble", first_name="Tom", last_name="Kibble", title="Prof.") higgs = User(full_name="Peter Higgs", first_name="Peter", last_name="Higgs", title="Prof.") track = Track(title=_("Higgs Fields")) session = Session(title=_("Higgs Fields Posters")) contribution_type = ContributionType(name=_("Poster")) contribution = Contribution( title="Broken Symmetry and the Mass of Gauge Vector Mesons", track=track, session=session, type=contribution_type, locator={ 'confId': -314, 'contrib_id': 1234 }) target_abstract = Abstract( friendly_id=315, title="Broken Symmetry", accepted_track=track, accepted_contrib_type=contribution_type, event=event, submitter=brout, state=AbstractState.accepted, contribution=contribution, primary_authors=[englert, brout], secondary_authors=[guralnik, hagen, kibble, higgs], locator={ 'confId': -314, 'abstract_id': 1235 }, judgment_comment='Vague but interesting!', merged_into=None) abstract = Abstract( friendly_id=314, title="Broken Symmetry and the Mass of Gauge Vector Mesons", accepted_track=track, accepted_contrib_type=contribution_type, event=event, submitter=brout, state=AbstractState.accepted, contribution=contribution, primary_authors=[englert, brout], secondary_authors=[guralnik, hagen, kibble, higgs], locator={ 'confId': -314, 'abstract_id': 1234 }, judgment_comment='Vague but interesting!', merged_into=target_abstract) return abstract
class ContributionCloner(EventCloner): name = 'contributions' friendly_name = _('Contributions') requires = {'event_persons', 'sessions', 'contribution_types', 'contribution_fields'} is_internal = True # We do not override `is_available` as we have cloners depending # on this internal cloner even if it won't clone anything. @classmethod @no_autoflush def clone_single_contribution(cls, contribution, preserve_session=False): """Clone a single contribution within the same event. :param contribution: The `Contribution` to clone :param preserve_session: Whether to assign and schedule :return: The newly created contribution """ event = contribution.event cloner = cls(event) cloner._person_map = dict(zip(event.persons, event.persons)) cloner._session_map = {contribution.session: contribution.session} cloner._session_block_map = {contribution.session_block: contribution.session_block} cloner._contrib_type_map = {contribution.type: contribution.type} cloner._contrib_field_map = dict(zip(event.contribution_fields, event.contribution_fields)) cloner._contrib_map = {} cloner._subcontrib_map = {} new_contribution = cloner._create_new_contribution(event, contribution, preserve_session=preserve_session, excluded_attrs={'friendly_id'}) if preserve_session: entry = schedule_contribution(new_contribution, contribution.timetable_entry.start_dt, session_block=new_contribution.session_block) event.timetable_entries.append(entry) db.session.flush() return new_contribution def run(self, new_event, cloners, shared_data): self._person_map = shared_data['event_persons']['person_map'] self._session_map = shared_data['sessions']['session_map'] self._session_block_map = shared_data['sessions']['session_block_map'] self._contrib_type_map = shared_data['contribution_types']['contrib_type_map'] self._contrib_field_map = shared_data['contribution_fields']['contrib_field_map'] self._contrib_map = {} self._subcontrib_map = {} with db.session.no_autoflush: self._clone_contribs(new_event) self._synchronize_friendly_id(new_event) db.session.flush() return {'contrib_map': self._contrib_map, 'subcontrib_map': self._subcontrib_map} def _create_new_contribution(self, event, old_contrib, preserve_session=True, excluded_attrs=None): attrs = (get_simple_column_attrs(Contribution) | {'own_room', 'own_venue'}) - {'abstract_id'} if excluded_attrs is not None: attrs -= excluded_attrs new_contrib = Contribution() new_contrib.populate_from_attrs(old_contrib, attrs) new_contrib.subcontributions = list(self._clone_subcontribs(old_contrib.subcontributions)) new_contrib.acl_entries = clone_principals(ContributionPrincipal, old_contrib.acl_entries) new_contrib.references = list(self._clone_references(ContributionReference, old_contrib.references)) new_contrib.person_links = list(self._clone_person_links(ContributionPersonLink, old_contrib.person_links)) new_contrib.field_values = list(self._clone_fields(old_contrib.field_values)) if old_contrib.type is not None: new_contrib.type = self._contrib_type_map[old_contrib.type] if preserve_session: if old_contrib.session is not None: new_contrib.session = self._session_map[old_contrib.session] if old_contrib.session_block is not None: new_contrib.session_block = self._session_block_map[old_contrib.session_block] event.contributions.append(new_contrib) return new_contrib def _clone_contribs(self, new_event): query = (Contribution.query.with_parent(self.old_event) .options(undefer('_last_friendly_subcontribution_id'), joinedload('own_venue'), joinedload('own_room').lazyload('*'), joinedload('session'), joinedload('session_block').lazyload('session'), joinedload('type'), subqueryload('acl_entries'), subqueryload('subcontributions').joinedload('references'), subqueryload('references'), subqueryload('person_links'), subqueryload('field_values'))) for old_contrib in query: self._contrib_map[old_contrib] = self._create_new_contribution(new_event, old_contrib) def _clone_subcontribs(self, subcontribs): attrs = get_simple_column_attrs(SubContribution) for old_subcontrib in subcontribs: subcontrib = SubContribution() subcontrib.populate_from_attrs(old_subcontrib, attrs) subcontrib.references = list(self._clone_references(SubContributionReference, old_subcontrib.references)) subcontrib.person_links = list(self._clone_person_links(SubContributionPersonLink, old_subcontrib.person_links)) self._subcontrib_map[old_subcontrib] = subcontrib yield subcontrib def _clone_references(self, cls, references): attrs = get_simple_column_attrs(cls) | {'reference_type'} for old_ref in references: ref = cls() ref.populate_from_attrs(old_ref, attrs) yield ref def _clone_person_links(self, cls, person_links): attrs = get_simple_column_attrs(cls) for old_link in person_links: link = cls() link.populate_from_attrs(old_link, attrs) link.person = self._person_map[old_link.person] yield link def _clone_fields(self, fields): attrs = get_simple_column_attrs(ContributionFieldValue) for old_field_value in fields: field_value = ContributionFieldValue() field_value.contribution_field = self._contrib_field_map[old_field_value.contribution_field] field_value.populate_from_attrs(old_field_value, attrs) yield field_value def _synchronize_friendly_id(self, new_event): new_event._last_friendly_contribution_id = ( db.session .query(db.func.max(Contribution.friendly_id)) .filter(Contribution.event_id == new_event.id) .scalar() or 0 )
def _topmenu_items(sender, **kwargs): if session.user and session.user.is_admin: yield TopMenuItem('admin', _('Administration'), url_for('core.admin_dashboard'), 70)
def _process(self): move_category(self.category, self.target_category) flash(_('Category "{}" moved to "{}".').format(self.category.title, self.target_category.title), 'success') return jsonify_data(flash=False)
def __call__(self, form, field): if field.data is not None and field.data > self.max_duration: raise ValidationError(_('Duration cannot exceed {}').format(format_human_timedelta(self.max_duration)))
class SessionForm(IndicoForm): title = StringField(_('Title'), [DataRequired()]) code = StringField( _('Session code'), description=_('The code that will identify the session in the Book of ' 'Abstracts.')) description = TextAreaField(_('Description')) default_contribution_duration = TimeDeltaField( _('Default contribution duration'), units=('minutes', 'hours'), description=_('Duration that a contribution created within this ' 'session will have by default.'), default=timedelta(minutes=20)) location_data = IndicoLocationField( _("Default location"), description=_("Default location for blocks inside the session.")) colors = IndicoPalettePickerField(_('Colours'), color_list=get_colors()) is_poster = BooleanField( _('Poster session'), widget=SwitchWidget(), description= _('Whether the session is a poster session or contains normal presentations.' )) def __init__(self, *args, **kwargs): event = kwargs.pop('event') super(SessionForm, self).__init__(*args, **kwargs) if event.type != 'conference': del self.is_poster del self.code
def _process(self): self.user.reset_signing_secret() flash(_('All your token-based links have been invalidated'), 'success') return redirect(url_for('api.user_profile'))
def __init__(self, fieldname): super().__init__(fieldname, message=_('The passwords do not match.'))
class EventCreationForm(EventCreationFormBase): _field_order = ('title', 'start_dt', 'end_dt', 'timezone', 'location_data', 'protection_mode') _advanced_field_order = () start_dt = IndicoDateTimeField(_("Start"), [InputRequired()], default_time=time(8), allow_clear=False) end_dt = IndicoDateTimeField(_("End"), [InputRequired(), LinkedDateTime('start_dt', not_equal=True)], default_time=time(18), allow_clear=False)
def __call__(self, form, field): if field.data and not is_valid_mail(field.data, self.multi): msg = _('Invalid email address list') if self.multi else _('Invalid email address') raise ValidationError(msg)