11/20/2019

Getting Related Team Information from Private Channel in SPFx MS Teams App

Just two weeks ago during MS Ignite Microsoft Teams team has announced Private channels - one of the most asked features.
So, a bit of technical details. Each private channel is a separate SharePoint site collection with a unique site template and no group assigned.
We can discuss a lot if it's good decision or not.
But in this post I want to focus on a specific problem I experienced while developing SPFx solution for MS Teams.

The Problem

You are developing a SharePoint Framework solution to be served as a Teams Tab. And you want to display some basic team (and maybe group) information in your app.
In general scenario everything looks pretty straightforward: you're getting team context as described here and using groupId property and MS Graph you now can get any information about team or group you want.
But, surprise-surprise! This won't work for Private Channels!
Well, you'll still be able to get the context, but groupId is undefined. Moreover, teamName, teamId, teamSite are actually name, id and site collection url of that private channel. So, there is no any team-related information in team's context.
If you look at web part's pageContext - it's all about private channel's site collection as well...
At that point you can feel really stuck and maybe angry :)
But I have good news for you - there is a solution

The Solution

You would expect that private channel's site collection somehow "knows" about related team and group...
And that is actually true: there is a RelatedGroupId property in the site collection object as well as in root web's property bag. And it contains the needed groupId value of the related team. So, we can use SharePoint REST API to get that value:
https://contoso.sharepoint.com/sites/private-site-collection-url/_api/site?$select=RelatedGroupId
// or
https://contoso.sharepoint.com/sites/private-site-collection-url/_api/web/allProperties
One small remark here: if you the site collection API (the first one) and don't specify the $select part you will not get that property back.
OK, now we can integrate that in our web part:
const siteResponse = await this.context.spHttpClient.get(`${this.context.pageContext.site.absoluteUrl}/_api/site?$select=RelatedGroupId`, SPHttpClient.configurations.v1);
const siteProps = await siteResponse.json();
const groupId: string = siteProps.RelatedGroupId;

const graphClient = await this.context.msGraphClientFactory.getClient();
const team = await graphClient.api(`/teams/${groupId}`).version('v1.0').get();

// do something with the team

And, most probably, you don't want to do additional requests if you're not in a private channel.
To check that we can use new team's context property channelType. It is equal to Private for private channels.
One thing about this property is it's not exposed to microsoftTeams.Context interface that is shipped with SPFx v 1.9.1 (the latest one). So, you'll need to do something like teamsContext as any to use it:
let groupId = this._teamsContext.groupId;
const teamsContext = this._teamsContext as any;
if (teamsContext.channelType === 'Private') {
  const siteResponse = await this.context.spHttpClient.get(`${this.context.pageContext.site.absoluteUrl}/_api/site?$select=RelatedGroupId`, SPHttpClient.configurations.v1);
  const siteProps = await siteResponse.json();
  const groupId: string = siteProps.RelatedGroupId;
}

const graphClient = await this.context.msGraphClientFactory.getClient();
const team = await graphClient.api(`/teams/${groupId}`).version('v1.0').get();

// do something with the team

Hopefully, I'll save you some time with that post!

That's all for today!
Have fun!

No comments:

Post a Comment