Add Activepieces integration for workflow automation
- Add Activepieces fork with SmoothSchedule custom piece - Create integrations app with Activepieces service layer - Add embed token endpoint for iframe integration - Create Automations page with embedded workflow builder - Add sidebar visibility fix for embed mode - Add list inactive customers endpoint to Public API - Include SmoothSchedule triggers: event created/updated/cancelled - Include SmoothSchedule actions: create/update/cancel events, list resources/services/customers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
|
||||
export const createChannelAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_create_channel',
|
||||
displayName: 'Create Channel',
|
||||
description: 'Create a new channel in Microsoft Teams.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelDisplayName: Property.ShortText({
|
||||
displayName: 'Channel Name',
|
||||
required: true,
|
||||
}),
|
||||
channelDescription: Property.LongText({
|
||||
displayName: 'Channel Description',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, channelDescription, channelDisplayName } = context.propsValue;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(context.auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
const channel = {
|
||||
displayName: channelDisplayName,
|
||||
description: channelDescription,
|
||||
};
|
||||
|
||||
return await client.api(`/teams/${teamId}/channels`).post(channel);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,92 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
import { Chat } from '@microsoft/microsoft-graph-types';
|
||||
|
||||
export const createChatAndSendMessageAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_create_chat_and_send_message',
|
||||
displayName: 'Create Chat & Send Message',
|
||||
description: 'Start a new chat and send an initial message.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
members:microsoftTeamsCommon.memberIds(true),
|
||||
contentType: Property.StaticDropdown({
|
||||
displayName: 'Message Content Type',
|
||||
required: true,
|
||||
defaultValue: 'text',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Text', value: 'text' },
|
||||
{ label: 'HTML', value: 'html' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Initial Message',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { members, contentType, content } = context.propsValue;
|
||||
|
||||
|
||||
if (isNil(members)) {
|
||||
throw new Error('For one-on-one chats, provide exactly one other member.');
|
||||
}
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(context.auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
// Resolve current user to include as a member
|
||||
const me = await client.api('/me').select('id,userPrincipalName').get();
|
||||
const currentUserBind = `https://graph.microsoft.com/v1.0/users('${me.id}')`;
|
||||
|
||||
// Parse provided members
|
||||
const otherMembersRaw: string[] = members.map((member)=>`https://graph.microsoft.com/v1.0/users('${member}')`)
|
||||
|
||||
|
||||
const membersPayload = [
|
||||
{
|
||||
'@odata.type': '#microsoft.graph.aadUserConversationMember',
|
||||
roles: ['owner'],
|
||||
'user@odata.bind': currentUserBind,
|
||||
},
|
||||
...otherMembersRaw.map((m) => ({
|
||||
'@odata.type': '#microsoft.graph.aadUserConversationMember',
|
||||
roles: ['owner'],
|
||||
'user@odata.bind': m,
|
||||
})),
|
||||
];
|
||||
|
||||
const chatBody: Chat = {
|
||||
chatType: otherMembersRaw.length ===1 ? 'oneOnOne':'group',
|
||||
members: membersPayload,
|
||||
};
|
||||
|
||||
// Create or get existing chat
|
||||
const chat = await client.api('/chats').post(chatBody);
|
||||
|
||||
// Send initial message
|
||||
const chatMessage = {
|
||||
body: {
|
||||
content: content,
|
||||
contentType: contentType,
|
||||
},
|
||||
};
|
||||
const messageResponse = await client.api(`/chats/${chat.id}/messages`).post(chatMessage);
|
||||
|
||||
return {
|
||||
chat,
|
||||
message: messageResponse,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { createGraphClient, withGraphRetry } from '../common/graph';
|
||||
|
||||
export const createPrivateChannelAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_create_private_channel',
|
||||
displayName: 'Create Private Channel',
|
||||
description: 'Create a new private channel in a team.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelDisplayName: Property.ShortText({
|
||||
displayName: 'Channel Name',
|
||||
required: true,
|
||||
}),
|
||||
channelDescription: Property.LongText({
|
||||
displayName: 'Channel Description',
|
||||
required: false,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, channelDescription, channelDisplayName } = context.propsValue;
|
||||
|
||||
const client = createGraphClient(context.auth.access_token);
|
||||
|
||||
const channel = {
|
||||
displayName: channelDisplayName,
|
||||
description: channelDescription,
|
||||
membershipType: 'private',
|
||||
};
|
||||
|
||||
// https://learn.microsoft.com/graph/api/channel-post?view=graph-rest-1.0
|
||||
return await withGraphRetry(() => client.api(`/teams/${teamId}/channels`).post(channel));
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
|
||||
export const findChannelAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_find_channel',
|
||||
displayName: 'Find Channel',
|
||||
description: 'Finds channels by name.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelName: Property.ShortText({
|
||||
displayName: 'Channel Name',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, channelName } = context.propsValue;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(context.auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
const response: PageCollection = await client
|
||||
.api(`/teams/${teamId}/allChannels`)
|
||||
.filter(`displayName eq '${channelName}'`)
|
||||
.get();
|
||||
|
||||
return {
|
||||
found: response.value.length > 0,
|
||||
result: response.value,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,55 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
|
||||
export const findTeamMemberAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_find_team_member',
|
||||
displayName: 'Find Team Member',
|
||||
description: 'Finds a team member by email or display name.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
searchBy: Property.StaticDropdown({
|
||||
displayName: 'Search By',
|
||||
required: true,
|
||||
defaultValue: 'email',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Email', value: 'email' },
|
||||
{ label: 'Name', value: 'name' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
searchValue: Property.ShortText({
|
||||
displayName: 'searchValue',
|
||||
required: true,
|
||||
description: 'Email address or name to search for.',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, searchBy, searchValue } = context.propsValue
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(context.auth.access_token),
|
||||
},
|
||||
})
|
||||
|
||||
const filter = searchBy == 'email' ?`microsoft.graph.aadUserConversationMember/email eq '${searchValue}'`:`microsoft.graph.aadUserConversationMember/displayName eq '${searchValue}'`;
|
||||
|
||||
const response: PageCollection = await client
|
||||
.api(`/teams/${teamId}/members`)
|
||||
.filter(filter)
|
||||
.get();
|
||||
|
||||
return {
|
||||
found: response.value.length > 0,
|
||||
result: response.value,
|
||||
};
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { createGraphClient, withGraphRetry } from '../common/graph';
|
||||
|
||||
export const getChannelMessageAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_get_channel_message',
|
||||
displayName: 'Get Channel Message',
|
||||
description: 'Fetch a specific channel message by team, channel, and message ID (optionally a reply).',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelId: microsoftTeamsCommon.channelId,
|
||||
messageId: Property.ShortText({
|
||||
displayName: 'Message ID',
|
||||
required: true,
|
||||
description: 'The ID of the channel message to retrieve.',
|
||||
}),
|
||||
replyId: Property.ShortText({
|
||||
displayName: 'Reply ID (optional)',
|
||||
required: false,
|
||||
description: 'Provide to fetch a specific reply under the message.',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, channelId, messageId, replyId } = context.propsValue;
|
||||
|
||||
const client = createGraphClient(context.auth.access_token);
|
||||
|
||||
// https://learn.microsoft.com/graph/api/chatmessage-get?view=graph-rest-1.0
|
||||
const base = `/teams/${teamId}/channels/${channelId}/messages/${messageId}`;
|
||||
const path = replyId ? `${base}/replies/${replyId}` : base;
|
||||
return await withGraphRetry(() => client.api(path).get());
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { createGraphClient, withGraphRetry } from '../common/graph';
|
||||
|
||||
export const getChatMessageAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_get_chat_message',
|
||||
displayName: 'Get Chat Message',
|
||||
description: 'Fetch a specific chat message by chat and message ID.',
|
||||
props: {
|
||||
chatId: microsoftTeamsCommon.chatId,
|
||||
messageId: Property.ShortText({
|
||||
displayName: 'Message ID',
|
||||
required: true,
|
||||
description: 'The ID of the message to retrieve.',
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { chatId, messageId } = context.propsValue;
|
||||
|
||||
const client = createGraphClient(context.auth.access_token);
|
||||
|
||||
// https://learn.microsoft.com/graph/api/chatmessage-get?view=graph-rest-1.0
|
||||
return await withGraphRetry(() => client.api(`/chats/${chatId}/messages/${messageId}`).get());
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { createGraphClient, withGraphRetry } from '../common/graph';
|
||||
|
||||
export const replyToChannelMessageAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_reply_to_channel_message',
|
||||
displayName: 'Reply to Channel Message',
|
||||
description: 'Post a reply to an existing channel message.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelId: microsoftTeamsCommon.channelId,
|
||||
messageId: Property.ShortText({
|
||||
displayName: 'Message ID',
|
||||
required: true,
|
||||
description: 'ID of the parent message to reply to.'
|
||||
}),
|
||||
contentType: Property.StaticDropdown({
|
||||
displayName: 'Content Type',
|
||||
required: true,
|
||||
defaultValue: 'text',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{ label: 'Text', value: 'text' },
|
||||
{ label: 'HTML', value: 'html' },
|
||||
],
|
||||
},
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Message',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, channelId, messageId, contentType, content } = context.propsValue;
|
||||
|
||||
const client = createGraphClient(context.auth.access_token);
|
||||
|
||||
const chatMessage = {
|
||||
body: {
|
||||
content: content,
|
||||
contentType: contentType,
|
||||
},
|
||||
};
|
||||
|
||||
// https://learn.microsoft.com/graph/api/chatmessage-post-replies?view=graph-rest-1.0
|
||||
return await withGraphRetry(() =>
|
||||
client
|
||||
.api(`/teams/${teamId}/channels/${channelId}/messages/${messageId}/replies`)
|
||||
.post(chatMessage)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
|
||||
export const sendChannelMessageAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_send_channel_message',
|
||||
displayName: 'Send Channel Message',
|
||||
description: "Sends a message to a teams's channel.",
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelId: microsoftTeamsCommon.channelId,
|
||||
contentType: Property.StaticDropdown({
|
||||
displayName: 'Content Type',
|
||||
required: true,
|
||||
defaultValue: 'text',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'Text',
|
||||
value: 'text',
|
||||
},
|
||||
{
|
||||
label: 'HTML',
|
||||
value: 'html',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Message',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { teamId, channelId, contentType, content } = context.propsValue;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(context.auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
//https://learn.microsoft.com/en-us/graph/api/channel-post-messages?view=graph-rest-1.0&tabs=http
|
||||
const chatMessage = {
|
||||
body: {
|
||||
content: content,
|
||||
contentType: contentType,
|
||||
},
|
||||
};
|
||||
|
||||
return await client.api(`/teams/${teamId}/channels/${channelId}/messages`).post(chatMessage);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { microsoftTeamsAuth } from '../..';
|
||||
import { createAction, Property } from '@activepieces/pieces-framework';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
|
||||
export const sendChatMessageAction = createAction({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'microsoft_teams_send_chat_message',
|
||||
displayName: 'Send Chat Message',
|
||||
description: 'Sends a message in an existing chat.',
|
||||
props: {
|
||||
chatId: microsoftTeamsCommon.chatId,
|
||||
contentType: Property.StaticDropdown({
|
||||
displayName: 'Content Type',
|
||||
required: true,
|
||||
defaultValue: 'text',
|
||||
options: {
|
||||
disabled: false,
|
||||
options: [
|
||||
{
|
||||
label: 'Text',
|
||||
value: 'text',
|
||||
},
|
||||
{
|
||||
label: 'HTML',
|
||||
value: 'html',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
content: Property.LongText({
|
||||
displayName: 'Message',
|
||||
required: true,
|
||||
}),
|
||||
},
|
||||
async run(context) {
|
||||
const { chatId, contentType, content } = context.propsValue;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(context.auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
const chatMessage = {
|
||||
body: {
|
||||
content: content,
|
||||
contentType: contentType,
|
||||
},
|
||||
};
|
||||
|
||||
return await client.api(`/chats/${chatId}/messages`).post(chatMessage);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,99 @@
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
|
||||
type GraphRetryOptions = {
|
||||
maxRetries?: number;
|
||||
initialDelayMs?: number;
|
||||
maxDelayMs?: number;
|
||||
};
|
||||
|
||||
export const createGraphClient = (accessToken: string): Client => {
|
||||
return Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(accessToken),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const delay = async (ms: number): Promise<void> =>
|
||||
new Promise((resolve) => setTimeout(resolve, ms));
|
||||
|
||||
const parseRetryAfterMs = (error: any): number | null => {
|
||||
const headers: Record<string, string> | undefined =
|
||||
error?.headers ?? error?.response?.headers ?? undefined;
|
||||
const retryAfter = headers?.['Retry-After'] ?? headers?.['retry-after'];
|
||||
if (!retryAfter) return null;
|
||||
const asNumber = Number(retryAfter);
|
||||
if (!Number.isNaN(asNumber)) return asNumber * 1000;
|
||||
// Retry-After can be HTTP-date; in that case, compute delta
|
||||
const retryDate = Date.parse(retryAfter);
|
||||
if (!Number.isNaN(retryDate)) {
|
||||
return Math.max(0, retryDate - Date.now());
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const extractStatusCode = (error: any): number => {
|
||||
return (
|
||||
error?.statusCode ??
|
||||
error?.status ??
|
||||
error?.response?.status ??
|
||||
error?.response?.statusCode ??
|
||||
0
|
||||
);
|
||||
};
|
||||
|
||||
const shouldRetry = (statusCode: number, code?: string): boolean => {
|
||||
// Retry on throttling and transient errors
|
||||
if (statusCode === 429 || statusCode === 503 || statusCode === 504) return true;
|
||||
// Some concurrency conflicts can be retried
|
||||
if (statusCode === 409) return true;
|
||||
// Optionally retry generic server errors
|
||||
if (statusCode >= 500 && statusCode < 600) return true;
|
||||
// Some SDKs surface codes like 'TooManyRequests'
|
||||
if (code && /too\s*many\s*requests/i.test(code)) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const buildGraphErrorMessage = (error: any): string => {
|
||||
const status = extractStatusCode(error);
|
||||
const err = error?.body?.error ?? error?.error ?? {};
|
||||
const code = err?.code ?? error?.code;
|
||||
const message = err?.message ?? error?.message ?? 'Request failed';
|
||||
const inner = err?.innerError ?? err?.innererror ?? {};
|
||||
const requestId = inner?.['request-id'] ?? inner?.requestId ?? error?.requestId;
|
||||
return `Graph error (${status}${code ? ` ${code}` : ''})${requestId ? ` [request-id: ${requestId}]` : ''}: ${message}`;
|
||||
};
|
||||
|
||||
export const withGraphRetry = async <T>(
|
||||
requestFn: () => Promise<T>,
|
||||
options: GraphRetryOptions = {}
|
||||
): Promise<T> => {
|
||||
const maxRetries = options.maxRetries ?? 3;
|
||||
const initialDelayMs = options.initialDelayMs ?? 1000;
|
||||
const maxDelayMs = options.maxDelayMs ?? 10000;
|
||||
|
||||
let attempt = 0;
|
||||
let delayMs = initialDelayMs;
|
||||
|
||||
while (attempt <= maxRetries) {
|
||||
try {
|
||||
return await requestFn();
|
||||
} catch (e: any) {
|
||||
const status = extractStatusCode(e);
|
||||
const code = e?.body?.error?.code ?? e?.error?.code ?? e?.code;
|
||||
if (attempt < maxRetries && shouldRetry(status, code)) {
|
||||
const retryAfterMs = parseRetryAfterMs(e);
|
||||
await delay(Math.min(retryAfterMs ?? delayMs, maxDelayMs));
|
||||
attempt++;
|
||||
if (!retryAfterMs) {
|
||||
delayMs = Math.min(delayMs * 2, maxDelayMs);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
throw new Error(buildGraphErrorMessage(e));
|
||||
}
|
||||
}
|
||||
throw new Error("Unexpected error occured");
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
import { DropdownOption, PiecePropValueSchema, Property } from '@activepieces/pieces-framework';
|
||||
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { Team, Channel, Chat, ConversationMember } from '@microsoft/microsoft-graph-types';
|
||||
import { microsoftTeamsAuth } from '../../';
|
||||
|
||||
export const microsoftTeamsCommon = {
|
||||
teamId: Property.Dropdown({
|
||||
auth: microsoftTeamsAuth,
|
||||
displayName: 'Team ID',
|
||||
refreshers: [],
|
||||
required: true,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof microsoftTeamsAuth>;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(authValue.access_token),
|
||||
},
|
||||
});
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
// Pagination : https://learn.microsoft.com/en-us/graph/sdks/paging?view=graph-rest-1.0&tabs=typescript#manually-requesting-subsequent-pages
|
||||
// List Joined Channels : https://learn.microsoft.com/en-us/graph/api/user-list-joinedteams?view=graph-rest-1.0&tabs=http
|
||||
let response: PageCollection = await client.api('/me/joinedTeams').get();
|
||||
while (response.value.length > 0) {
|
||||
for (const team of response.value as Team[]) {
|
||||
options.push({ label: team.displayName!, value: team.id! });
|
||||
}
|
||||
if (response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options: options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
channelId: Property.Dropdown({
|
||||
auth: microsoftTeamsAuth,
|
||||
displayName: 'Channel ID',
|
||||
refreshers: ['teamId'],
|
||||
required: true,
|
||||
options: async ({ auth, teamId }) => {
|
||||
if (!auth || !teamId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first and select team.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof microsoftTeamsAuth>;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(authValue.access_token),
|
||||
},
|
||||
});
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
// Pagination : https://learn.microsoft.com/en-us/graph/sdks/paging?view=graph-rest-1.0&tabs=typescript#manually-requesting-subsequent-pages
|
||||
// List Channels : https://learn.microsoft.com/en-us/graph/api/channel-list?view=graph-rest-1.0&tabs=http
|
||||
let response: PageCollection = await client.api(`/teams/${teamId}/channels`).get();
|
||||
while (response.value.length > 0) {
|
||||
for (const channel of response.value as Channel[]) {
|
||||
options.push({ label: channel.displayName!, value: channel.id! });
|
||||
}
|
||||
if (response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options: options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
memberId:(isRequired=false) =>Property.Dropdown({
|
||||
auth: microsoftTeamsAuth,
|
||||
displayName: 'Member',
|
||||
refreshers: ['teamId'],
|
||||
required: isRequired,
|
||||
options: async ({ auth, teamId }) => {
|
||||
if (!auth || !teamId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first and select team.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof microsoftTeamsAuth>;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(authValue.access_token),
|
||||
},
|
||||
});
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
let response: PageCollection = await client.api(`/teams/${teamId}/members`).get();
|
||||
while (response.value.length > 0) {
|
||||
for (const member of response.value as ConversationMember[]) {
|
||||
options.push({ label: member.displayName!, value: member.id! });
|
||||
}
|
||||
if (response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options: options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
memberIds:(isRequired=false) =>Property.MultiSelectDropdown({
|
||||
auth: microsoftTeamsAuth,
|
||||
displayName: 'Member',
|
||||
refreshers: ['teamId'],
|
||||
required: isRequired,
|
||||
options: async ({ auth, teamId }) => {
|
||||
if (!auth || !teamId) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first and select team.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof microsoftTeamsAuth>;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(authValue.access_token),
|
||||
},
|
||||
});
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
let response: PageCollection = await client.api(`/teams/${teamId}/members`).get();
|
||||
while (response.value.length > 0) {
|
||||
for (const member of response.value as ConversationMember[]) {
|
||||
options.push({ label: member.displayName!, value: member.id! });
|
||||
}
|
||||
if (response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options: options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
chatId: Property.Dropdown({
|
||||
auth: microsoftTeamsAuth,
|
||||
displayName: 'Chat ID',
|
||||
refreshers: [],
|
||||
required: true,
|
||||
options: async ({ auth }) => {
|
||||
if (!auth) {
|
||||
return {
|
||||
disabled: true,
|
||||
placeholder: 'Please connect your account first and select team.',
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
const authValue = auth as PiecePropValueSchema<typeof microsoftTeamsAuth>;
|
||||
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(authValue.access_token),
|
||||
},
|
||||
});
|
||||
const options: DropdownOption<string>[] = [];
|
||||
|
||||
// Pagination : https://learn.microsoft.com/en-us/graph/sdks/paging?view=graph-rest-1.0&tabs=typescript#manually-requesting-subsequent-pages
|
||||
// List Chats : https://learn.microsoft.com/en-us/graph/api/chat-list?view=graph-rest-1.0&tabs=http
|
||||
let response: PageCollection = await client.api('/chats').expand('members').get();
|
||||
while (response.value.length > 0) {
|
||||
for (const chat of response.value as Chat[]) {
|
||||
const chatName =
|
||||
chat.topic ??
|
||||
chat.members
|
||||
?.filter((member: ConversationMember) => member.displayName)
|
||||
.map((member: ConversationMember) => member.displayName)
|
||||
.join(',');
|
||||
options.push({
|
||||
label: `(${CHAT_TYPE[chat.chatType! as keyof typeof CHAT_TYPE]} Chat) ${chatName || '(no title)'}`,
|
||||
value: chat.id!,
|
||||
});
|
||||
}
|
||||
if (response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
disabled: false,
|
||||
options: options,
|
||||
};
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
const CHAT_TYPE = {
|
||||
oneOnOne: '1 : 1',
|
||||
group: 'Group',
|
||||
meeting: 'Meeting',
|
||||
unknownFutureValue: 'Unknown',
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
import { microsoftTeamsAuth } from '../../index';
|
||||
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import {
|
||||
createTrigger,
|
||||
AppConnectionValueForAuthProperty,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { ChatMessage } from '@microsoft/microsoft-graph-types';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { isNil } from '@activepieces/shared';
|
||||
type Props = {
|
||||
teamId: string;
|
||||
channelId: string;
|
||||
};
|
||||
|
||||
export const newChannelMessageTrigger = createTrigger({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'new-channel-message',
|
||||
displayName: 'New Channel Message',
|
||||
description: 'Triggers when a new message is posted in a channel.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
channelId: microsoftTeamsCommon.channelId,
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
sampleData: {
|
||||
replyToId: null,
|
||||
etag: '1747831213175',
|
||||
messageType: 'message',
|
||||
createdDateTime: '2025-05-21T12:40:13.175Z',
|
||||
lastModifiedDateTime: '2025-05-21T12:40:13.175Z',
|
||||
lastEditedDateTime: null,
|
||||
deletedDateTime: null,
|
||||
subject: 'Test',
|
||||
summary: null,
|
||||
chatId: null,
|
||||
importance: 'normal',
|
||||
locale: 'en-us',
|
||||
webUrl:'',
|
||||
policyViolation: null,
|
||||
eventDetail: null,
|
||||
id: '1747831213175',
|
||||
from: {
|
||||
application: null,
|
||||
device: null,
|
||||
user: {
|
||||
'@odata.type': '#microsoft.graph.teamworkUserIdentity',
|
||||
id: '90b3720d-f459-42c1-a02e-a1ecb068',
|
||||
displayName: 'Activepieces',
|
||||
userIdentityType: 'aadUser',
|
||||
tenantId: '9b37335a-d996-4a8d-9ae4-a3a04c94',
|
||||
},
|
||||
},
|
||||
body: {
|
||||
contentType: 'html',
|
||||
content: '<p>Test Message</p>',
|
||||
},
|
||||
channelIdentity: {
|
||||
teamId: '99cb9-7ebe-43ee-a69b-5f77ce8a4b4e',
|
||||
channelId: '19:LiZnIkTo_1FmFY9OTsfym0q3bwo-y2UfV9FaYA1@thread.tacv2',
|
||||
},
|
||||
attachments: [],
|
||||
mentions: [],
|
||||
reactions: [],
|
||||
},
|
||||
});
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof microsoftTeamsAuth>, Props> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, propsValue, lastFetchEpochMS, store }) {
|
||||
const { teamId, channelId } = propsValue;
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
const messages: ChatMessage[] = [];
|
||||
|
||||
if (lastFetchEpochMS === 0) {
|
||||
const response: PageCollection = await client
|
||||
.api(`/teams/${teamId}/channels/${channelId}/messages`)
|
||||
.top(5)
|
||||
.get();
|
||||
|
||||
if (!isNil(response.value)) {
|
||||
messages.push(...response.value);
|
||||
}
|
||||
} else {
|
||||
const requestUrl =
|
||||
(await store.get<string>('deltalink')) ??
|
||||
`/teams/${teamId}/channels/${channelId}/messages/delta`;
|
||||
let nextLink: string | null = requestUrl;
|
||||
|
||||
// https://learn.microsoft.com/en-us/graph/api/chatmessage-delta?view=graph-rest-1.0&tabs=http
|
||||
while (nextLink) {
|
||||
const response: PageCollection = await client.api(nextLink).get();
|
||||
const channelMessages = response.value as ChatMessage[];
|
||||
|
||||
if (Array.isArray(channelMessages)) {
|
||||
messages.push(...channelMessages);
|
||||
}
|
||||
|
||||
nextLink = response['@odata.nextLink'] ?? null;
|
||||
|
||||
if (response['@odata.deltaLink']) {
|
||||
await store.put<string>('deltalink', response['@odata.deltaLink']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return messages.map((message: ChatMessage) => {
|
||||
return {
|
||||
epochMilliSeconds: dayjs(message.createdDateTime).valueOf(),
|
||||
data: message,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,95 @@
|
||||
import { microsoftTeamsAuth } from '../../index';
|
||||
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import {
|
||||
createTrigger,
|
||||
AppConnectionValueForAuthProperty,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { Channel } from '@microsoft/microsoft-graph-types';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { isNil } from '@activepieces/shared';
|
||||
|
||||
type Props = {
|
||||
teamId: string;
|
||||
};
|
||||
|
||||
export const newChannelTrigger = createTrigger({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'new-channel',
|
||||
displayName: 'New Channel',
|
||||
description: 'Triggers when a new channel is created in a team.',
|
||||
props: {
|
||||
teamId: microsoftTeamsCommon.teamId,
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
sampleData: {
|
||||
id: '19:561fbdbbfca848a484f0a6f00ce9dbbd@thread.tacv2',
|
||||
createdDateTime: '2025-05-21T12:40:13.175Z',
|
||||
displayName: 'General',
|
||||
description: 'Auto-generated channel',
|
||||
membershipType: 'standard',
|
||||
isArchived: false,
|
||||
},
|
||||
});
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof microsoftTeamsAuth>, Props> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, propsValue, lastFetchEpochMS }) {
|
||||
const { teamId } = propsValue;
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(auth.access_token),
|
||||
},
|
||||
});
|
||||
const lastFetchDate = dayjs(lastFetchEpochMS).toISOString();
|
||||
|
||||
const channels: Channel[] = [];
|
||||
const filter = lastFetchEpochMS === 0 ? '' : `?$filter=createdDateTime gt ${lastFetchDate}`;
|
||||
|
||||
let response: PageCollection = await client.api(`/teams/${teamId}/channels${filter}`).get();
|
||||
|
||||
while (response.value && response.value.length > 0) {
|
||||
for (const channel of response.value as Channel[]) {
|
||||
if (isNil(channel.createdDateTime)) {
|
||||
continue;
|
||||
}
|
||||
channels.push(channel);
|
||||
}
|
||||
if (lastFetchEpochMS !== 0 && response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return channels.map((channel: Channel) => {
|
||||
return {
|
||||
epochMilliSeconds: dayjs(channel.createdDateTime!).valueOf(),
|
||||
data: channel,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,138 @@
|
||||
import { microsoftTeamsAuth } from '../../index';
|
||||
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import {
|
||||
createTrigger,
|
||||
AppConnectionValueForAuthProperty,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { microsoftTeamsCommon } from '../common';
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { ChatMessage } from '@microsoft/microsoft-graph-types';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { isNil } from '@activepieces/shared';
|
||||
|
||||
type Props = {
|
||||
chatId: string;
|
||||
};
|
||||
|
||||
export const newChatMessageTrigger = createTrigger({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'new-chat-message',
|
||||
displayName: 'New Chat Message',
|
||||
description: 'Triggers when a new message is received in a chat.',
|
||||
props: {
|
||||
chatId: microsoftTeamsCommon.chatId,
|
||||
},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue,
|
||||
});
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context);
|
||||
},
|
||||
sampleData: {
|
||||
replyToId: null,
|
||||
etag: '1747831213175',
|
||||
messageType: 'message',
|
||||
createdDateTime: '2025-05-21T12:40:13.175Z',
|
||||
lastModifiedDateTime: '2025-05-21T12:40:13.175Z',
|
||||
lastEditedDateTime: null,
|
||||
deletedDateTime: null,
|
||||
subject: null,
|
||||
summary: null,
|
||||
chatId: '19:example_chat_id@unq.gbl.spaces',
|
||||
importance: 'normal',
|
||||
locale: 'en-us',
|
||||
webUrl: '',
|
||||
policyViolation: null,
|
||||
eventDetail: null,
|
||||
id: '1747831213175',
|
||||
from: {
|
||||
application: null,
|
||||
device: null,
|
||||
user: {
|
||||
'@odata.type': '#microsoft.graph.teamworkUserIdentity',
|
||||
id: '90b3720d-f459-42c1-a02e-a1ecb068',
|
||||
displayName: 'Activepieces',
|
||||
userIdentityType: 'aadUser',
|
||||
tenantId: '9b37335a-d996-4a8d-9ae4-a3a04c94',
|
||||
},
|
||||
},
|
||||
body: {
|
||||
contentType: 'html',
|
||||
content: '<p>Test Message</p>',
|
||||
},
|
||||
attachments: [],
|
||||
mentions: [],
|
||||
reactions: [],
|
||||
},
|
||||
});
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof microsoftTeamsAuth>, Props> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, propsValue, lastFetchEpochMS, store }) {
|
||||
const { chatId } = propsValue;
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(auth.access_token),
|
||||
},
|
||||
});
|
||||
|
||||
const messages: ChatMessage[] = [];
|
||||
|
||||
if (lastFetchEpochMS === 0) {
|
||||
const response: PageCollection = await client
|
||||
.api(`/chats/${chatId}/messages`)
|
||||
.top(5)
|
||||
.get();
|
||||
|
||||
if (!isNil(response.value)) {
|
||||
messages.push(...(response.value as ChatMessage[]));
|
||||
}
|
||||
} else {
|
||||
const requestUrl =
|
||||
(await store.get<string>('deltalink')) ?? `/chats/${chatId}/messages/delta`;
|
||||
let nextLink: string | null = requestUrl;
|
||||
|
||||
// https://learn.microsoft.com/graph/api/chatmessage-delta?view=graph-rest-1.0&tabs=http
|
||||
while (nextLink) {
|
||||
const response: PageCollection = await client.api(nextLink).get();
|
||||
const chatMessages = response.value as ChatMessage[];
|
||||
|
||||
if (Array.isArray(chatMessages)) {
|
||||
messages.push(...chatMessages);
|
||||
}
|
||||
|
||||
nextLink = response['@odata.nextLink'] ?? null;
|
||||
|
||||
if (response['@odata.deltaLink']) {
|
||||
await store.put<string>('deltalink', response['@odata.deltaLink']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return messages.map((message: ChatMessage) => {
|
||||
return {
|
||||
epochMilliSeconds: dayjs(message.createdDateTime).valueOf(),
|
||||
data: message,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
import { microsoftTeamsAuth } from '../../index';
|
||||
import { DedupeStrategy, Polling, pollingHelper } from '@activepieces/pieces-common';
|
||||
import {
|
||||
createTrigger,
|
||||
AppConnectionValueForAuthProperty,
|
||||
TriggerStrategy,
|
||||
} from '@activepieces/pieces-framework';
|
||||
import { isNil } from '@activepieces/shared';
|
||||
import { Client, PageCollection } from '@microsoft/microsoft-graph-client';
|
||||
import { Chat, ChatType } from '@microsoft/microsoft-graph-types';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
type Props = {
|
||||
chatType?: ChatType;
|
||||
};
|
||||
|
||||
export const newChatTrigger = createTrigger({
|
||||
auth: microsoftTeamsAuth,
|
||||
name: 'new-chat',
|
||||
displayName: 'New Chat',
|
||||
description: 'Triggers when a new chat is created.',
|
||||
props: {},
|
||||
type: TriggerStrategy.POLLING,
|
||||
async onEnable(context) {
|
||||
await pollingHelper.onEnable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue as Props,
|
||||
});
|
||||
},
|
||||
async onDisable(context) {
|
||||
await pollingHelper.onDisable(polling, {
|
||||
auth: context.auth,
|
||||
store: context.store,
|
||||
propsValue: context.propsValue as Props,
|
||||
});
|
||||
},
|
||||
async test(context) {
|
||||
return await pollingHelper.test(polling, context as any);
|
||||
},
|
||||
async run(context) {
|
||||
return await pollingHelper.poll(polling, context as any);
|
||||
},
|
||||
sampleData: {
|
||||
id: '19:example_chat_id@unq.gbl.spaces',
|
||||
createdDateTime: '2025-05-21T12:40:13.175Z',
|
||||
lastUpdatedDateTime: '2025-05-21T12:40:13.175Z',
|
||||
chatType: 'oneOnOne',
|
||||
webUrl: '',
|
||||
isHiddenForAllMembers: false,
|
||||
},
|
||||
});
|
||||
|
||||
const polling: Polling<AppConnectionValueForAuthProperty<typeof microsoftTeamsAuth>, Props> = {
|
||||
strategy: DedupeStrategy.TIMEBASED,
|
||||
async items({ auth, lastFetchEpochMS }) {
|
||||
const client = Client.initWithMiddleware({
|
||||
authProvider: {
|
||||
getAccessToken: () => Promise.resolve(auth.access_token),
|
||||
},
|
||||
});
|
||||
const lastFetchDate = dayjs(lastFetchEpochMS).toISOString();
|
||||
|
||||
const chats: Chat[] = [];
|
||||
const filter =
|
||||
lastFetchEpochMS === 0
|
||||
? '$top=10'
|
||||
: `$filter=createdDateTime gt ${lastFetchDate}`;
|
||||
|
||||
let response: PageCollection = await client.api(`/chats?${filter}`).get();
|
||||
|
||||
console.log('RESPONE');
|
||||
console.log(JSON.stringify(response))
|
||||
|
||||
while (response.value && response.value.length > 0) {
|
||||
for (const channel of response.value as Chat[]) {
|
||||
if (isNil(channel.createdDateTime)) {
|
||||
continue;
|
||||
}
|
||||
chats.push(channel);
|
||||
}
|
||||
if (lastFetchEpochMS !== 0 && response['@odata.nextLink']) {
|
||||
response = await client.api(response['@odata.nextLink']).get();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return chats.map((chat: Chat) => {
|
||||
return {
|
||||
epochMilliSeconds: dayjs(chat.createdDateTime!).valueOf(),
|
||||
data: chat,
|
||||
};
|
||||
});
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user