/**
 * DISCLAIMER
 *
 * As there is not yet an OData end-point for managed metadata, this service makes use of the ProcessQuery end-points.
 * The service will get updated once the APIs are in place for managing managed metadata.
 */ import { SPHttpClient , SPHttpClientResponse , ISPHttpClientOptions } from '@microsoft/sp-http' ; import { Environment , EnvironmentType } from '@microsoft/sp-core-library' ; import { BaseComponentContext } from '@microsoft/sp-component-base' ; import { IPickerTerm } from './../propertyFields/termPicker/IPropertyFieldTermPicker' ; import { ITermStore , ITerms , ITerm , IGroup , ITermSet , ISPTermStorePickerServiceProps , ISPTermStorePickerService , TermStorePickerServiceHelper , ITermSets } from './ISPTermStorePickerService' ; import SPTermStoreMockHttpClient from './SPTermStorePickerMockService' ; /**
 * Service implementation to manage term stores in SharePoint
 */ export default class SPTermStorePickerService implements ISPTermStorePickerService { private clientServiceUrl : string ; /**
     * Service constructor
     */ constructor ( private props , private context ) { this . clientServiceUrl = this . context . pageContext . web . absoluteUrl + '/_vti_bin/client.svc/ProcessQuery' ; } /**
     * Gets the collection of term stores in the current SharePoint env
     */ public getTermStores ( ) { if ( Environment . type === EnvironmentType . Local ) { return this . getTermStoresFromMock ( ) ; } else { const data = '<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName=".NET Library" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="2" ObjectPathId="1" /><ObjectIdentityQuery Id="3" ObjectPathId="1" /><ObjectPath Id="5" ObjectPathId="4" /><ObjectIdentityQuery Id="6" ObjectPathId="4" /><Query Id="7" ObjectPathId="4"><Query SelectAllProperties="false"><Properties><Property Name="Id" ScalarProperty="true" /><Property Name="Name" ScalarProperty="true" /><Property Name="Groups"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="Name" ScalarProperty="true" /><Property Name="Id" ScalarProperty="true" /><Property Name="IsSystemGroup" ScalarProperty="true" /><Property Name="TermSets"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="Name" ScalarProperty="true" /><Property Name="Id" ScalarProperty="true" /><Property Name="Description" ScalarProperty="true" /><Property Name="Names" ScalarProperty="true" /></Properties></ChildItemQuery></Property></Properties></ChildItemQuery></Property></Properties></Query></Query></Actions><ObjectPaths><StaticMethod Id="1" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="4" ParentId="1" Name="GetDefaultSiteCollectionTermStore" /></ObjectPaths></Request>' ; const reqHeaders = new Headers ( ) ; reqHeaders . append ( "accept" , "application/json" ) ; reqHeaders . append ( "content-type" , "application/xml" ) ; const httpPostOptions = { headers : reqHeaders , body : data } ; return this . context . spHttpClient . post ( this . clientServiceUrl , SPHttpClient . configurations . v1 , httpPostOptions ) . then ( ( serviceResponse ) => { return serviceResponse . json ( ) . then ( ( serviceJSONResponse ) => { let termStoreResult = serviceJSONResponse . filter ( r => r [ '_ObjectType_' ] === 'SP.Taxonomy.TermStore' ) ; if ( termStoreResult . length > 0 ) { if ( this . props . limitByGroupNameOrID || this . props . limitByTermsetNameOrID || this . props . excludeSystemGroup ) { return termStoreResult . map ( termstore => { let termGroups = termstore . Groups . _Child_Items_ ; if ( this . props . limitByGroupNameOrID ) { const groupNameOrId = this . props . limitByGroupNameOrID ; termGroups = termGroups . filter ( ( group ) => group . Name === groupNameOrId || group . Id . toLowerCase ( ) === groupNameOrId . toLowerCase ( ) ) ; } if ( this . props . limitByTermsetNameOrID ) { const termsetNameOrId = this . props . limitByTermsetNameOrID ; termGroups = termGroups . map ( ( group ) => { group . TermSets . _Child_Items_ = group . TermSets . _Child_Items_ . filter ( ( termSet ) => termSet . Name === termsetNameOrId || TermStorePickerServiceHelper . cleanGuid ( termSet . Id ) . toLowerCase ( ) === TermStorePickerServiceHelper . cleanGuid ( termsetNameOrId ) . toLowerCase ( ) ) ; return group ; } ) ; } if ( this . props . excludeSystemGroup ) { termGroups = termGroups . filter ( group => ! group . IsSystemGroup ) ; } termGroups = termGroups . filter ( ( group ) => group . TermSets . _Child_Items_ . length > 0 ) ; termstore . Groups . _Child_Items_ = termGroups ; return termstore ; } ) ; } return termStoreResult ; } return [ ] ; } ) ; } ) ; } } /**
     * Gets the current term set
     */ public async getTermSets ( ) { const termStore = await this . getTermStores ( ) ; return this . getAllTermSets ( termStore , this . props . limitByTermsetNameOrID ) ; } param termstore param termset private getAllTermSets ( termstore , termsetNameOrId ) { if ( termstore && termstore . length > 0 ) { const ts = termstore [ 0 ] ; let termSets = [ ] ; if ( ts . Groups && ts . Groups . _Child_Items_ ) { for ( const group of ts . Groups . _Child_Items_ ) { if ( group . TermSets && group . TermSets . _Child_Items_ ) { if ( termsetNameOrId ) { for ( const termSet of group . TermSets . _Child_Items_ ) { if ( termSet . Name === termsetNameOrId || termSet . Id . indexOf ( termsetNameOrId ) !== - 1 ) { termSets = [ ... termSets , termSet ] ; } } } else { termSets = [ ... termSets , ... group . TermSets . _Child_Items_ ] ; } } } } return termSets ; } return null ; } param termsetId public async getAllTerms ( termSet ) { if ( Environment . type === EnvironmentType . Local ) { return this . getAllMockTerms ( ) ; } else { const data = `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName=".NET Library" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="30" ObjectPathId="29" /><Query Id="31" ObjectPathId="29"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="Name" ScalarProperty="true" /><Property Name="Id" ScalarProperty="true" /><Property Name="Description" ScalarProperty="true" /><Property Name="IsDeprecated" ScalarProperty="true" /><Property Name="IsAvailableForTagging" ScalarProperty="true" /><Property Name="IsRoot" ScalarProperty="true" /><Property Name="PathOfTerm" ScalarProperty="true" /><Property Name="TermSet" SelectAll="true" /><Property Name="Parent" SelectAll="true"><Query SelectAllProperties="false"><Properties /></Query></Property><Property Name="TermSet"><Query SelectAllProperties="false"><Properties><Property Name="Id" ScalarProperty="true" /></Properties></Query></Property></Properties></ChildItemQuery></Query></Actions><ObjectPaths><Method Id="29" ParentId="18" Name="GetAllTerms" /><Identity Id="18" Name="${ termSet . _ObjectIdentity_ }"
      /></ObjectPaths></Request>` ; const reqHeaders = new Headers ( ) ; reqHeaders . append ( "accept" , "application/json" ) ; reqHeaders . append ( "content-type" , "application/xml" ) ; const httpPostOptions = { headers : reqHeaders , body : data } ; return this . context . spHttpClient . post ( this . clientServiceUrl , SPHttpClient . configurations . v1 , httpPostOptions ) . then ( ( serviceResponse ) => { return serviceResponse . json ( ) . then ( ( serviceJSONResponse ) => { const termStoreResult = serviceJSONResponse . filter ( r => r [ '_ObjectType_' ] === 'SP.Taxonomy.TermCollection' ) ; if ( termStoreResult . length > 0 ) { let terms = termStoreResult [ 0 ] . _Child_Items_ ; terms = terms . map ( term => { term . Id = TermStorePickerServiceHelper . cleanGuid ( term . Id ) ; term [ 'PathDepth' ] = term . PathOfTerm . split ( ';' ) . length ; return term ; } ) ; if ( terms . length > 0 ) { return TermStorePickerServiceHelper . sortTerms ( terms ) ; } } return null ; } ) ; } ) ; } } param searchText public searchTermsByName ( searchText ) { if ( Environment . type === EnvironmentType . Local ) { return SPTermStoreMockHttpClient . searchTermsByName ( searchText ) ; } else { if ( this . props . limitByTermsetNameOrID ) { return this . searchTermsByTermSet ( searchText , this . props . limitByTermsetNameOrID ) ; } else if ( this . props . limitByGroupNameOrID ) { return this . searchTermsByGroup ( searchText ) ; } else { return this . searchAllTerms ( searchText ) ; } } } public async getGroupTermSets ( group ) { return group . TermSets ; } param searchText param termsetId private searchTermsByTermSet ( searchText , termSet ) { if ( Environment . type === EnvironmentType . Local ) { return SPTermStoreMockHttpClient . searchTermsByName ( searchText ) ; } else { return new Promise < IPickerTerm [ ] > ( resolve => { this . getTermStores ( ) . then ( termStore => { let TermSetId = termSet ; if ( ! TermStorePickerServiceHelper . isGuid ( termSet ) ) { TermSetId = TermStorePickerServiceHelper . cleanGuid ( termStore [ 0 ] . Groups . _Child_Items_ [ 0 ] . TermSets . _Child_Items_ [ 0 ] . Id ) ; } const group = this . getTermGroupByTermSetId ( TermSetId , termStore ) ; let data = `<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="Javascript Library"><Actions><ObjectPath Id="456" ObjectPathId="455" /><ObjectIdentityQuery Id="457" ObjectPathId="455" /><ObjectPath Id="459" ObjectPathId="458" /><ObjectIdentityQuery Id="460" ObjectPathId="458" /><ObjectPath Id="462" ObjectPathId="461" /><ObjectIdentityQuery Id="463" ObjectPathId="461" /><ObjectPath Id="465" ObjectPathId="464" /><SetProperty Id="466" ObjectPathId="464" Name="TermLabel"><Parameter Type="String">${ searchText }</Parameter></SetProperty><SetProperty Id="467" ObjectPathId="464" Name="DefaultLabelOnly"><Parameter Type="Boolean">true</Parameter></SetProperty><SetProperty Id="468" ObjectPathId="464" Name="StringMatchOption"><Parameter Type="Number">0</Parameter></SetProperty><SetProperty Id="469" ObjectPathId="464" Name="ResultCollectionSize"><Parameter Type="Number">10</Parameter></SetProperty><SetProperty Id="470" ObjectPathId="464" Name="TrimUnavailable"><Parameter Type="Boolean">true</Parameter></SetProperty><ObjectPath Id="472" ObjectPathId="471" /><Query Id="473" ObjectPathId="471"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="IsRoot" SelectAll="true" /><Property Name="Id" SelectAll="true" /><Property Name="Name" SelectAll="true" /><Property Name="PathOfTerm" SelectAll="true" /><Property Name="TermSet" SelectAll="true" /></Properties></ChildItemQuery></Query></Actions><ObjectPaths><StaticMethod Id="455" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="458" ParentId="455" Name="GetDefaultKeywordsTermStore" /><Method Id="461" ParentId="458" Name="GetTermSet"><Parameters><Parameter Type="Guid">${ TermSetId }</Parameter></Parameters></Method><Constructor Id="464" TypeId="{61a1d689-2744-4ea3-a88b-c95bee9803aa}" /><Method Id="471" ParentId="461" Name="GetTerms"><Parameters><Parameter ObjectPathId="464" /></Parameters></Method></ObjectPaths></Request>` ; const reqHeaders = new Headers ( ) ; reqHeaders . append ( "accept" , "application/json" ) ; reqHeaders . append ( "content-type" , "application/xml" ) ; const httpPostOptions = { headers : reqHeaders , body : data } ; return this . context . spHttpClient . post ( this . clientServiceUrl , SPHttpClient . configurations . v1 , httpPostOptions ) . then ( ( serviceResponse ) => { return serviceResponse . json ( ) . then ( ( serviceJSONResponse ) => { const termStoreResult = serviceJSONResponse . filter ( r => r [ '_ObjectType_' ] === 'SP.Taxonomy.TermCollection' ) ; if ( termStoreResult . length > 0 ) { let terms = termStoreResult [ 0 ] . _Child_Items_ ; let returnTerms = [ ] ; terms . forEach ( term => { if ( term . Name . toLowerCase ( ) . indexOf ( searchText . toLowerCase ( ) ) !== - 1 ) { returnTerms . push ( { key : TermStorePickerServiceHelper . cleanGuid ( term . Id ) , name : term . Name , path : term . PathOfTerm , termSet : term . TermSet . Id , termSetName : term . TermSet . Name , termGroup : group ? TermStorePickerServiceHelper . cleanGuid ( group . Id ) : '' } ) ; } } ) ; resolve ( returnTerms ) ; } return null ; } ) ; } ) ; } ) ; } ) ; } } param searchText private searchTermsByGroup ( searchText ) { if ( Environment . type === EnvironmentType . Local ) { return SPTermStoreMockHttpClient . searchTermsByName ( searchText ) ; } else { return new Promise < IPickerTerm [ ] > ( resolve => { this . getTermStores ( ) . then ( termStore => { let termSetTerms = [ ] ; termStore [ 0 ] . Groups . _Child_Items_ [ 0 ] . TermSets . _Child_Items_ . forEach ( ts => { termSetTerms . push ( this . getAllTerms ( ts ) ) ; } ) ; Promise . all ( termSetTerms ) . then ( results => { let returnTerms = [ ] ; results . forEach ( terms => { if ( terms ) { terms . forEach ( term => { if ( term . Name . toLowerCase ( ) . indexOf ( searchText . toLowerCase ( ) ) !== - 1 ) { returnTerms . push ( { key : TermStorePickerServiceHelper . cleanGuid ( term . Id ) , name : term . Name , path : term . PathOfTerm , termSet : term . TermSet . Id , termSetName : term . TermSet . Name , termGroup : TermStorePickerServiceHelper . cleanGuid ( termStore [ 0 ] . Groups . _Child_Items_ [ 0 ] . Id ) } ) ; } } ) ; } } ) ; resolve ( returnTerms ) ; } ) ; } ) ; } ) ; } } param searchText private searchAllTerms ( searchText ) { if ( Environment . type === EnvironmentType . Local ) { return SPTermStoreMockHttpClient . searchTermsByName ( searchText ) ; } else { return new Promise < IPickerTerm [ ] > ( resolve => { let data = `<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="Javascript Library"><Actions><ObjectPath Id="775" ObjectPathId="774" /><ObjectIdentityQuery Id="776" ObjectPathId="774" /><ObjectPath Id="778" ObjectPathId="777" /><ObjectIdentityQuery Id="779" ObjectPathId="777" /><ObjectPath Id="781" ObjectPathId="780" /><SetProperty Id="782" ObjectPathId="780" Name="TermLabel"><Parameter Type="String">${ searchText }</Parameter></SetProperty><SetProperty Id="783" ObjectPathId="780" Name="DefaultLabelOnly"><Parameter Type="Boolean">true</Parameter></SetProperty><SetProperty Id="784" ObjectPathId="780" Name="StringMatchOption"><Parameter Type="Number">0</Parameter></SetProperty><SetProperty Id="785" ObjectPathId="780" Name="ResultCollectionSize"><Parameter Type="Number">10</Parameter></SetProperty><SetProperty Id="786" ObjectPathId="780" Name="TrimUnavailable"><Parameter Type="Boolean">true</Parameter></SetProperty><ObjectPath Id="788" ObjectPathId="787" /><Query Id="789" ObjectPathId="787"><Query SelectAllProperties="false"><Properties /></Query><ChildItemQuery SelectAllProperties="false"><Properties><Property Name="IsRoot" SelectAll="true" /><Property Name="Id" SelectAll="true" /><Property Name="Name" SelectAll="true" /><Property Name="PathOfTerm" SelectAll="true" /><Property Name="TermSet" SelectAll="true" /></Properties></ChildItemQuery></Query></Actions><ObjectPaths><StaticMethod Id="774" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" /><Method Id="777" ParentId="774" Name="GetDefaultKeywordsTermStore" /><Constructor Id="780" TypeId="{61a1d689-2744-4ea3-a88b-c95bee9803aa}" /><Method Id="787" ParentId="777" Name="GetTerms"><Parameters><Parameter ObjectPathId="780" /></Parameters></Method></ObjectPaths></Request>` ; const reqHeaders = new Headers ( ) ; reqHeaders . append ( "accept" , "application/json" ) ; reqHeaders . append ( "content-type" , "application/xml" ) ; const httpPostOptions = { headers : reqHeaders , body : data } ; return this . context . spHttpClient . post ( this . clientServiceUrl , SPHttpClient . configurations . v1 , httpPostOptions ) . then ( ( serviceResponse ) => { return serviceResponse . json ( ) . then ( ( serviceJSONResponse ) => { const termStoreResult = serviceJSONResponse . filter ( r => r [ '_ObjectType_' ] === 'SP.Taxonomy.TermCollection' ) ; if ( termStoreResult . length > 0 ) { let terms = termStoreResult [ 0 ] . _Child_Items_ ; let returnTerms = [ ] ; terms . forEach ( term => { if ( term . Name . toLowerCase ( ) . indexOf ( searchText . toLowerCase ( ) ) !== - 1 ) { returnTerms . push ( { key : TermStorePickerServiceHelper . cleanGuid ( term . Id ) , name : term . Name , path : term . PathOfTerm , termSet : term . TermSet . Id , termSetName : term . TermSet . Name , termGroup : '' } ) ; } } ) ; resolve ( returnTerms ) ; } return null ; } ) ; } ) ; } ) ; } } /**
     * Returns 3 fake SharePoint lists for the Mock mode
     */ private getTermStoresFromMock ( ) { return SPTermStoreMockHttpClient . getTermStores ( this . context . pageContext . web . absoluteUrl ) . then ( ( data ) => { return data ; } ) as Promise < ITermStore [ ] > ; } /**
     * Returns 3 fake SharePoint lists for the Mock mode
     */ private getAllMockTerms ( ) { return SPTermStoreMockHttpClient . getAllTerms ( ) . then ( ( data ) => { return data ; } ) as Promise < ITerm [ ] > ; } private getTermGroupByTermSetId ( termSetId , termStores ) { for ( let i = 0 , len = termStores . length ; i < len ; i ++ ) { const termStore = termStores [ i ] ; for ( let groupIdx = 0 , groupsLen = termStore . Groups . _Child_Items_ . length ; groupIdx < groupsLen ; groupIdx ++ ) { const group = termStore . Groups . _Child_Items_ [ groupIdx ] ; if ( group . TermSets . _Child_Items_ . filter ( ts => TermStorePickerServiceHelper . cleanGuid ( ts . Id ) === termSetId ) . length ) { return group ; } } } return null ; } }