def search_users(exact=False, include_deleted=False, include_pending=False, external=False, allow_system_user=False, **criteria): """Searches for users. :param exact: Indicates if only exact matches should be returned. This is MUCH faster than a non-exact saerch, especially when searching external users. :param include_deleted: Indicates if also users marked as deleted should be returned. :param include_pending: Indicates if also users who are still pending should be returned. :param external: Indicates if identity providers should be searched for matching users. :param allow_system_user: Whether the system user may be returned in the search results. :param criteria: A dict containing any of the following keys: name, first_name, last_name, email, affiliation, phone, address :return: A set of matching users. If `external` was set, it may contain both :class:`~flask_multipass.IdentityInfo` objects for external users not yet in Indico and :class:`.User` objects for existing users. """ criteria = {key: value.strip() for key, value in criteria.iteritems() if value.strip()} if not criteria: return set() query = (build_user_search_query(dict(criteria), exact=exact, include_deleted=include_deleted, include_pending=include_pending) .options(db.joinedload(User.identities), db.joinedload(User.merged_into_user))) found_emails = {} found_identities = {} system_user = set() for user in query: for identity in user.identities: found_identities[(identity.provider, identity.identifier)] = user for email in user.all_emails: found_emails[email] = user if user.is_system and not user.all_emails and allow_system_user: system_user = {user} # external user providers if external: identities = multipass.search_identities(exact=exact, **criteria) for ident in identities: if not ident.data.get('email'): # Skip users with no email continue if ((ident.provider.name, ident.identifier) not in found_identities and ident.data['email'].lower() not in found_emails): found_emails[ident.data['email'].lower()] = ident found_identities[(ident.provider, ident.identifier)] = ident return set(found_emails.viewvalues()) | system_user
def search_users(exact=False, include_deleted=False, include_pending=False, external=False, **criteria): unspecified = object() query = User.query.options(db.joinedload(User.identities), db.joinedload(User._all_emails), db.joinedload(User.merged_into_user)) original_criteria = dict(criteria) if not criteria: return set() if not include_pending: query = query.filter(~User.is_pending) if not include_deleted: query = query.filter(~User.is_deleted) organisation = criteria.pop('affiliation', unspecified) if organisation is not unspecified: query = query.join(UserAffiliation).filter(_build_match(UserAffiliation.name, organisation, exact)) email = criteria.pop('email', unspecified) if email is not unspecified: query = query.join(UserEmail).filter(_build_match(UserEmail.email, email, exact)) for k, v in criteria.iteritems(): query = query.filter(_build_match(getattr(User, k), v, exact)) found_emails = {} found_identities = {} for user in query: for identity in user.identities: found_identities[(identity.provider, identity.identifier)] = user for email in user.all_emails: found_emails[email] = user # external user providers if external: from indico.core.auth import multipass identities = multipass.search_identities(exact=exact, **original_criteria) for ident in identities: if ((ident.provider.name, ident.identifier) not in found_identities and ident.data['email'].lower() not in found_emails): found_emails[ident.data['email'].lower()] = ident found_identities[(ident.provider, ident.identifier)] = ident return set(found_emails.viewvalues())
def iter_identifiers(self, check_providers=False, providers=None): """Yields ``(provider, identifier)`` tuples for the user. :param check_providers: If True, providers are searched for additional identifiers once all existing identifiers have been yielded. :param providers: May be a set containing provider names to get only identifiers from the specified providers. """ done = set() for identity in self.identities: if providers is not None and identity.provider not in providers: continue item = (identity.provider, identity.identifier) done.add(item) yield item if not check_providers: return for identity_info in multipass.search_identities(providers=providers, exact=True, email=self.all_emails): item = (identity_info.provider.name, identity_info.identifier) if item not in done: yield item
def search_users(exact=False, include_deleted=False, include_pending=False, external=False, **criteria): """Searches for users. :param exact: Indicates if only exact matches should be returned. This is MUCH faster than a non-exact saerch, especially when searching external users. :param include_deleted: Indicates if also users marked as deleted should be returned. :param include_pending: Indicates if also users who are still pending should be returned. :param external: Indicates if identity providers should be searched for matching users. :param criteria: A dict containing any of the following keys: first_name, last_name, email, affiliation, phone, address :return: A set of matching users. If `external` was set, it may contain both :class:`~flask_multipass.IdentityInfo` objects for external users not yet in Indico and :class:`.User` objects for existing users. """ unspecified = object() query = User.query.options(db.joinedload(User.identities), db.joinedload(User._all_emails), db.joinedload(User.merged_into_user)) criteria = { key: value.strip() for key, value in criteria.iteritems() if value.strip() } original_criteria = dict(criteria) if not criteria: return set() if not include_pending: query = query.filter(~User.is_pending) if not include_deleted: query = query.filter(~User.is_deleted) organisation = criteria.pop('affiliation', unspecified) if organisation is not unspecified: query = query.join(UserAffiliation).filter( unaccent_match(UserAffiliation.name, organisation, exact)) email = criteria.pop('email', unspecified) if email is not unspecified: query = query.join(UserEmail).filter( unaccent_match(UserEmail.email, email, exact)) for k, v in criteria.iteritems(): query = query.filter(unaccent_match(getattr(User, k), v, exact)) found_emails = {} found_identities = {} for user in query: for identity in user.identities: found_identities[(identity.provider, identity.identifier)] = user for email in user.all_emails: found_emails[email] = user # external user providers if external: identities = multipass.search_identities(exact=exact, **original_criteria) for ident in identities: if not ident.data.get('email'): # Skip users with no email continue if ((ident.provider.name, ident.identifier) not in found_identities and ident.data['email'].lower() not in found_emails): found_emails[ident.data['email'].lower()] = ident found_identities[(ident.provider, ident.identifier)] = ident return set(found_emails.viewvalues())
def search_users(exact=False, include_deleted=False, include_pending=False, external=False, **criteria): """Searches for users. :param exact: Indicates if only exact matches should be returned. This is MUCH faster than a non-exact saerch, especially when searching external users. :param include_deleted: Indicates if also users marked as deleted should be returned. :param include_pending: Indicates if also users who are still pending should be returned. :param external: Indicates if identity providers should be searched for matching users. :param criteria: A dict containing any of the following keys: first_name, last_name, email, affiliation, phone, address :return: A set of matching users. If `external` was set, it may contain both :class:`~flask_multipass.IdentityInfo` objects for external users not yet in Indico and :class:`.User` objects for existing users. """ unspecified = object() query = User.query.options(db.joinedload(User.identities), db.joinedload(User._all_emails), db.joinedload(User.merged_into_user)) criteria = {key: value.strip() for key, value in criteria.iteritems() if value.strip()} original_criteria = dict(criteria) if not criteria: return set() if not include_pending: query = query.filter(~User.is_pending) if not include_deleted: query = query.filter(~User.is_deleted) organisation = criteria.pop('affiliation', unspecified) if organisation is not unspecified: query = query.join(UserAffiliation).filter(unaccent_match(UserAffiliation.name, organisation, exact)) email = criteria.pop('email', unspecified) if email is not unspecified: query = query.join(UserEmail).filter(unaccent_match(UserEmail.email, email, exact)) for k, v in criteria.iteritems(): query = query.filter(unaccent_match(getattr(User, k), v, exact)) found_emails = {} found_identities = {} for user in query: for identity in user.identities: found_identities[(identity.provider, identity.identifier)] = user for email in user.all_emails: found_emails[email] = user # external user providers if external: identities = multipass.search_identities(exact=exact, **original_criteria) for ident in identities: if not ident.data.get('email'): # Skip users with no email continue if ((ident.provider.name, ident.identifier) not in found_identities and ident.data['email'].lower() not in found_emails): found_emails[ident.data['email'].lower()] = ident found_identities[(ident.provider, ident.identifier)] = ident return set(found_emails.viewvalues())
def search_users(exact=False, include_deleted=False, include_pending=False, external=False, allow_system_user=False, **criteria): """Searches for users. :param exact: Indicates if only exact matches should be returned. This is MUCH faster than a non-exact saerch, especially when searching external users. :param include_deleted: Indicates if also users marked as deleted should be returned. :param include_pending: Indicates if also users who are still pending should be returned. :param external: Indicates if identity providers should be searched for matching users. :param allow_system_user: Whether the system user may be returned in the search results. :param criteria: A dict containing any of the following keys: name, first_name, last_name, email, affiliation, phone, address :return: A set of matching users. If `external` was set, it may contain both :class:`~flask_multipass.IdentityInfo` objects for external users not yet in Indico and :class:`.User` objects for existing users. """ criteria = {key: value.strip() for key, value in criteria.iteritems() if value.strip()} if not criteria: return set() query = (build_user_search_query( dict(criteria), exact=exact, include_deleted=include_deleted, include_pending=include_pending) .options(db.joinedload(User.identities), db.joinedload(User.merged_into_user))) found_emails = {} found_identities = {} system_user = set() for user in query: for identity in user.identities: found_identities[(identity.provider, identity.identifier)] = user for email in user.all_emails: found_emails[email] = user if user.is_system and not user.all_emails and allow_system_user: system_user = {user} # external user providers if external: identities = multipass.search_identities(exact=exact, **criteria) for ident in identities: if not ident.data.get('email'): # Skip users with no email continue if ((ident.provider.name, ident.identifier) not in found_identities and ident.data['email'].lower() not in found_emails): found_emails[ident.data['email'].lower()] = ident found_identities[(ident.provider, ident.identifier)] = ident return set(found_emails.viewvalues()) | system_user
def search_users(exact=False, include_deleted=False, include_pending=False, external=False, allow_system_user=False, **criteria): """Searches for users. :param exact: Indicates if only exact matches should be returned. This is MUCH faster than a non-exact saerch, especially when searching external users. :param include_deleted: Indicates if also users marked as deleted should be returned. :param include_pending: Indicates if also users who are still pending should be returned. :param external: Indicates if identity providers should be searched for matching users. :param allow_system_user: Whether the system user may be returned in the search results. :param criteria: A dict containing any of the following keys: first_name, last_name, email, affiliation, phone, address :return: A set of matching users. If `external` was set, it may contain both :class:`~flask_multipass.IdentityInfo` objects for external users not yet in Indico and :class:`.User` objects for existing users. """ unspecified = object() query = User.query.options(db.joinedload(User.identities), db.joinedload(User._all_emails), db.joinedload(User.merged_into_user)) criteria = { key: value.strip() for key, value in criteria.iteritems() if value.strip() } original_criteria = dict(criteria) if not criteria: return set() if not include_pending: query = query.filter(~User.is_pending) if not include_deleted: query = query.filter(~User.is_deleted) affiliation = criteria.pop('affiliation', unspecified) if affiliation is not unspecified: query = query.join(UserAffiliation).filter( unaccent_match(UserAffiliation.name, affiliation, exact)) email = criteria.pop('email', unspecified) if email is not unspecified: query = query.join(UserEmail).filter( unaccent_match(UserEmail.email, email, exact)) abstract = criteria.pop('abstract', unspecified) track = criteria.pop('track', unspecified) query2 = query if abstract is not unspecified: if track is unspecified: query = query.join(Abstract, (Abstract.submitter_id == User.id)).filter( unaccent_match(Abstract.title, abstract, exact)) query2 = query2.join( Abstract, (Abstract.submitter_id == User.id)).filter( unaccent_match(Abstract.title, abstract, exact)).add_columns( User.id, Track.title.label('track'), Abstract.title.label('abstract')) else: query = query.join( Abstract, (Abstract.submitter_id == User.id)).join( Track, (Abstract.accepted_track_id == Track.id)).filter( unaccent_match( Abstract.title, abstract, exact)).filter( Track.title.op("~*")( r'[[:<:]]{}[[:>:]]'.format(track))) query2 = query2.join( Abstract, (Abstract.submitter_id == User.id)).add_columns( User.id, Track.title.label('track'), Abstract.title.label('abstract')).join( Track, (Abstract.accepted_track_id == Track.id)).filter( unaccent_match( Abstract.title, abstract, exact)).filter( Track.title.op("~*")( r'[[:<:]]{}[[:>:]]'.format(track))) elif track is not unspecified: query = query.join(Abstract, (Abstract.submitter_id == User.id)).join( Track, (Abstract.accepted_track_id == Track.id)).filter( Track.title.op("~*")(r'[[:<:]]{}[[:>:]]'.format(track))) query2 = query2.join( Abstract, (Abstract.submitter_id == User.id)).add_columns( User.id, Track.title.label('track'), Abstract.title.label('abstract')).join( Track, (Abstract.accepted_track_id == Track.id)).filter( Track.title.op("~*")( r'[[:<:]]{}[[:>:]]'.format(track))) for k, v in criteria.iteritems(): query = query.filter(unaccent_match(getattr(User, k), v, exact)) for user1 in query: for user2 in query2: if (user1.id == user2.id) and ((abstract is not unspecified) or (track is not unspecified)): user1.abstract = user2.abstract user1.track = user2.track found_emails = {} found_identities = {} system_user = set() for user in query: for identity in user.identities: found_identities[(identity.provider, identity.identifier)] = user for email in user.all_emails: found_emails[email] = user if user.is_system and not user.all_emails and allow_system_user: system_user = {user} # external user providers if external: identities = multipass.search_identities(exact=exact, **original_criteria) for ident in identities: if not ident.data.get('email'): # Skip users with no email continue if ((ident.provider.name, ident.identifier) not in found_identities and ident.data['email'].lower() not in found_emails): found_emails[ident.data['email'].lower()] = ident found_identities[(ident.provider, ident.identifier)] = ident return set(found_emails.viewvalues()) | system_user