def _find_humans( self, organization_id: OrganizationID, query: Optional[str] = None, page: int = 1, per_page: int = 100, omit_revoked: bool = False, omit_non_human: bool = False, ) -> Tuple[List[HumanFindResultItem], int]: assert page >= 1 assert per_page >= 1 org = self._organizations[organization_id] # Query is run against human handle field, hence non-human are automatically ignored users: Iterable[User] if query: # Handle a case insensitive find search to be conform with postgresql query users = [] query_parts = query.lower().split() for user in org.users.values(): if not user.human_handle: continue lemail = str(user.human_handle.email).lower() llabel = str(user.human_handle.label).lower() if all([part in lemail for part in query_parts]) or all( [part in llabel for part in query_parts]): users.append(user) else: users = org.users.values() if omit_non_human: users = [r for r in users if r.human_handle is not None] # Sort human by label users = [ *sorted( [res for res in users if res.human_handle is not None], key=lambda r: r.human_handle.label.lower(), # type: ignore ), *[res for res in users if res.human_handle is None], ] now = pendulum.now() results = [ HumanFindResultItem( user_id=user.user_id, human_handle=user.human_handle, revoked=(user.revoked_on is not None and user.revoked_on <= now), ) for user in users ] if omit_revoked: results = [res for res in results if not res.revoked] total = len(results) # Handle pagination paginated_results = results[(page - 1) * per_page:page * per_page] return paginated_results, total
async def query_find_humans( conn, organization_id: OrganizationID, omit_revoked: bool = False, omit_non_human: bool = False, page: int = 1, per_page: int = 100, query: Optional[str] = None, ) -> Tuple[List[HumanFindResultItem], int]: if page >= 1: offset = (page - 1) * per_page else: return ([], 0) q = _q_human_factory(with_query=bool(query), omit_revoked=omit_revoked, omit_non_human=omit_non_human) if query: args = q( organization_id=organization_id.str, now=pendulum_now(), query=_escape_sql_like_arg(query), offset=offset, limit=per_page, ) else: args = q(organization_id=organization_id.str, now=pendulum_now(), offset=offset, limit=per_page) raw_results = await conn.fetch(*args) total = raw_results[0]["total"] results = [ HumanFindResultItem( user_id=UserID(user_id), human_handle=HumanHandle(email=email, label=label) if email else None, revoked=is_revoked, ) for user_id, email, label, is_revoked, _, _ in raw_results[1:] ] return results, total
async def find_humans( self, organization_id: OrganizationID, query: str = None, page: int = 1, per_page: int = 100, omit_revoked: bool = False, omit_non_human: bool = False, ) -> Tuple[List[HumanFindResultItem], int]: org = self._organizations[organization_id] if query: data = [] query_terms = [qt.lower() for qt in query.split()] for user in org.users.values(): if user.human_handle: user_terms = ( *[x.lower() for x in user.human_handle.label.split()], user.human_handle.email.lower(), user.user_id.lower(), ) else: user_terms = (user.user_id.lower(), ) for qt in query_terms: if not any(ut.startswith(qt) for ut in user_terms): break else: # All query term have match the current user data.append(user) else: data = org.users.values() now = pendulum.now() results = [ HumanFindResultItem( user_id=user.user_id, human_handle=user.human_handle, revoked=(user.revoked_on is not None and user.revoked_on <= now), ) for user in data ] if omit_revoked: results = [res for res in results if not res.revoked] # PostgreSQL does case insensitive sort humans = sorted( [res for res in results if res.human_handle], key=lambda r: (r.human_handle.label.lower(), r.user_id.lower()), # type: ignore ) non_humans = sorted([res for res in results if not res.human_handle], key=lambda r: r.user_id.lower()) if omit_non_human: results = humans else: # Keeping non-human last results = [*humans, *non_humans] return (results[(page - 1) * per_page:page * per_page], len(results))
async def query_find_humans( conn, organization_id: OrganizationID, query: str, page: int, per_page: int, omit_revoked: bool, omit_non_human: bool, ) -> Tuple[List[HumanFindResultItem], int]: if query: if omit_revoked: q = _q_human_factory(query=True, omit_revoked=True, omit_non_human=omit_non_human) args = (pendulum_now(), organization_id, query) else: q = _q_human_factory(query=True, omit_revoked=False, omit_non_human=omit_non_human) args = (pendulum_now(), organization_id, query) else: if omit_revoked: q = _q_human_factory(query=False, omit_revoked=True, omit_non_human=omit_non_human) args = (pendulum_now(), organization_id) else: q = _q_human_factory(query=False, omit_revoked=False, omit_non_human=omit_non_human) args = (pendulum_now(), organization_id) raw_results = await conn.fetch(q, *args) humans = [ HumanFindResultItem( user_id=UserID(user_id), human_handle=HumanHandle(email=email, label=label), revoked=revoked, ) for user_id, email, label, revoked in raw_results if email is not None ] non_humans = [ HumanFindResultItem(user_id=UserID(user_id), human_handle=None, revoked=revoked) for user_id, email, label, revoked in raw_results if email is None ] results = [ *sorted(humans, key=lambda x: (x.human_handle.label.lower(), x.user_id.lower())), *sorted(non_humans, key=lambda x: x.user_id.lower()), ] # TODO: should user LIMIT and OFFSET in the SQL query instead return results[(page - 1) * per_page:page * per_page], len(results)