diff --git a/apps/sim/blocks/blocks/microsoft_teams.ts b/apps/sim/blocks/blocks/microsoft_teams.ts index a9e326624e..e5c8348880 100644 --- a/apps/sim/blocks/blocks/microsoft_teams.ts +++ b/apps/sim/blocks/blocks/microsoft_teams.ts @@ -48,6 +48,7 @@ export const MicrosoftTeamsBlock: BlockConfig = { 'ChannelMessage.Send', 'ChannelMessage.Read.All', 'ChannelMember.Read.All', + 'TeamsAppInstallation.ReadForTeam.All', 'Group.Read.All', 'Group.ReadWrite.All', 'Team.ReadBasic.All', diff --git a/apps/sim/lib/auth.ts b/apps/sim/lib/auth.ts index cb00ea4307..46291dd02d 100644 --- a/apps/sim/lib/auth.ts +++ b/apps/sim/lib/auth.ts @@ -513,6 +513,7 @@ export const auth = betterAuth({ 'ChannelMessage.Send', 'ChannelMessage.Read.All', 'ChannelMember.Read.All', + 'TeamsAppInstallation.ReadForTeam.All', 'Group.Read.All', 'Group.ReadWrite.All', 'Team.ReadBasic.All', diff --git a/apps/sim/lib/oauth/oauth.ts b/apps/sim/lib/oauth/oauth.ts index 5658509c59..e65116f52e 100644 --- a/apps/sim/lib/oauth/oauth.ts +++ b/apps/sim/lib/oauth/oauth.ts @@ -240,6 +240,7 @@ export const OAUTH_PROVIDERS: Record = { 'ChannelMessage.Send', 'ChannelMessage.Read.All', 'ChannelMember.Read.All', + 'TeamsAppInstallation.ReadForTeam.All', 'Group.Read.All', 'Group.ReadWrite.All', 'Team.ReadBasic.All', diff --git a/apps/sim/tools/microsoft_teams/utils.ts b/apps/sim/tools/microsoft_teams/utils.ts index 0f85153e49..b65c3f62c0 100644 --- a/apps/sim/tools/microsoft_teams/utils.ts +++ b/apps/sim/tools/microsoft_teams/utils.ts @@ -180,7 +180,8 @@ async function fetchChannelMembers( channelId: string, accessToken: string ): Promise { - const response = await fetch( + // Fetch channel members (users only) + const membersResponse = await fetch( `https://graph.microsoft.com/v1.0/teams/${encodeURIComponent(teamId)}/channels/${encodeURIComponent(channelId)}/members`, { headers: { @@ -190,22 +191,52 @@ async function fetchChannelMembers( } ) - if (!response.ok) { + const members: TeamMember[] = [] + + if (membersResponse.ok) { + const membersData = await membersResponse.json() + const userMembers = (membersData.value || []).map((member: TeamMember) => ({ + id: member.id, + displayName: member.displayName || '', + userIdentityType: member.userIdentityType, + })) + members.push(...userMembers) + } else { logger.error('Failed to fetch channel members:', { - status: response.status, - statusText: response.statusText, + status: membersResponse.status, + statusText: membersResponse.statusText, }) - return [] } - const data = await response.json() - const members = (data.value || []).map((member: TeamMember) => ({ - id: member.id, - displayName: member.displayName || '', - userIdentityType: member.userIdentityType, - })) + // Fetch installed apps (includes bots) at team level + const appsResponse = await fetch( + `https://graph.microsoft.com/v1.0/teams/${encodeURIComponent(teamId)}/installedApps?$expand=teamsAppDefinition`, + { + headers: { + Authorization: `Bearer ${accessToken}`, + 'Content-Type': 'application/json', + }, + } + ) - logger.info('Fetched channel members:', { + if (appsResponse.ok) { + const appsData = await appsResponse.json() + const bots = (appsData.value || []) + .filter((app: any) => app.teamsAppDefinition?.bot) + .map((app: any) => ({ + id: app.teamsAppDefinition.bot.id || app.teamsAppDefinition.teamsAppId, + displayName: app.teamsAppDefinition.displayName || '', + userIdentityType: 'bot', + })) + members.push(...bots) + } else { + logger.warn('Failed to fetch installed apps/bots:', { + status: appsResponse.status, + statusText: appsResponse.statusText, + }) + } + + logger.info('Fetched channel members and bots:', { count: members.length, members: members.map((m: TeamMember) => ({ displayName: m.displayName,