evont-software.com

Email: info@evont-software.com

Site termgroup add contributor or manager

Category:SPFX
Date:
Author: Mathias Osterkamp

Add site collection term group Managers and Contributors using JSOM

On client side for CSOM we have already a solution for adding managers or contributors for term groups. You can have a look here for the original article.

1ClientContext clientContext = GetClientContext();
2
3var taxonomySession = TaxonomySession.GetTaxonomySession(clientContext);
4
5var termStore = taxonomySession.GetDefaultSiteCollectionTermStore();
6
7var myTermGroup = termStore.Groups.GetByName("My Custom Terms Group");
8
9//Add Group Managers
10myTermGroup.AddGroupManager("i:0#.f|membership|...@tenant.onmicrosoft.com");
11
12//Add Group Contributors
13myTermGroup.AddContributor("i:0#.f|membership|...@tenant.onmicrosoft.com");
14myTermGroup.AddContributor("i:0#.f|membership|...@tenant.onmicrosoft.com");
15
16clientContext.Load(myTermGroup, group => group.GroupManagerPrincipalNames, group => group.ContributorPrincipalNames);
17clientContext.ExecuteQuery();
18
19Console.WriteLine("Group Managers: ");
20foreach (var manager in myTermGroup.GroupManagerPrincipalNames)
21{
22 Console.WriteLine(manager);
23}
24
25Console.WriteLine("Group Contributors: ");
26foreach (var contributors in myTermGroup.ContributorPrincipalNames)
27{
28 Console.WriteLine(contributors);
29}


I extracted the methods for the special case of site collection term group managers and contributors, you can find here a working version with pure typescript. Your class should also have a property for spHttpClient and absoluteWebUrl from pnp js.

1/**
2 * Add manager (creates site term group if not exists, allowed to run multiple times for same user)
3 * @param principalName name of user contoso\login or Everyone
4 */
5 public async addSiteGroupManager(principalName: string): Promise<void> {
6 const requestBody = `<?xml version="1.0" encoding="UTF-8"?>
7 <Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="Javascript Library">
8 <Actions>
9 <ObjectPath Id="1" ObjectPathId="0" />
10 <ObjectIdentityQuery Id="2" ObjectPathId="0" />
11 <ObjectPath Id="4" ObjectPathId="3" />
12 <ObjectIdentityQuery Id="5" ObjectPathId="3" />
13 <ObjectPath Id="7" ObjectPathId="6" />
14 <ObjectPath Id="9" ObjectPathId="8" />
15 <ObjectPath Id="11" ObjectPathId="10" />
16 <ObjectIdentityQuery Id="12" ObjectPathId="10" />
17 <Method Name="AddGroupManager" Id="13" ObjectPathId="10">
18 <Parameters>
19 <Parameter Type="String">${principalName}</Parameter>
20 </Parameters>
21 </Method>
22 </Actions>
23 <ObjectPaths>
24 <StaticMethod Id="0" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" />
25 <Method Id="3" ParentId="0" Name="GetDefaultSiteCollectionTermStore" />
26 <StaticProperty Id="6" TypeId="{3747adcd-a3c3-41b9-bfab-4a64dd2f1e0a}" Name="Current" />
27 <Property Id="8" ParentId="6" Name="Site" />
28 <Method Id="10" ParentId="3" Name="GetSiteCollectionGroup">
29 <Parameters>
30 <Parameter ObjectPathId="8" />
31 <Parameter Type="Boolean">true</Parameter>
32 </Parameters>
33 </Method>
34 </ObjectPaths>
35 </Request>`;
36
37 return await this.postcsom(requestBody).then((result) => {
38 if (result[0].ErrorInfo !== null) {
39 throw new Error(JSON.stringify(result[0].ErrorInfo));
40 }
41 return;
42 });
43 }
44
45 /**
46 * Add contributor (creates site term group if not exists, allowed to run multiple times for same user)
47 * @param principalName name of user contoso\login or Everyone
48 */
49 public async addSiteGroupContributor(principalName: string): Promise<void> {
50 const requestBody = `<?xml version="1.0" encoding="UTF-8"?>
51 <Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="Javascript Library">
52 <Actions>
53 <ObjectPath Id="1" ObjectPathId="0" />
54 <ObjectIdentityQuery Id="2" ObjectPathId="0" />
55 <ObjectPath Id="4" ObjectPathId="3" />
56 <ObjectIdentityQuery Id="5" ObjectPathId="3" />
57 <ObjectPath Id="7" ObjectPathId="6" />
58 <ObjectPath Id="9" ObjectPathId="8" />
59 <ObjectPath Id="11" ObjectPathId="10" />
60 <ObjectIdentityQuery Id="12" ObjectPathId="10" />
61 <Method Name="AddContributor" Id="13" ObjectPathId="10">
62 <Parameters>
63 <Parameter Type="String">${principalName}</Parameter>
64 </Parameters>
65 </Method>
66 </Actions>
67 <ObjectPaths>
68 <StaticMethod Id="0" Name="GetTaxonomySession" TypeId="{981cbc68-9edc-4f8d-872f-71146fcbb84f}" />
69 <Method Id="3" ParentId="0" Name="GetDefaultSiteCollectionTermStore" />
70 <StaticProperty Id="6" TypeId="{3747adcd-a3c3-41b9-bfab-4a64dd2f1e0a}" Name="Current" />
71 <Property Id="8" ParentId="6" Name="Site" />
72 <Method Id="10" ParentId="3" Name="GetSiteCollectionGroup">
73 <Parameters>
74 <Parameter ObjectPathId="8" />
75 <Parameter Type="Boolean">true</Parameter>
76 </Parameters>
77 </Method>
78 </ObjectPaths>
79 </Request>`;
80 return await this.postcsom(requestBody).then((result) => {
81 if (result[0].ErrorInfo !== null) {
82 throw new Error(JSON.stringify(result[0].ErrorInfo));
83 }
84 return;
85 });
86 }
87
88
89/**
90 * sends a request to client svc
91 * @param data request data
92 */
93 // eslint-disable-next-line @typescript-eslint/no-explicit-any
94 private async postcsom(data: string): Promise<any> {
95 const clientServiceUrl = this.absoluteWebUrl + '/_vti_bin/client.svc/ProcessQuery';
96
97 const formDigest = await this.getFormDigest();
98
99 const requestHeaders: Headers = new Headers();
100 requestHeaders.append('Accept', 'application/json');
101 requestHeaders.append('Content-Type', 'text/xml');
102 requestHeaders.append('X-RequestDigest', formDigest);
103
104 const httpPostOptions: IHttpClientOptions = {
105 headers: requestHeaders,
106 body: data
107 };
108
109 const serviceResponse: IResponse = await this.spHttpClient.post(clientServiceUrl,SPHttpClient.configurations.v1, httpPostOptions);
110 const serviceJSONResponse = await serviceResponse.json();
111 if (serviceResponse.ok) {
112 return serviceJSONResponse;
113 }
114 return null;
115 }
116
117 /**
118 * digest is needed for post requests
119 */
120 private async getFormDigest(): Promise<string> {
121 if (this.cachedDigest && !this.isDigestDateInvalid()) return this.cachedDigest;
122 this.cachedDigestDate = new Date();
123 const contextInfoUrl = this.absoluteWebUrl + '/_api/contextinfo';
124
125 const requestHeaders: Headers = new Headers();
126 requestHeaders.append('Accept', 'application/json');
127 requestHeaders.append('Content-Type', 'text/xml');
128
129 const httpPostOptions: IHttpClientOptions = {
130 headers: requestHeaders
131 };
132 const contextInfoResponse: IResponse = await this.spHttpClient.post(contextInfoUrl, httpPostOptions);
133 const contextInfoJsonResponse = await contextInfoResponse.json();
134 const formDigest: string = contextInfoJsonResponse.FormDigestValue;
135 this.cachedDigest = formDigest;
136 return formDigest;
137 }
138
139 private isDigestDateInvalid(): boolean {
140 const today = new Date().getTime();
141 const cachedtime = this.cachedDigestDate.getTime();
142 const difference = Math.abs(cachedtime - today);
143 const seconds = (difference / 1000) % 60;
144 return seconds > 60;
145 }


The easy usage is:

addSiteGroupContributor('Everyone')