/**
 * -------------------------------------------------------------------------------------------
 * Copyright (c) Microsoft Corporation.  All Rights Reserved.  Licensed under the MIT License.
 * See License in the project root for license information.
 * -------------------------------------------------------------------------------------------
 */ import { IGraph , prepScopes , CacheItem , CacheService , CacheStore } from '@microsoft/mgt-element' ; import { User } from '@microsoft/microsoft-graph-types' ; import { findPeople , PersonType } from './graph.people' ; import { schemas } from './cacheStores' ; /**
 * Object to be stored in cache
 */ export interface CacheUser extends CacheItem { /**
     * stringified json representing a user
     */ user ? : string ; } /**
 * Object to be stored in cache
 */ export interface CacheUserQuery extends CacheItem { /**
     * max number of results the query asks for
     */ maxResults ? : number ; /**
     * list of users returned by query
     */ results ? : string [ ] ; } /**
 * Defines the time it takes for objects in the cache to expire
 */ export const getUserInvalidationTime = ( ) : number => CacheService . config . users . invalidationPeriod || CacheService . config . defaultInvalidationPeriod ; /**
 * Whether or not the cache is enabled
 */ export const getIsUsersCacheEnabled = ( ) : boolean => CacheService . config . users . isEnabled && CacheService . config . isEnabled ; returns { ( Promise < User > ) } memberof export async function getMe ( graph , requestedProps ? ) { let cache ; if ( getIsUsersCacheEnabled ( ) ) { cache = CacheService . getCache < CacheUser > ( schemas . users , schemas . users . stores . users ) ; const me = await cache . getValue ( 'me' ) ; if ( me && getUserInvalidationTime ( ) > Date . now ( ) - me . timeCached ) { const cachedData = JSON . parse ( me . user ) ; const uniqueProps = requestedProps ? requestedProps . filter ( prop => ! Object . keys ( cachedData ) . includes ( prop ) ) : null ; if ( ! uniqueProps || uniqueProps . length <= 1 ) { return cachedData ; } } } let apiString = 'me' ; if ( requestedProps ) { apiString = apiString + '?$select=' + requestedProps . toString ( ) ; } const response = graph . api ( apiString ) . middlewareOptions ( prepScopes ( 'user.read' ) ) . get ( ) ; if ( getIsUsersCacheEnabled ( ) ) { cache . putValue ( 'me' , { user : JSON . stringify ( await response ) } ) ; } return response ; } param { string } userPrincipleName returns { ( Promise < User > ) } memberof export async function getUser ( graph , userPrincipleName , requestedProps ? ) { const scopes = 'user.readbasic.all' ; let cache ; if ( getIsUsersCacheEnabled ( ) ) { cache = CacheService . getCache < CacheUser > ( schemas . users , schemas . users . stores . users ) ; const user = await cache . getValue ( userPrincipleName ) ; if ( user && getUserInvalidationTime ( ) > Date . now ( ) - user . timeCached ) { const cachedData = user . user ? JSON . parse ( user . user ) : null ; const uniqueProps = requestedProps && cachedData ? requestedProps . filter ( prop => ! Object . keys ( cachedData ) . includes ( prop ) ) : null ; if ( ! uniqueProps || uniqueProps . length <= 1 ) { return cachedData ; } } } let apiString = `/users/${ userPrincipleName }` ; if ( requestedProps ) { apiString = apiString + '?$select=' + requestedProps . toString ( ) ; } let response ; try { response = await graph . api ( apiString ) . middlewareOptions ( prepScopes ( scopes ) ) . get ( ) ; } catch ( _ ) { } if ( getIsUsersCacheEnabled ( ) ) { cache . putValue ( userPrincipleName , { user : JSON . stringify ( response ) } ) ; } return response ; } export param { IGraph } graph param { string [ ] } userIds returns { Promise < User [ ] > } export async function getUsersForUserIds ( graph , userIds , searchInput = '' ) { if ( ! userIds || userIds . length === 0 ) { return [ ] ; } const batch = graph . createBatch ( ) ; const peopleDict = { } ; const peopleSearchMatches = { } ; const notInCache = [ ] ; searchInput = searchInput . toLowerCase ( ) ; let cache ; if ( getIsUsersCacheEnabled ( ) ) { cache = CacheService . getCache < CacheUser > ( schemas . users , schemas . users . stores . users ) ; } for ( const id of userIds ) { peopleDict [ id ] = null ; let user = null ; if ( getIsUsersCacheEnabled ( ) ) { user = await cache . getValue ( id ) ; } if ( user && getUserInvalidationTime ( ) > Date . now ( ) - user . timeCached ) { user = JSON . parse ( user ?. user ) ; const displayName = user . displayName ; const searchMatches = displayName && displayName . toLowerCase ( ) . includes ( searchInput ) ? true : false ; if ( searchInput && searchMatches ) { peopleSearchMatches [ id ] = user ? user : null ; } else { peopleDict [ id ] = user ? user : null ; } } else if ( id !== '' ) { if ( id . toString ( ) === 'me' ) { peopleDict [ id ] = await getMe ( graph ) ; } else { batch . get ( id , `/users/${ id }` , [ 'user.readbasic.all' ] ) ; } } } try { const responses = await batch . executeAll ( ) ; for ( const id of userIds ) { const response = responses . get ( id ) ; if ( response && response . content ) { const user = response . content ; if ( searchInput ) { const displayName = user ?. displayName . toLowerCase ( ) ; if ( displayName . contains ( searchInput ) ) { peopleSearchMatches [ id ] = user ; } } else { peopleDict [ id ] = user ; } if ( getIsUsersCacheEnabled ( ) ) { cache . putValue ( id , { user : JSON . stringify ( user ) } ) ; } } } if ( searchInput && Object . keys ( peopleSearchMatches ) . length ) { return Promise . all ( Object . values ( peopleSearchMatches ) ) ; } return Promise . all ( Object . values ( peopleDict ) ) ; } catch ( _ ) { try { userIds . filter ( id => notInCache . includes ( id ) ) . forEach ( id => ( peopleDict [ id ] = getUser ( graph , id ) ) ) ; if ( getIsUsersCacheEnabled ( ) ) { userIds . filter ( id => notInCache . includes ( id ) ) . forEach ( async ( id ) => cache . putValue ( id , { user : JSON . stringify ( await peopleDict [ id ] ) } ) ) ; } return Promise . all ( Object . values ( peopleDict ) ) ; } catch ( _ ) { return [ ] ; } } } export param { IGraph } graph param { string [ ] } peopleQueries returns { Promise < User [ ] > } export async function getUsersForPeopleQueries ( graph , peopleQueries ) { if ( ! peopleQueries || peopleQueries . length === 0 ) { return [ ] ; } const batch = graph . createBatch ( ) ; const people = [ ] ; let cacheRes ; let cache ; if ( getIsUsersCacheEnabled ( ) ) { cache = CacheService . getCache < CacheUserQuery > ( schemas . users , schemas . users . stores . usersQuery ) ; } for ( const personQuery of peopleQueries ) { if ( getIsUsersCacheEnabled ( ) ) { cacheRes = await cache . getValue ( personQuery ) ; } if ( getIsUsersCacheEnabled ( ) && cacheRes && getUserInvalidationTime ( ) > Date . now ( ) - cacheRes . timeCached ) { people . push ( JSON . parse ( cacheRes . results [ 0 ] ) ) ; } else if ( personQuery !== '' ) { batch . get ( personQuery , `/me/people?$search="${ personQuery }"` , [ 'people.read' ] ) ; } } try { const responses = await batch . executeAll ( ) ; for ( const personQuery of peopleQueries ) { const response = responses . get ( personQuery ) ; if ( response && response . content && response . content . value && response . content . value . length > 0 ) { people . push ( response . content . value [ 0 ] ) ; if ( getIsUsersCacheEnabled ( ) ) { cache . putValue ( personQuery , { maxResults : 1 , results : [ JSON . stringify ( response . content . value [ 0 ] ) ] } ) ; } } else { people . push ( null ) ; } } return people ; } catch ( _ ) { try { return Promise . all ( peopleQueries . filter ( personQuery => personQuery && personQuery !== '' ) . map ( async ( personQuery ) => { const personArray = await findPeople ( graph , personQuery , 1 ) ; if ( personArray && personArray . length ) { if ( getIsUsersCacheEnabled ( ) ) { cache . putValue ( personQuery , { maxResults : 1 , results : [ JSON . stringify ( personArray [ 0 ] ) ] } ) ; } return personArray [ 0 ] ; } } ) ) ; } catch ( _ ) { return [ ] ; } } } export param { IGraph } graph param { string } query param { number } top returns { Promise < User [ ] > } export async function findUsers ( graph , query , top = 10 ) { const scopes = 'User.ReadBasic.All' ; const item = { maxResults : top , results : null } ; let cache ; if ( getIsUsersCacheEnabled ( ) ) { cache = CacheService . getCache < CacheUserQuery > ( schemas . users , schemas . users . stores . usersQuery ) ; const result = await cache . getValue ( query ) ; if ( result && getUserInvalidationTime ( ) > Date . now ( ) - result . timeCached ) { return result . results . map ( userStr => JSON . parse ( userStr ) ) ; } } let graphResult ; let encodedQuery = `${ query . replace ( /#/g , '%2523' ) }` ; try { graphResult = await graph . api ( 'users' ) . header ( 'ConsistencyLevel' , 'eventual' ) . count ( true ) . search ( `"displayName:${ encodedQuery }" OR "mail:${ encodedQuery }"` ) . top ( top ) . middlewareOptions ( prepScopes ( scopes ) ) . get ( ) ; } catch { } if ( getIsUsersCacheEnabled ( ) && graphResult ) { item . results = graphResult . value . map ( userStr => JSON . stringify ( userStr ) ) ; cache . putValue ( query , item ) ; } return graphResult ? graphResult . value : null ; } param { string } query param { string } groupId param { number } top param { PersonType } personType param { boolean } transitive returns { ( Promise < User [ ] > ) } export async function findGroupMembers ( graph , query , groupId , top = 10 , personType = PersonType . person , transitive = false ) { const scopes = [ 'user.read.all' , 'people.read' ] ; const item = { maxResults : top , results : null } ; let cache ; const key = `${ groupId || '*' }:${ query || '*' }:${ personType }:${ transitive }` ; if ( getIsUsersCacheEnabled ( ) ) { cache = CacheService . getCache < CacheUserQuery > ( schemas . users , schemas . users . stores . usersQuery ) ; const result = await cache . getValue ( key ) ; if ( result && getUserInvalidationTime ( ) > Date . now ( ) - result . timeCached ) { return result . results . map ( userStr => JSON . parse ( userStr ) ) ; } } let filter = '' ; if ( query ) { filter = `startswith(displayName,'${ query }') or startswith(givenName,'${ query }') or startswith(surname,'${ query }') or startswith(mail,'${ query }') or startswith(userPrincipalName,'${ query }')` ; } let apiUrl = `/groups/${ groupId }/${ transitive ? 'transitiveMembers' : 'members' }` ; if ( personType === PersonType . person ) { apiUrl += `/microsoft.graph.user` ; } else if ( personType === PersonType . group ) { apiUrl += `/microsoft.graph.group` ; if ( query ) { filter = `startswith(displayName,'${ query }') or startswith(mail,'${ query }')` ; } } const graphResult = await graph . api ( apiUrl ) . count ( true ) . top ( top ) . filter ( filter ) . header ( 'ConsistencyLevel' , 'eventual' ) . middlewareOptions ( prepScopes ( ... scopes ) ) . get ( ) ; if ( getIsUsersCacheEnabled ( ) && graphResult ) { item . results = graphResult . value . map ( userStr => JSON . stringify ( userStr ) ) ; cache . putValue ( key , item ) ; } return graphResult ? graphResult . value : null ; }