Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating Chat prop to include support for external users. #14711

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
name: "Create Channel",
description: "Create a new channel in Microsoft Teams. [See the docs here](https://docs.microsoft.com/en-us/graph/api/channel-post?view=graph-rest-1.0&tabs=http)",
type: "action",
version: "0.0.6",
version: "0.0.7",
props: {
microsoftTeams,
teamId: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
name: "List Channels",
description: "Lists all channels in a Microsoft Team. [See the docs here](https://docs.microsoft.com/en-us/graph/api/channel-list?view=graph-rest-1.0&tabs=http)",
type: "action",
version: "0.0.6",
version: "0.0.7",
props: {
microsoftTeams,
teamId: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
name: "List Shifts",
description: "Get the list of shift instances for a team. [See the documentation](https://learn.microsoft.com/en-us/graph/api/schedule-list-shifts?view=graph-rest-1.0&tabs=http)",
type: "action",
version: "0.0.3",
version: "0.0.4",
props: {
microsoftTeams,
teamId: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
name: "Send Channel Message",
description: "Send a message to a team's channel. [See the docs here](https://docs.microsoft.com/en-us/graph/api/channel-post-messages?view=graph-rest-1.0&tabs=http)",
type: "action",
version: "0.0.6",
version: "0.0.7",
props: {
microsoftTeams,
teamId: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
name: "Send Chat Message",
description: "Send a message to a team's chat. [See the docs here](https://docs.microsoft.com/en-us/graph/api/chat-post-messages?view=graph-rest-1.0&tabs=http)",
type: "action",
version: "0.0.6",
version: "0.0.7",
props: {
microsoftTeams,
chatId: {
Expand Down
46 changes: 43 additions & 3 deletions components/microsoft_teams/microsoft_teams.app.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import constants from "./common/constants.mjs";
export default {
type: "app",
app: "microsoft_teams",
description: "**Personal accounts are not currently supported by Microsoft Teams.** Refer to Microsoft's documentation [here](https://learn.microsoft.com/en-us/graph/permissions-reference#remarks-7) to learn more.",
description: "Connect and interact with Microsoft Teams, supporting both internal and external communications.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume removing the dcumentation link is intentional here

propDefinitions: {
team: {
type: "string",
Expand Down Expand Up @@ -58,16 +58,50 @@ export default {
chat: {
type: "string",
label: "Chat",
description: "Team Chat within the organization (No external Contacts)",
description: "Team Chat (internal and external contacts)",
async options({ prevContext }) {
const response = prevContext.nextLink
? await this.makeRequest({
path: prevContext.nextLink,
})
: await this.listChats();

const myTenantId = await this.getAuthenticatedUserTenant();
const options = [];

for (const chat of response.value) {
const members = chat.members.map((member) => member.displayName);
const messages = await this.makeRequest({
path: `/chats/${chat.id}/messages?$top=50`,
});

const members = await Promise.all(chat.members.map(async (member) => {
let displayName = member.displayName;

if (!displayName && messages.value.length > 0) {
const userMessage = messages.value.find((msg) =>
msg.from?.user?.id === member.userId);
if (userMessage?.from?.user?.displayName) {
displayName = userMessage.from.user.displayName;
}
}

if (!displayName) {
try {
const userDetails = await this.makeRequest({
path: `/users/${member.userId}`,
});
displayName = userDetails.displayName;
} catch (err) {
displayName = "Unknown User";
}
}

const isExternal = member.tenantId !== myTenantId || !member.tenantId;
return isExternal
? `${displayName} (External)`
: displayName;
}));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error handling and performance

The member resolution logic has several areas for improvement:

  1. Error handling is generic and could miss specific API error cases
  2. Multiple sequential API calls could impact performance
  3. No caching mechanism for user details

Consider implementing these improvements:

          const members = await Promise.all(chat.members.map(async (member) => {
-            let displayName = member.displayName;
+            // Cache key using userId
+            const cacheKey = `user_${member.userId}`;
+            let displayName = member.displayName || this._userCache?.get(cacheKey);
 
-            if (!displayName && messages.value.length > 0) {
+            if (!displayName) {
               const userMessage = messages.value.find((msg) =>
                 msg.from?.user?.id === member.userId);
               if (userMessage?.from?.user?.displayName) {
                 displayName = userMessage.from.user.displayName;
               }
-            }
 
-            if (!displayName) {
               try {
                 const userDetails = await this.makeRequest({
                   path: `/users/${member.userId}`,
                 });
                 displayName = userDetails.displayName;
+                // Cache the result
+                this._userCache?.set(cacheKey, displayName);
               } catch (err) {
-                displayName = "Unknown User";
+                if (err.statusCode === 404) {
+                  displayName = "User Not Found";
+                } else if (err.statusCode === 403) {
+                  displayName = "Access Denied";
+                } else {
+                  displayName = "Unknown User";
+                }
+                console.error(`Failed to fetch user details for ${member.userId}:`, err);
               }
             }

Committable suggestion skipped: line range outside the PR's diff.


options.push({
label: members.join(", "),
value: chat.id,
Expand Down Expand Up @@ -144,6 +178,12 @@ export default {
: reduction;
}, api);
},
async getAuthenticatedUserTenant() {
const { value } = await this.client()
.api("/organization")
.get();
return value[0].id;
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error handling to tenant ID retrieval

The method assumes the organization API will always return results. Add proper error handling for edge cases.

     async getAuthenticatedUserTenant() {
-      const { value } = await this.client()
-        .api("/organization")
-        .get();
-      return value[0].id;
+      try {
+        const { value } = await this.client()
+          .api("/organization")
+          .get();
+        
+        if (!value || value.length === 0) {
+          throw new Error("No organization found");
+        }
+        
+        return value[0].id;
+      } catch (error) {
+        console.error("Failed to fetch tenant ID:", error);
+        throw new Error("Unable to determine tenant ID");
+      }
     },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async getAuthenticatedUserTenant() {
const { value } = await this.client()
.api("/organization")
.get();
return value[0].id;
},
async getAuthenticatedUserTenant() {
try {
const { value } = await this.client()
.api("/organization")
.get();
if (!value || value.length === 0) {
throw new Error("No organization found");
}
return value[0].id;
} catch (error) {
console.error("Failed to fetch tenant ID:", error);
throw new Error("Unable to determine tenant ID");
}
},

async authenticatedUserId() {
const { id } = await this.client()
.api("/me")
Expand Down
2 changes: 1 addition & 1 deletion components/microsoft_teams/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@pipedream/microsoft_teams",
"version": "0.1.2",
"version": "0.1.3",
"description": "Pipedream Microsoft Teams Components",
"main": "microsoft_teams.app.mjs",
"keywords": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "microsoft_teams-new-channel-message",
name: "New Channel Message",
description: "Emit new event when a new message is posted in a channel",
version: "0.0.7",
version: "0.0.8",
type: "source",
dedupe: "unique",
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "microsoft_teams-new-channel",
name: "New Channel",
description: "Emit new event when a new channel is created within a team",
version: "0.0.7",
version: "0.0.8",
type: "source",
dedupe: "unique",
props: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "microsoft_teams-new-chat-message",
name: "New Chat Message",
description: "Emit new event when a new message is received in a chat",
version: "0.0.7",
version: "0.0.8",
type: "source",
dedupe: "unique",
props: {
Expand Down
2 changes: 1 addition & 1 deletion components/microsoft_teams/sources/new-chat/new-chat.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "microsoft_teams-new-chat",
name: "New Chat",
description: "Emit new event when a new chat is created",
version: "0.0.7",
version: "0.0.8",
type: "source",
dedupe: "unique",
methods: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "microsoft_teams-new-team-member",
name: "New Team Member",
description: "Emit new event when a new member is added to a team",
version: "0.0.7",
version: "0.0.8",
type: "source",
dedupe: "unique",
props: {
Expand Down
2 changes: 1 addition & 1 deletion components/microsoft_teams/sources/new-team/new-team.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
key: "microsoft_teams-new-team",
name: "New Team",
description: "Emit new event when a new team is joined by the authenticated user",
version: "0.0.7",
version: "0.0.8",
type: "source",
dedupe: "unique",
methods: {
Expand Down
Loading