def test_scoped_cache(): cache.set('foo', 1) cache.set('foobar', 2) scoped = make_scoped_cache('test') assert scoped.get('foo', 'notset') == 'notset' scoped.set('foo', 'bar') scoped.add('foobar', 'test') scoped.add('foo', 'nope') # accessing the scope through the global cache is possibly, but should not be done # if this ever starts failing because we change something in the cache implementation # removing this particular assertion is fine assert cache.get('test/foo') == 'bar' assert scoped.get('foo') == 'bar' assert scoped.get_many('foo', 'foobar') == ['bar', 'test'] assert scoped.get_dict('foo', 'foobar') == {'foo': 'bar', 'foobar': 'test'} scoped.delete('foobar') scoped.delete_many('foo') assert scoped.get_many('foo', 'foobar') == [None, None] # ensure deletions only affected the scoped keys assert cache.get_many('foo', 'foobar') == [1, 2] scoped.set_many({'a': 'aa', 'b': 'bb'}) assert scoped.get_dict('a', 'b') == {'a': 'aa', 'b': 'bb'} assert cache.get_many('foo', 'foobar', 'a', 'b') == [1, 2, None, None]
def _send_confirmation(self, email): token_storage = make_scoped_cache('confirm-email') data = {'email': email, 'user_id': self.user.id} token = make_unique_token(lambda t: not token_storage.get(t)) token_storage.set(token, data, timeout=86400) send_email(make_email(email, template=get_template_module('users/emails/verify_email.txt', user=self.user, email=email, token=token)))
class RHUserEmailsVerify(RHUserBase): flash_user_status = False token_storage = make_scoped_cache('confirm-email') def _validate(self, data): if not data: flash(_('The verification token is invalid or expired.'), 'error') return False, None user = User.get(data['user_id']) if not user or user != self.user: flash( _('This token is for a different Indico user. Please login with the correct account' ), 'error') return False, None existing = UserEmail.query.filter_by(is_user_deleted=False, email=data['email']).first() if existing and not existing.user.is_pending: if existing.user == self.user: flash( _('This email address is already attached to your account.' )) else: flash( _('This email address is already in use by another account.' ), 'error') return False, existing.user return True, existing.user if existing else None def _process(self): token = request.view_args['token'] data = self.token_storage.get(token) valid, existing = self._validate(data) if valid: self.token_storage.delete(token) if existing and existing.is_pending: logger.info("Found pending user %s to be merged into %s", existing, self.user) # If the pending user has missing names, copy them from the active one # to allow it to be marked as not pending and deleted during the merge. existing.first_name = existing.first_name or self.user.first_name existing.last_name = existing.last_name or self.user.last_name merge_users(existing, self.user) flash( _("Merged data from existing '{}' identity").format( existing.email)) existing.is_pending = False self.user.secondary_emails.add(data['email']) signals.users.email_added.send(self.user, email=data['email']) flash( _('The email address {email} has been added to your account.'). format(email=data['email']), 'success') return redirect(url_for('.user_emails'))
def test_expiry(freeze_time, scoped, timeout): now = datetime.now() freeze_time(now) cache_obj = make_scoped_cache('test') if scoped else cache cache_obj.set('a', 1, timeout=timeout) cache_obj.add('b', 2, timeout=timeout) cache_obj.set_many({'c': 3}, timeout=timeout) assert cache_obj.get_many('a', 'b', 'c') == [1, 2, 3] freeze_time(now + timedelta(seconds=4)) assert cache_obj.get_many('a', 'b', 'c') == [1, 2, 3] freeze_time(now + timedelta(seconds=5)) assert cache_obj.get_many('a', 'b', 'c') == [None, None, None]
def _get_person_link(self, data): from indico.modules.events.persons.schemas import PersonLinkSchema identifier = data.get('identifier') data = PersonLinkSchema(unknown=EXCLUDE).load(data) if identifier and identifier.startswith('ExternalUser:'******'external-user') external_user_data = cache.get( identifier.removeprefix('ExternalUser:'******'affiliation_data')) and data['affiliation'] == affiliation_data['name']): data['affiliation_link'] = Affiliation.get_or_create_from_data( affiliation_data) data['affiliation'] = data['affiliation_link'].name
def get(cls, *args, **kwargs): """Create and return a serializable Report object, retrieved from cache if possible""" from indico_piwik.plugin import PiwikPlugin if not PiwikPlugin.settings.get('cache_enabled'): return cls(*args, **kwargs).serialize() cache = make_scoped_cache('piwik-report') key = f'{cls.__name__}-{args}-{kwargs}' report = cache.get(key) if not report: report = cls(*args, **kwargs) cache.set(key, report, timeout=PiwikPlugin.settings.get('cache_ttl')) return report.serialize()
def memoize_redis(ttl): """Memoize a function in redis. The cached value can be cleared by calling the method ``clear_cached()`` of the decorated function with the same arguments that were used during the function call. To check whether a value has been cached call ``is_cached()`` in the same way. :param ttl: How long the result should be cached. May be a timedelta or a number (seconds). """ from indico.core.cache import make_scoped_cache cache = make_scoped_cache('memoize') def decorator(f): def _get_key(args, kwargs): return f.__module__, f.__name__, make_hashable( getcallargs(f, *args, **kwargs)) def _clear_cached(*args, **kwargs): cache.delete(_get_key(args, kwargs)) def _is_cached(*args, **kwargs): return cache.get(_get_key(args, kwargs), _notset) is not _notset @wraps(f) def memoizer(*args, **kwargs): if current_app.config['TESTING'] or current_app.config.get('REPL'): # No memoization during tests or in the shell return f(*args, **kwargs) key = _get_key(args, kwargs) value = cache.get(key, _notset) if value is _notset: value = f(*args, **kwargs) cache.set(key, value, timeout=ttl) return value memoizer.clear_cached = _clear_cached memoizer.is_cached = _is_cached return memoizer return decorator
class OAuthGrant: """OAuth grant token.""" #: cache entry to store grant tokens _cache = make_scoped_cache('oauth-grant-tokens') def __init__(self, client_id, code, redirect_uri, user, scopes, expires): self.client_id = client_id self.code = code self.redirect_uri = redirect_uri self.user = user self.scopes = scopes self.expires = expires @property def key(self): return self.make_key(self.client_id, self.code) @property def ttl(self): return self.expires - datetime.utcnow() @classmethod def get(cls, client_id, code): key = cls.make_key(client_id, code) return cls._cache.get(key) @classmethod def make_key(cls, client_id, code): return f'{client_id}:{code}' def delete(self): self._cache.delete(self.key) def save(self): self._cache.set(self.key, self, timeout=self.ttl)
def test_expiry(scoped, timeout): cache_obj = make_scoped_cache('test') if scoped else cache cache_obj.set('a', 1, timeout=timeout) cache_obj.add('b', 2, timeout=timeout) cache_obj.set_many({'c': 3}, timeout=timeout) assert cache_obj.get_many('a', 'b', 'c') == [1, 2, 3]
from packaging.version import InvalidVersion, Version import indico from indico.core.cache import make_scoped_cache from indico.core.celery import celery from indico.core.config import config from indico.core.db import db from indico.core.db.sqlalchemy.util.queries import get_postgres_version from indico.core.logger import Logger from indico.core.marshmallow import mm from indico.util.caching import memoize_request from indico.util.string import render_markdown from indico.web.flask.templating import template_hook logger = Logger.get('notices') notices_cache = make_scoped_cache('notices') class NoticeSeverity(str, Enum): highlight = 'highlight' warning = 'warning' error = 'error' @dataclass(frozen=True) class SystemNoticeCriteria: python_version: t.Optional[str] = None postgres_version: t.Optional[str] = None indico_version: t.Optional[str] = None
import indico from indico.core import signals from indico.core.cache import make_scoped_cache from indico.core.config import config from indico.core.db import db from indico.core.plugins import url_for_plugin from indico.modules.events.layout import layout_settings from indico.modules.events.layout.models.menu import MenuEntry, MenuEntryType, TransientMenuEntry from indico.util.caching import memoize_request from indico.util.signals import named_objects_from_signal, values_from_signal from indico.util.string import crc32 from indico.web.flask.util import url_for _cache = make_scoped_cache('updated-menus') def _menu_entry_key(entry_data): return entry_data.position == -1, entry_data.position, entry_data.name @memoize_request def get_menu_entries_from_signal(): return named_objects_from_signal(signals.event.sidemenu.send(), plugin_attr='plugin') def build_menu_entry_name(name, plugin=None): """Build the proper name for a menu entry. Given a menu entry's name and optionally a plugin, returns the
RHEditablesBase, RHEditableTypeEditorBase, RHEditableTypeManagementBase) from indico.modules.events.editing.models.editable import Editable from indico.modules.events.editing.models.revision_files import EditingRevisionFile from indico.modules.events.editing.models.revisions import EditingRevision from indico.modules.events.editing.operations import (assign_editor, generate_editables_json, generate_editables_zip, unassign_editor) from indico.modules.events.editing.schemas import EditableBasicSchema, EditingEditableListSchema, FilteredEditableSchema from indico.modules.files.models.files import File from indico.util.i18n import _ from indico.util.marshmallow import Principal from indico.web.args import use_kwargs from indico.web.flask.util import url_for archive_cache = make_scoped_cache('editables-archive') class RHEditableList(RHEditableTypeEditorBase): """Return the list of editables of the event for a given type.""" def _process_args(self): RHEditableTypeEditorBase._process_args(self) self.contributions = (Contribution.query.with_parent( self.event).options(joinedload('editables')).order_by( Contribution.friendly_id).all()) def _process(self): return (EditingEditableListSchema(many=True, context={ 'editable_type': self.editable_type
from warnings import warn from flask_multipass import MultipassException from werkzeug.utils import cached_property from indico.core.auth import multipass from indico.core.cache import make_scoped_cache from indico.core.config import config from indico.core.db import db from indico.core.db.sqlalchemy.principals import PrincipalType from indico.modules.auth import Identity from indico.modules.groups.models.groups import LocalGroup from indico.util.caching import memoize_request group_membership_cache = make_scoped_cache('group-membership') class GroupProxy: """Provide a generic interface for both local and multipass groups. Creating an instance of this class actually creates either a ``LocalGroupProxy`` or a ``MultipassGroupProxy``, but they expose the same API. :param name_or_id: The name of a multipass group or ID of a local group :param provider: The provider of a multipass group """ principal_order = 3
# This file is part of Indico. # Copyright (C) 2002 - 2021 CERN # # Indico is free software; you can redistribute it and/or # modify it under the terms of the MIT License; see the # LICENSE file for more details. from authlib.oauth2.rfc6749 import InvalidScopeError, scope_to_list from authlib.oauth2.rfc6749.grants import AuthorizationCodeGrant from authlib.oauth2.rfc7636.challenge import CodeChallenge from indico.core.cache import make_scoped_cache from indico.core.oauth.models.tokens import OAuth2AuthorizationCode from indico.modules.users import User auth_code_store = make_scoped_cache('oauth-grant-tokens') class IndicoAuthorizationCodeGrant(AuthorizationCodeGrant): TOKEN_ENDPOINT_AUTH_METHODS = ('client_secret_basic', 'client_secret_post', 'none') def save_authorization_code(self, code, request): code_challenge = request.data.get('code_challenge') code_challenge_method = request.data.get('code_challenge_method') auth_code = OAuth2AuthorizationCode( code=code, client_id=request.client.client_id, redirect_uri=request.redirect_uri, scope=request.scope, user_id=request.user.id,
from indico.core.cache import make_scoped_cache from indico.core.db import db from indico.core.logger import Logger from indico.modules.api import APIMode, api_settings from indico.modules.api.models.keys import APIKey from indico.modules.oauth import oauth from indico.modules.oauth.provider import load_token from indico.web.http_api import HTTPAPIHook from indico.web.http_api.metadata.serializer import Serializer from indico.web.http_api.responses import HTTPAPIError, HTTPAPIResult, HTTPAPIResultSchema from indico.web.http_api.util import get_query_parameter # Remove the extension at the end or before the querystring RE_REMOVE_EXTENSION = re.compile(r'\.(\w+)(?:$|(?=\?))') API_CACHE = make_scoped_cache('legacy-http-api') def normalizeQuery(path, query, remove=('signature', ), separate=False): """Normalize request path and query so it can be used for caching and signing. Returns a string consisting of path and sorted query string. Dynamic arguments like signature and timestamp are removed from the query string. """ qparams = parse_qs(query) sorted_params = [] for key, values in sorted(list(qparams.items()), key=lambda x: x[0].lower()): key = key.lower() if key not in remove:
from indico.modules.events.timetable.forms import ImportContributionsForm from indico.modules.events.timetable.operations import update_timetable_entry from indico.modules.events.tracks.models.tracks import Track from indico.modules.events.util import check_event_locked, get_field_values, track_location_changes, track_time_changes from indico.modules.logs import EventLogRealm, LogKind from indico.util.date_time import format_datetime, format_human_timedelta from indico.util.i18n import _, ngettext from indico.util.spreadsheets import send_csv, send_xlsx from indico.util.string import handle_legacy_description from indico.web.flask.templating import get_template_module from indico.web.flask.util import send_file, url_for from indico.web.forms.base import FormDefaults from indico.web.forms.fields.principals import serialize_principal from indico.web.util import jsonify_data, jsonify_form, jsonify_template export_list_cache = make_scoped_cache('contrib-export-list') def _render_subcontribution_list(contrib): tpl = get_template_module( 'events/contributions/management/_subcontribution_list.html') subcontribs = (SubContribution.query.with_parent(contrib).options( undefer('attachment_count')).order_by(SubContribution.position).all()) return tpl.render_subcontribution_list(contrib.event, contrib, subcontribs) class RHManageContributionsBase(RHManageEventBase): """Base class for all contributions management RHs.""" def _process_args(self): RHManageEventBase._process_args(self) self.list_generator = ContributionListGenerator(event=self.event)
def __init__(self): self.storage = make_scoped_cache('flask-session')
get_ticket_attachments, get_title_uuid, get_user_data, import_registrations_from_csv, make_registration_schema) from indico.modules.events.registration.views import WPManageRegistration from indico.modules.events.util import ZipGeneratorMixin from indico.modules.logs import LogKind from indico.util.fs import secure_filename from indico.util.i18n import _, ngettext from indico.util.marshmallow import Principal from indico.util.placeholders import replace_placeholders from indico.util.spreadsheets import send_csv, send_xlsx from indico.web.args import parser, use_kwargs from indico.web.flask.templating import get_template_module from indico.web.flask.util import send_file, url_for from indico.web.util import jsonify_data, jsonify_form, jsonify_template badge_cache = make_scoped_cache('badge-printing') def _render_registration_details(registration): from indico.modules.events.registration.schemas import RegistrationTagSchema event = registration.registration_form.event tpl = get_template_module( 'events/registration/management/_registration_details.html') schema = RegistrationTagSchema(many=True) assigned_tags = schema.dump(registration.tags) all_tags = schema.dump(event.registration_tags) return tpl.render_registration_details( registration=registration,
from indico.modules.events.models.series import EventSeries from indico.modules.events.notifications import notify_event_creation from indico.modules.events.operations import create_event from indico.modules.rb import rb_settings from indico.modules.rb.util import rb_check_user_access from indico.util.date_time import now_utc from indico.util.iterables import materialize_iterable from indico.util.marshmallow import NaiveDateTime from indico.web.args import use_kwargs from indico.web.flask.util import url_for from indico.web.forms.base import FormDefaults from indico.web.rh import RH, RHProtected from indico.web.util import jsonify_data, jsonify_template, url_for_index prepared_event_data_store = make_scoped_cache('event-preparation') class RHCreateEvent(RHProtected): """Create a new event.""" def _process_args(self): self.event_type = EventType[request.view_args['event_type']] self.root_category = Category.get_root() def _has_only_subcategories(self, category): return category.has_children and not category.has_events @cached_property def _default_category(self): try:
def __init__(self, duration=DEFAULT_CACHE_TTL): self._cache = make_scoped_cache('zeep') self._duration = duration
import uuid from flask import request from werkzeug.exceptions import Forbidden, NotFound from indico.core.cache import make_scoped_cache from indico.modules.designer.models.templates import DesignerTemplate from indico.modules.events.management.controllers import RHManageEventBase from indico.modules.events.management.forms import PosterPrintingForm from indico.modules.events.posters import PosterPDF from indico.util.i18n import _ from indico.web.flask.util import send_file, url_for from indico.web.util import jsonify_data, jsonify_form poster_cache = make_scoped_cache('poster-printing') class RHPosterPrintSettings(RHManageEventBase): ALLOW_LOCKED = True def _process_args(self): RHManageEventBase._process_args(self) self.template_id = request.args.get('template_id') def _process(self): self.commit = False form = PosterPrintingForm(self.event, template=self.template_id) if form.validate_on_submit(): data = dict(form.data) template_id = data.pop('template')
def principal_from_identifier(identifier, allow_groups=False, allow_external_users=False, allow_event_roles=False, allow_category_roles=False, allow_registration_forms=False, allow_emails=False, allow_networks=False, event_id=None, category_id=None, soft_fail=False): from indico.modules.categories.models.categories import Category from indico.modules.categories.models.roles import CategoryRole from indico.modules.events.models.events import Event from indico.modules.events.models.roles import EventRole from indico.modules.events.registration.models.forms import RegistrationForm from indico.modules.groups import GroupProxy from indico.modules.networks.models.networks import IPNetworkGroup from indico.modules.users import User if allow_category_roles and category_id is None and event_id is None: raise ValueError('Cannot use category roles without a category/event context') if allow_event_roles and event_id is None: raise ValueError('Cannot use event roles without an event context') if allow_registration_forms and event_id is None: raise ValueError('Cannot use registration forms without an event context') try: type_, data = identifier.split(':', 1) except ValueError: raise ValueError('Invalid data') if type_ == 'User': try: user_id = int(data) except ValueError: raise ValueError('Invalid data') user = User.get(user_id, is_deleted=(None if soft_fail else False)) if user is None: raise ValueError(f'Invalid user: {user_id}') return user elif type_ == 'ExternalUser': if not allow_external_users: raise ValueError('External users are not allowed') cache = make_scoped_cache('external-user') external_user_data = cache.get(data) if not external_user_data: raise ValueError('Invalid data') user = User.query.filter(User.all_emails == external_user_data['email'], ~User.is_deleted).first() if user: return user # create a pending user. this user isn't sent to the DB unless it gets added # to the sqlalchemy session somehow (e.g. by adding it to an ACL). # like this processing form data does not result in something being stored in # the database, which is good! return User(first_name=external_user_data['first_name'], last_name=external_user_data['last_name'], email=external_user_data['email'], affiliation=external_user_data['affiliation'], address=external_user_data['address'], phone=external_user_data['phone'], is_pending=True) elif type_ == 'Group': if not allow_groups: raise ValueError('Groups are not allowed') try: provider, name = data.split(':', 1) except ValueError: raise ValueError('Invalid data') if not provider: # local group try: group_id = int(name) except ValueError: raise ValueError('Invalid data') group = GroupProxy(group_id) else: # multipass group group = GroupProxy(name, provider) if not soft_fail and group.group is None: raise ValueError(f'Invalid group: {data}') return group elif type_ == 'EventRole': if not allow_event_roles: raise ValueError('Event roles are not allowed') try: event_role_id = int(data) except ValueError: raise ValueError('Invalid data') event_role = EventRole.get(event_role_id) if event_role is None or event_role.event_id != event_id: raise ValueError(f'Invalid event role: {event_role_id}') return event_role elif type_ == 'CategoryRole': if not allow_category_roles: raise ValueError('Category roles are not allowed') category = None if category_id is not None: category = Category.get(category_id) if category is None: raise ValueError(f'Invalid category id: {category_id}') elif event_id is not None: event = Event.get(event_id) if event is None: raise ValueError(f'Invalid event id: {event_id}') category = event.category try: category_role_id = int(data) except ValueError: raise ValueError('Invalid data') if soft_fail: category_role = CategoryRole.get(category_role_id) else: category_role = CategoryRole.get_category_role_by_id(category, category_role_id) if category_role is None: raise ValueError(f'Invalid category role: {category_role_id}') return category_role elif type_ == 'RegistrationForm': if not allow_registration_forms: raise ValueError('Registration forms are not allowed') try: reg_form_id = int(data) except ValueError: raise ValueError('Invalid data') registration_form = RegistrationForm.get(reg_form_id, is_deleted=(None if soft_fail else False)) if registration_form is None or registration_form.event_id != event_id: raise ValueError(f'Invalid registration form: {reg_form_id}') return registration_form elif type_ == 'Email': if not allow_emails: raise ValueError('Emails are not allowed') return EmailPrincipal(data) elif type_ == 'IPNetworkGroup': if not allow_networks: raise ValueError('Network groups are not allowed') try: netgroup_id = int(data) except ValueError: raise ValueError('Invalid data') netgroup = IPNetworkGroup.get(netgroup_id) if netgroup is None or (netgroup.hidden and not soft_fail): raise ValueError(f'Invalid network group: {netgroup_id}') return netgroup else: raise ValueError('Invalid data')
# LICENSE file for more details. import traceback from uuid import uuid4 from flask import g, jsonify, render_template, request, session from itsdangerous import BadData from sqlalchemy.exc import OperationalError from werkzeug.exceptions import Forbidden, HTTPException from indico.core.cache import make_scoped_cache from indico.core.errors import NoReportError from indico.web.util import get_request_info from indico.web.views import WPError error_cache = make_scoped_cache('errors') def render_error(exc, title, message, code, standalone=False): _save_error(exc, title, message) if _need_json_response(): return _jsonify_error(exc, title, message, code) elif standalone: return render_template('standalone_error.html', error_message=title, error_description=message), code else: try: return WPError(title, message).getHTML(), code except OperationalError: # If the error was caused while connecting the database,
def _process_pending_users(self, results): cache = make_scoped_cache('external-user') for entry in results: ext_id = entry.pop('_ext_id', None) if ext_id is not None: cache.set(ext_id, self.externals[ext_id], timeout=86400)
from indico.core import signals from indico.core.cache import make_scoped_cache from indico.core.config import config from indico.core.logger import Logger from indico.core.permissions import ManagementPermission, check_permissions from indico.core.settings import SettingsProxy from indico.core.settings.converters import ModelListConverter from indico.modules.categories.models.categories import Category from indico.modules.rb.models.rooms import Room from indico.util.i18n import _ from indico.web.flask.util import url_for from indico.web.menu import SideMenuItem, TopMenuItem logger = Logger.get('rb') rb_cache = make_scoped_cache('roombooking') rb_settings = SettingsProxy( 'roombooking', { 'managers_edit_rooms': False, 'excluded_categories': [], 'notification_before_days': 2, 'notification_before_days_weekly': 5, 'notification_before_days_monthly': 7, 'notifications_enabled': True, 'end_notification_daily': 1, 'end_notification_weekly': 3, 'end_notification_monthly': 7, 'end_notifications_enabled': True, 'booking_limit': 365, 'tileserver_url': None,
reservation_user_event_schema) from indico.modules.rb.util import ( generate_spreadsheet_from_occurrences, get_linked_object, get_prebooking_collisions, group_by_occurrence_date, is_booking_start_within_grace_period, serialize_availability, serialize_booking_details, serialize_occurrences) from indico.util.date_time import now_utc, utc_to_server from indico.util.i18n import _ from indico.util.spreadsheets import send_csv, send_xlsx from indico.web.args import use_args, use_kwargs from indico.web.flask.util import url_for from indico.web.util import ExpectedError NUM_SUGGESTIONS = 5 _export_cache = make_scoped_cache('bookings-export') class RHTimeline(RHRoomBookingBase): def _process_args(self): self.room = None if 'room_id' in request.view_args: self.room = Room.get_or_404(request.view_args['room_id'], is_deleted=False) @use_kwargs( { 'start_dt': fields.DateTime(required=True), 'end_dt': fields.DateTime(required=True), 'repeat_frequency': EnumField(RepeatFrequency, load_default='NEVER'),
def principal_from_identifier(identifier, allow_groups=False, allow_external_users=False, allow_event_roles=False, allow_category_roles=False, allow_registration_forms=False, allow_emails=False, allow_networks=False, event_id=None, category_id=None, soft_fail=False): from indico.modules.categories.models.categories import Category from indico.modules.categories.models.roles import CategoryRole from indico.modules.events.models.events import Event from indico.modules.events.models.roles import EventRole from indico.modules.events.registration.models.forms import RegistrationForm from indico.modules.groups import GroupProxy from indico.modules.networks.models.networks import IPNetworkGroup from indico.modules.users import User from indico.modules.users.models.affiliations import Affiliation from indico.modules.users.models.users import UserTitle if allow_category_roles and category_id is None and event_id is None: raise ValueError( 'Cannot use category roles without a category/event context') if allow_event_roles and event_id is None: raise ValueError('Cannot use event roles without an event context') if allow_registration_forms and event_id is None: raise ValueError( 'Cannot use registration forms without an event context') try: type_, data = identifier.split(':', 1) except ValueError: raise ValueError('Invalid data') if type_ == 'User': try: user_id = int(data) except ValueError: raise ValueError('Invalid data') user = User.get(user_id, is_deleted=(None if soft_fail else False)) if user is None: raise ValueError(f'Invalid user: {user_id}') return user elif type_ == 'ExternalUser': if not allow_external_users: raise ValueError('External users are not allowed') cache = make_scoped_cache('external-user') external_user_data = cache.get(data) if not external_user_data: raise ValueError('Invalid data') user = User.query.filter( User.all_emails == external_user_data['email'], ~User.is_deleted).first() if user: return user # create a pending user. this user isn't sent to the DB unless it gets added # to the sqlalchemy session somehow (e.g. by adding it to an ACL). # like this processing form data does not result in something being stored in # the database, which is good! user = User(first_name=external_user_data['first_name'], last_name=external_user_data['last_name'], email=external_user_data['email'], affiliation=external_user_data['affiliation'], address=external_user_data['address'], phone=external_user_data['phone'], _title=UserTitle.none, is_pending=True) if affiliation_data := external_user_data.get('affiliation_data'): user._affiliation.affiliation_link = Affiliation.get_or_create_from_data( affiliation_data) user._affiliation.name = user._affiliation.affiliation_link.name return user
# This file is part of Indico. # Copyright (C) 2002 - 2021 CERN # # Indico is free software; you can redistribute it and/or # modify it under the terms of the MIT License; see the # LICENSE file for more details. from functools import wraps from celery import current_task from indico.core.cache import make_scoped_cache from indico.core.logger import Logger _lock_cache = make_scoped_cache('task-locks') def locked_task(f): """Decorator to prevent a task from running multiple times at once.""" @wraps(f) def wrapper(*args, **kwargs): name = current_task.name if _lock_cache.get(name): Logger.get('celery').warning( 'Task %s is locked; not executing it. ' 'To manually unlock it, run `indico celery unlock %s`', name, name) return _lock_cache.set(name, True, 86400) try: return f(*args, **kwargs)
# This file is part of the CERN Indico plugins. # Copyright (C) 2014 - 2021 CERN # # The CERN Indico plugins are free software; you can redistribute # them and/or modify them under the terms of the MIT License; see # the LICENSE file for more details. from indico.core.cache import make_scoped_cache from indico.util.i18n import make_bound_gettext _ = make_bound_gettext('conversion') pdf_state_cache = make_scoped_cache('pdf-conversion')