Skip to content

Commit

Permalink
fix: correct permissions used for some requests (#2953)
Browse files Browse the repository at this point in the history
also removes a couple of dead code paths and refactors for easier reading
  • Loading branch information
gavinbarron committed Jan 18, 2024
1 parent 6d44a17 commit ec25e57
Show file tree
Hide file tree
Showing 10 changed files with 179 additions and 174 deletions.
1 change: 1 addition & 0 deletions packages/mgt-components/src/components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export * from './mgt-search-box/mgt-search-box';
export * from './mgt-search-results/mgt-search-results';
export * from './mgt-theme-toggle/mgt-theme-toggle';
export * from './sub-components/mgt-spinner/mgt-spinner';
export * from './mgt-teams-channel-picker/teams-channel-picker-types';
// include preview components here for ease of import into mgt-react
// There are no preview components in this package at this time
// export * from './preview';
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {
mgtHtml
} from '@microsoft/mgt-element';
import '../../styles/style-helper';
import '../sub-components/mgt-spinner/mgt-spinner';
import { debounce, isValidEmail } from '../../utils/Utils';
import { MgtPerson, defaultPersonProperties, registerMgtPersonComponent } from '../mgt-person/mgt-person';
import { PersonCardInteraction } from '../PersonCardInteraction';
Expand Down Expand Up @@ -1081,7 +1080,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
} catch (_) {
this._groupPeople = [];
}
} else if (this.groupIds) {
} else {
if (this.type === PersonType.group) {
try {
this._groupPeople = await getGroupsForGroupIds(graph, this.groupIds, this.groupFilters);
Expand Down Expand Up @@ -1119,21 +1118,13 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
}
}
} else if (this.type === PersonType.group) {
if (this.groupIds) {
try {
people = await this.getGroupsForGroupIds(graph, people);
} catch (_) {
// nop
}
} else {
let groups = (await findGroups(graph, '', this.showMax, this.groupType, this._groupFilters)) || [];
// eslint-disable-next-line @typescript-eslint/dot-notation
if (groups.length > 0 && groups[0]['value']) {
// eslint-disable-next-line @typescript-eslint/dot-notation, @typescript-eslint/no-unsafe-assignment
groups = groups[0]['value'];
}
people = groups;
let groups = (await findGroups(graph, '', this.showMax, this.groupType, this._groupFilters)) || [];
// eslint-disable-next-line @typescript-eslint/dot-notation
if (groups.length > 0 && groups[0]['value']) {
// eslint-disable-next-line @typescript-eslint/dot-notation, @typescript-eslint/no-unsafe-assignment
groups = groups[0]['value'];
}
people = groups;
}
this.defaultPeople = people;
}
Expand Down Expand Up @@ -1189,15 +1180,15 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
if (this.userType === UserType.contact || this.userType === UserType.user) {
// we might have a user-filters property set, search for users with it.
if (this.userIds?.length) {
// has the user-ids proerty set
// has the user-ids property set
people = await getUsersForUserIds(graph, this.userIds, input, this._userFilters);
} else {
people = await findUsers(graph, input, this.showMax, this._userFilters);
}
} else {
if (!this.groupIds) {
if (this.userIds?.length) {
// has the user-ids proerty set
// has the user-ids property set
people = await getUsersForUserIds(graph, this.userIds, input, this._userFilters);
} else {
people = (await findPeople(graph, input, this.showMax, this.userType, this._peopleFilters)) || [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -492,10 +492,10 @@ export class MgtPeople extends MgtTemplatedComponent {
// populate people
if (this.groupId) {
this.people = await findGroupMembers(graph, null, this.groupId, this.showMax, PersonType.person);
} else if (this.userIds || this.peopleQueries) {
this.people = this.userIds
? await getUsersForUserIds(graph, this.userIds, '', '', this._fallbackDetails)
: await getUsersForPeopleQueries(graph, this.peopleQueries, this._fallbackDetails);
} else if (this.userIds) {
this.people = await getUsersForUserIds(graph, this.userIds, '', '', this._fallbackDetails);
} else if (this.peopleQueries) {
this.people = await getUsersForPeopleQueries(graph, this.peopleQueries, this._fallbackDetails);
} else if (this.resource) {
this.people = await getPeopleFromResource(graph, this.version, this.resource, this.scopes);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@ const buildOrgStructureRequest = (batch: IBatch, userId: string) => {
batch.get(batchKeys.directReports, `users/${userId}/directReports?$select=${userProperties}`);
};

const validPeopleScopes = ['People.Read.All'];
const buildWorksWithRequest = (batch: IBatch, userId: string) => {
batch.get(batchKeys.people, `users/${userId}/people?$filter=personType/class eq 'Person'`, validUserByIdScopes);
batch.get(batchKeys.people, `users/${userId}/people?$filter=personType/class eq 'Person'`, validPeopleScopes);
};
const validMailSearchScopes = ['Mail.ReadBasic', 'Mail.Read', 'Mail.ReadWrite'];
const buildMessagesWithUserRequest = (batch: IBatch, emailAddress: string) => {
Expand All @@ -139,6 +140,7 @@ const buildFilesRequest = (batch: IBatch, emailAddress?: string) => {
batch.get(batchKeys.files, request, validInsightScopes);
};

const validProfileScopes = ['User.Read.All', 'User.ReadWrite.All'];
/**
* Get the profile for a user
*
Expand All @@ -150,7 +152,7 @@ const getProfile = async (graph: IGraph, userId: string): Promise<Profile> =>
(await graph
.api(`/users/${userId}/profile`)
.version('beta')
.middlewareOptions(prepScopes(validUserByIdScopes))
.middlewareOptions(prepScopes(validProfileScopes))
.get()) as Profile;

const validCreateChatScopes = ['Chat.Create', 'Chat.ReadWrite'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ export class MgtTaxonomyPicker extends MgtTemplatedComponent {
class="mgt-get"
resource=${resource}
version=${this.version}
scopes=${['TermStore.Read.All']}
scopes="TermStore.Read.All, TermStore.ReadWrite.All"
?cache-enabled=${this.cacheEnabled}
?cache-invalidation-period=${this.cacheInvalidationPeriod}>
</mgt-get>`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* -------------------------------------------------------------------------------------------
*/

import { IGraph, BetaGraph, CacheService, CacheStore, prepScopes } from '@microsoft/mgt-element';
import { Team } from '@microsoft/microsoft-graph-types';
import { IGraph, CacheService, CacheStore, prepScopes } from '@microsoft/mgt-element';
import { Team, Channel } from '@microsoft/microsoft-graph-types';
import {
getPhotoForResource,
CachePhoto,
Expand All @@ -15,14 +15,28 @@ import {
} from '../../graph/graph.photos';
import { schemas } from '../../graph/cacheStores';
import { CollectionResponse } from '@microsoft/mgt-element';
import { DropdownItem } from './teams-channel-picker-types';

const teamReadScopes = [
'Team.ReadBasic.All',
'TeamSettings.Read.All',
'TeamSettings.ReadWrite.All',
'User.Read.All',
'User.ReadWrite.All'
];

const channelReadScopes = ['Channel.ReadBasic.All', 'ChannelSettings.Read.All', 'ChannelSettings.ReadWrite.All'];

const teamPhotoReadScopes = ['Team.ReadBasic.All', 'TeamSettings.Read.All', 'TeamSettings.ReadWrite.All'];

/**
* async promise, returns all Teams associated with the user logged in
*
* @returns {Promise<Team[]>}
* @memberof Graph
*/
export const getAllMyTeams = async (graph: IGraph, scopes: string[]): Promise<Team[]> => {
export const getAllMyTeams = async (graph: IGraph): Promise<Team[]> => {
const scopes = teamReadScopes;
const teams = (await graph
.api('/me/joinedTeams')
.select(['displayName', 'id', 'isArchived'])
Expand All @@ -38,11 +52,11 @@ type CachePhotos = Record<string, CachePhoto>;
/**
* Load the photos for a give set of teamIds
*
* @param graph {BetaGraph}
* @param graph {IGraph}
* @param teamIds {string[]}
* @returns {Promise<CachePhotos>}
*/
export const getTeamsPhotosForPhotoIds = async (graph: BetaGraph, teamIds: string[]): Promise<CachePhotos> => {
export const getTeamsPhotosForPhotoIds = async (graph: IGraph, teamIds: string[]): Promise<CachePhotos> => {
let cache: CacheStore<CachePhoto>;
let photos: CachePhotos = {};

Expand All @@ -63,12 +77,11 @@ export const getTeamsPhotosForPhotoIds = async (graph: BetaGraph, teamIds: strin
}
}

const scopes = ['team.readbasic.all'];
photos = {};

for (const id of teamIds) {
try {
const photoDetail = await getPhotoForResource(graph, `/teams/${id}`, scopes);
const photoDetail = await getPhotoForResource(graph, `/teams/${id}`, teamPhotoReadScopes);
if (getIsPhotosCacheEnabled() && photoDetail) {
await cache.putValue(id, photoDetail);
}
Expand All @@ -80,3 +93,31 @@ export const getTeamsPhotosForPhotoIds = async (graph: BetaGraph, teamIds: strin

return photos;
};

/**
* Creates an array of DropdownItems from an array of Teams populated with channels and photos
*
* @param graph {IGraph}
* @param teams {Team[]} the teams to get channels for
* @returns {Promise<DropdownItem[]>} a promise that resolves to an array of DropdownItems
*/
export const getChannelsForTeams = async (graph: IGraph, teams: Team[]): Promise<DropdownItem[]> => {
const batch = graph.createBatch<CollectionResponse<Channel>>();

for (const team of teams) {
batch.get(team.id, `teams/${team.id}/channels`, channelReadScopes);
}

const responses = await batch.executeAll();
const result: DropdownItem[] = [];
for (const team of teams) {
const channelsForTeam = responses.get(team.id);
// skip over any teams that don't have channels
if (!channelsForTeam?.content?.value?.length) continue;
result.push({
item: team,
channels: channelsForTeam.content.value.map(c => ({ item: c }))
});
}
return result;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,12 @@ import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
import { html, TemplateResult } from 'lit';
import { state } from 'lit/decorators.js';
import { classMap } from 'lit/directives/class-map.js';
import {
Providers,
ProviderState,
MgtTemplatedComponent,
BetaGraph,
mgtHtml,
CollectionResponse
} from '@microsoft/mgt-element';
import { Providers, ProviderState, MgtTemplatedComponent, mgtHtml } from '@microsoft/mgt-element';
import '../../styles/style-helper';
import '../sub-components/mgt-spinner/mgt-spinner';
import { getSvg, SvgIcon } from '../../utils/SvgHelper';
import { debounce } from '../../utils/Utils';
import { styles } from './mgt-teams-channel-picker-css';
import { getAllMyTeams, getTeamsPhotosForPhotoIds } from './mgt-teams-channel-picker.graph';
import { getAllMyTeams, getChannelsForTeams, getTeamsPhotosForPhotoIds } from './mgt-teams-channel-picker.graph';
import { strings } from './strings';
import { repeat } from 'lit/directives/repeat.js';
import { registerFluentComponents } from '../../utils/FluentComponents';
Expand All @@ -36,104 +28,7 @@ import {
} from '@fluentui/web-components';
import { registerComponent } from '@microsoft/mgt-element';
import { registerMgtSpinnerComponent } from '../sub-components/mgt-spinner/mgt-spinner';

/**
* Team with displayName
*
* @export
* @interface SelectedChannel
*/
export type Team = MicrosoftGraph.Team & {
/**
* Display name Of Team
*
* @type {string}
*/
displayName?: string;
};

/**
* Selected Channel item
*
* @export
* @interface SelectedChannel
*/
export interface SelectedChannel {
/**
* Channel
*
* @type {MicrosoftGraph.Channel}
* @memberof SelectedChannel
*/
channel: MicrosoftGraph.Channel;

/**
* Team
*
* @type {MicrosoftGraph.Team}
* @memberof SelectedChannel
*/
team: Team;
}

/**
* Drop down menu item
*
* @export
* @interface DropdownItem
*/
interface DropdownItem {
/**
* Teams channel
*
* @type {DropdownItem[]}
* @memberof DropdownItem
*/
channels?: DropdownItem[];
/**
* Microsoft Graph Channel or Team
*
* @type {(MicrosoftGraph.Channel | MicrosoftGraph.Team)}
* @memberof DropdownItem
*/
item: MicrosoftGraph.Channel | Team;
}

/**
* Drop down menu item state
*
* @interface DropdownItemState
*/
interface ChannelPickerItemState {
/**
* Microsoft Graph Channel or Team
*
* @type {(MicrosoftGraph.Channel | MicrosoftGraph.Team)}
* @memberof ChannelPickerItemState
*/
item: MicrosoftGraph.Channel | Team;
/**
* if dropdown item shows expanded state
*
* @type {boolean}
* @memberof DropdownItemState
*/
isExpanded?: boolean;
/**
* If item contains channels
*
* @type {ChannelPickerItemState[]}
* @memberof DropdownItemState
*/
channels?: ChannelPickerItemState[];
/**
* if Item has parent item (team)
*
* @type {ChannelPickerItemState}
* @memberof DropdownItemState
*/
parent: ChannelPickerItemState;
}
import { SelectedChannel, DropdownItem, ChannelPickerItemState } from './teams-channel-picker-types';

export const registerMgtTeamsChannelPickerComponent = () => {
registerFluentComponents(
Expand Down Expand Up @@ -727,31 +622,13 @@ export class MgtTeamsChannelPicker extends MgtTemplatedComponent {
if (provider && provider.state === ProviderState.SignedIn) {
const graph = provider.graph.forComponent(this);

teams = await getAllMyTeams(graph, MgtTeamsChannelPicker.requiredScopes);
teams = await getAllMyTeams(graph);
teams = teams.filter(t => !t.isArchived);

const beta = BetaGraph.fromGraph(graph);

const teamsIds = teams.map(t => t.id);
this.teamsPhotos = await getTeamsPhotosForPhotoIds(beta, teamsIds);

const batch = graph.createBatch<CollectionResponse<MicrosoftGraph.Channel>>();
this.teamsPhotos = await getTeamsPhotosForPhotoIds(graph, teamsIds);

for (const team of teams) {
batch.get(team.id, `teams/${team.id}/channels`, MgtTeamsChannelPicker.requiredScopes);
}

const responses = await batch.executeAll();
this._items = [];
for (const team of teams) {
const channelsForTeam = responses.get(team.id);
// skip over any teams that don't have channels
if (!channelsForTeam?.content?.value?.length) continue;
this.items.push({
item: team,
channels: channelsForTeam.content.value.map(c => ({ item: c }))
});
}
this._items = await getChannelsForTeams(graph, teams);
}
this.filterList();
this.resetFocusState();
Expand Down
Loading

0 comments on commit ec25e57

Please sign in to comment.