import { IExecuteFunctions, } from 'n8n-core'; import { IDataObject, ILoadOptionsFunctions, INodeExecutionData, INodePropertyOptions, INodeType, INodeTypeDescription, } from 'n8n-workflow'; import { microsoftApiRequest, microsoftApiRequestAllItems, } from './GenericFunctions'; import { channelFields, channelOperations, } from './ChannelDescription'; import { channelMessageFields, channelMessageOperations, } from './ChannelMessageDescription'; import { taskFields, taskOperations, } from './TaskDescription'; export class MicrosoftTeams implements INodeType { description: INodeTypeDescription = { displayName: 'Microsoft Teams', name: 'microsoftTeams', icon: 'file:teams.svg', group: ['input'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Consume Microsoft Teams API', defaults: { name: 'Microsoft Teams', color: '#555cc7', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'microsoftTeamsOAuth2Api', required: true, }, ], properties: [ { displayName: 'Resource', name: 'resource', type: 'options', options: [ { name: 'Channel', value: 'channel', }, { name: 'Channel Message (Beta)', value: 'channelMessage', }, { name: 'Task', value: 'task', }, ], default: 'channel', description: 'The resource to operate on.', }, // CHANNEL ...channelOperations, ...channelFields, /// MESSAGE ...channelMessageOperations, ...channelMessageFields, ///TASK ...taskOperations, ...taskFields, ], }; methods = { loadOptions: { // Get all the team's channels to display them to user so that he can // select them easily async getChannels(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const teamId = this.getCurrentNodeParameter('teamId') as string; const { value } = await microsoftApiRequest.call(this, 'GET', `/v1.0/teams/${teamId}/channels`); for (const channel of value) { const channelName = channel.displayName; const channelId = channel.id; returnData.push({ name: channelName, value: channelId, }); } return returnData; }, // Get all the teams to display them to user so that he can // select them easily async getTeams(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const { value } = await microsoftApiRequest.call(this, 'GET', '/v1.0/me/joinedTeams'); for (const team of value) { const teamName = team.displayName; const teamId = team.id; returnData.push({ name: teamName, value: teamId, }); } return returnData; }, // Get all the groups to display them to user so that he can // select them easily async getGroups(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const { value } = await microsoftApiRequest.call(this, 'GET', '/v1.0/groups'); for (const group of value) { returnData.push({ name: group.mail, value: group.id, }); } return returnData; }, // Get all the plans to display them to user so that he can // select them easily async getPlans(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const groupId = this.getCurrentNodeParameter('groupId') as string; const { value } = await microsoftApiRequest.call(this, 'GET', `/v1.0/groups/${groupId}/planner/plans`); for (const plan of value) { returnData.push({ name: plan.title, value: plan.id, }); } return returnData; }, // Get all the plans to display them to user so that he can // select them easily async getBuckets(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const planId = this.getCurrentNodeParameter('planId') as string; const { value } = await microsoftApiRequest.call(this, 'GET', `/v1.0/planner/plans/${planId}/buckets`); for (const bucket of value) { returnData.push({ name: bucket.name, value: bucket.id, }); } return returnData; }, // Get all the plans to display them to user so that he can // select them easily async getMembers(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const groupId = this.getCurrentNodeParameter('groupId') as string; const { value } = await microsoftApiRequest.call(this, 'GET', `/v1.0/groups/${groupId}/members`); for (const member of value) { returnData.push({ name: member.displayName, value: member.id, }); } return returnData; }, // Get all the labels to display them to user so that he can // select them easily async getLabels(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; const planId = this.getCurrentNodeParameter('planId') as string; const { categoryDescriptions } = await microsoftApiRequest.call(this, 'GET', `/v1.0/planner/plans/${planId}/details`); for (const key of Object.keys(categoryDescriptions)) { if (categoryDescriptions[key] !== null) { returnData.push({ name: categoryDescriptions[key], value: key, }); } } return returnData; }, }, }; async execute(this: IExecuteFunctions): Promise { const items = this.getInputData(); const returnData: IDataObject[] = []; const length = items.length as unknown as number; const qs: IDataObject = {}; let responseData; const resource = this.getNodeParameter('resource', 0) as string; const operation = this.getNodeParameter('operation', 0) as string; for (let i = 0; i < length; i++) { if (resource === 'channel') { //https://docs.microsoft.com/en-us/graph/api/channel-post?view=graph-rest-beta&tabs=http if (operation === 'create') { const teamId = this.getNodeParameter('teamId', i) as string; const name = this.getNodeParameter('name', i) as string; const options = this.getNodeParameter('options', i) as IDataObject; const body: IDataObject = { displayName: name, }; if (options.description) { body.description = options.description as string; } if (options.type) { body.membershipType = options.type as string; } responseData = await microsoftApiRequest.call(this, 'POST', `/v1.0/teams/${teamId}/channels`, body); } //https://docs.microsoft.com/en-us/graph/api/channel-delete?view=graph-rest-beta&tabs=http if (operation === 'delete') { const teamId = this.getNodeParameter('teamId', i) as string; const channelId = this.getNodeParameter('channelId', i) as string; responseData = await microsoftApiRequest.call(this, 'DELETE', `/v1.0/teams/${teamId}/channels/${channelId}`); responseData = { success: true }; } //https://docs.microsoft.com/en-us/graph/api/channel-get?view=graph-rest-beta&tabs=http if (operation === 'get') { const teamId = this.getNodeParameter('teamId', i) as string; const channelId = this.getNodeParameter('channelId', i) as string; responseData = await microsoftApiRequest.call(this, 'GET', `/v1.0/teams/${teamId}/channels/${channelId}`); } //https://docs.microsoft.com/en-us/graph/api/channel-list?view=graph-rest-beta&tabs=http if (operation === 'getAll') { const teamId = this.getNodeParameter('teamId', i) as string; const returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll) { responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/v1.0/teams/${teamId}/channels`); } else { qs.limit = this.getNodeParameter('limit', i) as number; responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/v1.0/teams/${teamId}/channels`, {}); responseData = responseData.splice(0, qs.limit); } } //https://docs.microsoft.com/en-us/graph/api/channel-patch?view=graph-rest-beta&tabs=http if (operation === 'update') { const teamId = this.getNodeParameter('teamId', i) as string; const channelId = this.getNodeParameter('channelId', i) as string; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const body: IDataObject = {}; if (updateFields.name) { body.displayName = updateFields.name as string; } if (updateFields.description) { body.description = updateFields.description as string; } responseData = await microsoftApiRequest.call(this, 'PATCH', `/v1.0/teams/${teamId}/channels/${channelId}`, body); responseData = { success: true }; } } if (resource === 'channelMessage') { //https://docs.microsoft.com/en-us/graph/api/channel-post-messages?view=graph-rest-beta&tabs=http //https://docs.microsoft.com/en-us/graph/api/channel-post-messagereply?view=graph-rest-beta&tabs=http if (operation === 'create') { const teamId = this.getNodeParameter('teamId', i) as string; const channelId = this.getNodeParameter('channelId', i) as string; const messageType = this.getNodeParameter('messageType', i) as string; const message = this.getNodeParameter('message', i) as string; const options = this.getNodeParameter('options', i) as IDataObject; const body: IDataObject = { body: { contentType: messageType, content: message, }, }; if (options.makeReply) { const replyToId = options.makeReply as string; responseData = await microsoftApiRequest.call(this, 'POST', `/beta/teams/${teamId}/channels/${channelId}/messages/${replyToId}/replies`, body); } else { responseData = await microsoftApiRequest.call(this, 'POST', `/beta/teams/${teamId}/channels/${channelId}/messages`, body); } } //https://docs.microsoft.com/en-us/graph/api/channel-list-messages?view=graph-rest-beta&tabs=http if (operation === 'getAll') { const teamId = this.getNodeParameter('teamId', i) as string; const channelId = this.getNodeParameter('channelId', i) as string; const returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll) { responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/beta/teams/${teamId}/channels/${channelId}/messages`); } else { qs.limit = this.getNodeParameter('limit', i) as number; responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/beta/teams/${teamId}/channels/${channelId}/messages`, {}); responseData = responseData.splice(0, qs.limit); } } } if (resource === 'task') { //https://docs.microsoft.com/en-us/graph/api/planner-post-tasks?view=graph-rest-1.0&tabs=http if (operation === 'create') { const planId = this.getNodeParameter('planId', i) as string; const bucketId = this.getNodeParameter('bucketId', i) as string; const title = this.getNodeParameter('title', i) as string; const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject; const body: IDataObject = { planId, bucketId, title, }; Object.assign(body, additionalFields); if (body.assignedTo) { body.assignments = { [body.assignedTo as string]: { '@odata.type': 'microsoft.graph.plannerAssignment', 'orderHint': ' !', }, }; delete body.assignedTo; } if (Array.isArray(body.labels)) { body.appliedCategories = (body.labels as string[]).map((label) => ({ [label]: true })); } responseData = await microsoftApiRequest.call(this, 'POST', `/v1.0/planner/tasks`, body); } //https://docs.microsoft.com/en-us/graph/api/plannertask-delete?view=graph-rest-1.0&tabs=http if (operation === 'delete') { const taskId = this.getNodeParameter('taskId', i) as string; const task = await microsoftApiRequest.call(this, 'GET', `/v1.0/planner/tasks/${taskId}`); responseData = await microsoftApiRequest.call(this, 'DELETE', `/v1.0/planner/tasks/${taskId}`, {}, {}, undefined, { 'If-Match': task['@odata.etag'] }); responseData = { success: true }; } //https://docs.microsoft.com/en-us/graph/api/plannertask-get?view=graph-rest-1.0&tabs=http if (operation === 'get') { const taskId = this.getNodeParameter('taskId', i) as string; responseData = await microsoftApiRequest.call(this, 'GET', `/v1.0/planner/tasks/${taskId}`); } //https://docs.microsoft.com/en-us/graph/api/planneruser-list-tasks?view=graph-rest-1.0&tabs=http if (operation === 'getAll') { const memberId = this.getNodeParameter('memberId', i) as string; const returnAll = this.getNodeParameter('returnAll', i) as boolean; if (returnAll) { responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/v1.0/users/${memberId}/planner/tasks`); } else { qs.limit = this.getNodeParameter('limit', i) as number; responseData = await microsoftApiRequestAllItems.call(this, 'value', 'GET', `/v1.0/users/${memberId}/planner/tasks`, {}); responseData = responseData.splice(0, qs.limit); } } //https://docs.microsoft.com/en-us/graph/api/plannertask-update?view=graph-rest-1.0&tabs=http if (operation === 'update') { const taskId = this.getNodeParameter('taskId', i) as string; const updateFields = this.getNodeParameter('updateFields', i) as IDataObject; const body: IDataObject = {}; Object.assign(body, updateFields); if (body.assignedTo) { body.assignments = { [body.assignedTo as string]: { '@odata.type': 'microsoft.graph.plannerAssignment', 'orderHint': ' !', }, }; delete body.assignedTo; } if (Array.isArray(body.labels)) { body.appliedCategories = (body.labels as string[]).map((label) => ({ [label]: true })); } const task = await microsoftApiRequest.call(this, 'GET', `/v1.0/planner/tasks/${taskId}`); responseData = await microsoftApiRequest.call(this, 'PATCH', `/v1.0/planner/tasks/${taskId}`, body, {}, undefined, { 'If-Match': task['@odata.etag'] }); responseData = { success: true }; } } if (Array.isArray(responseData)) { returnData.push.apply(returnData, responseData as IDataObject[]); } else { returnData.push(responseData as IDataObject); } } return [this.helpers.returnJsonArray(returnData)]; } }