Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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())
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
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())
Ejemplo n.º 6
0
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())
Ejemplo n.º 7
0
Archivo: util.py Proyecto: jas01/indico
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
Ejemplo n.º 8
0
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