From 532503b69f840c2644c6f7928c4af555f6cc6b5e Mon Sep 17 00:00:00 2001 From: Ricardo Espinoza Date: Sun, 13 Dec 2020 04:47:52 -0500 Subject: [PATCH] :sparkles: Feature/slack node extended (#1239) * Added reaction method to message * Increased limit for channels on getChannels, removed unused fields in the code * Using own operation for reactions * Registering reaction fields and operations * Added Operation "Reaction" to Slack.node.ts * Fixing variable name for emoji * now removing reaction on "remove" instead of "add" * Using GET for reactions.get and passing arguments as query * Added members operation * Fixed typo in timestamp * Added user.info and user.getPresence * Fixed: wrong operation name * :zap: Improvements to #1238 * :zap: Add field resolve data when retrieving channel members * :zap: Minor improvements to Slack-Node Co-authored-by: Andreas Scherren Co-authored-by: Jan Oberhauser --- .../credentials/SlackOAuth2Api.credentials.ts | 8 +- .../nodes/Slack/ChannelDescription.ts | 199 +++++++++++++----- .../nodes-base/nodes/Slack/FileDescription.ts | 40 ++-- .../nodes/Slack/GenericFunctions.ts | 14 +- .../nodes/Slack/MessageDescription.ts | 47 +++-- .../nodes/Slack/MessageInterface.ts | 1 - .../nodes/Slack/ReactionDescription.ts | 101 +++++++++ packages/nodes-base/nodes/Slack/Slack.node.ts | 93 +++++++- .../nodes-base/nodes/Slack/StarDescription.ts | 34 +-- .../nodes-base/nodes/Slack/UserDescription.ts | 85 ++++++++ .../nodes/Slack/UserProfileDescription.ts | 13 +- 11 files changed, 509 insertions(+), 126 deletions(-) create mode 100644 packages/nodes-base/nodes/Slack/ReactionDescription.ts create mode 100644 packages/nodes-base/nodes/Slack/UserDescription.ts diff --git a/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts b/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts index cdca307de5..050bdfb641 100644 --- a/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/SlackOAuth2Api.credentials.ts @@ -8,13 +8,15 @@ const userScopes = [ 'chat:write', 'files:read', 'files:write', + 'groups:read', + 'im:read', + 'mpim:read', + 'reactions:read', + 'reactions:write', 'stars:read', 'stars:write', 'users.profile:read', 'users.profile:write', - 'groups:read', - 'im:read', - 'mpim:read', ]; export class SlackOAuth2Api implements ICredentialType { diff --git a/packages/nodes-base/nodes/Slack/ChannelDescription.ts b/packages/nodes-base/nodes/Slack/ChannelDescription.ts index 52437134e7..2dbf1059e8 100644 --- a/packages/nodes-base/nodes/Slack/ChannelDescription.ts +++ b/packages/nodes-base/nodes/Slack/ChannelDescription.ts @@ -1,4 +1,6 @@ -import { INodeProperties } from 'n8n-workflow'; +import { + INodeProperties, +} from 'n8n-workflow'; export const channelOperations = [ { @@ -63,6 +65,11 @@ export const channelOperations = [ value: 'leave', description: 'Leaves a conversation.', }, + { + name: 'Member', + value: 'member', + description: 'List members of a conversation.', + }, { name: 'Open', value: 'open', @@ -101,9 +108,9 @@ export const channelOperations = [ export const channelFields = [ -/* -------------------------------------------------------------------------- */ -/* channel:archive */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* channel:archive */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -125,9 +132,10 @@ export const channelFields = [ required: true, description: 'The name of the channel to archive.', }, -/* -------------------------------------------------------------------------- */ -/* channel:close */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:close */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -149,9 +157,10 @@ export const channelFields = [ required: true, description: 'The name of the channel to close.', }, -/* -------------------------------------------------------------------------- */ -/* channel:create */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:create */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -197,9 +206,10 @@ export const channelFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* channel:invite */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:invite */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -242,9 +252,10 @@ export const channelFields = [ required: true, description: 'The ID of the user to invite into channel.', }, -/* -------------------------------------------------------------------------- */ -/* channel:get */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -288,9 +299,10 @@ export const channelFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* channel:kick */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:kick */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -332,9 +344,10 @@ export const channelFields = [ }, default: '', }, -/* -------------------------------------------------------------------------- */ -/* channel:join */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:join */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -356,9 +369,10 @@ export const channelFields = [ }, required: true, }, -/* -------------------------------------------------------------------------- */ -/* channel:getAll */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:getAll */ + /* -------------------------------------------------------------------------- */ { displayName: 'Return All', name: 'returnAll', @@ -451,9 +465,10 @@ export const channelFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* channel:history */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:history */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -557,9 +572,10 @@ export const channelFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* channel:leave */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:leave */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -581,9 +597,89 @@ export const channelFields = [ required: true, description: 'The name of the channel to leave.', }, -/* -------------------------------------------------------------------------- */ -/* channel:open */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:member */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'Channel', + name: 'channelId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChannels', + }, + default: '', + displayOptions: { + show: { + operation: [ + 'member', + ], + resource: [ + 'channel', + ], + }, + }, + required: true, + }, + { + displayName: 'Return All', + name: 'returnAll', + type: 'boolean', + displayOptions: { + show: { + resource: [ + 'channel', + ], + operation: [ + 'member', + ], + }, + }, + default: false, + description: 'If all results should be returned or only up to a given limit.', + }, + { + displayName: 'Limit', + name: 'limit', + type: 'number', + default: 100, + placeholder: 'Limit', + displayOptions: { + show: { + operation: [ + 'member', + ], + resource: [ + 'channel', + ], + returnAll: [ + false, + ], + }, + }, + required: false, + }, + { + displayName: 'Resolve Data', + name: 'resolveData', + type: 'boolean', + default: false, + displayOptions: { + show: { + resource: [ + 'channel', + ], + operation: [ + 'member', + ], + }, + }, + description: 'By default the response only contain the ID to resource. If this
option gets activated it will resolve the data automatically.', + }, + + /* -------------------------------------------------------------------------- */ + /* channel:open */ + /* -------------------------------------------------------------------------- */ { displayName: 'Options', name: 'options', @@ -627,9 +723,10 @@ export const channelFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* channel:rename */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:rename */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -669,9 +766,10 @@ export const channelFields = [ required: true, description: 'New name for conversation.', }, -/* -------------------------------------------------------------------------- */ -/* channel:replies */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:replies */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -793,9 +891,10 @@ export const channelFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* channel:setPurpose */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:setPurpose */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -835,9 +934,10 @@ export const channelFields = [ required: true, description: 'A new, specialer purpose', }, -/* -------------------------------------------------------------------------- */ -/* channel:setTopic */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:setTopic */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', @@ -877,9 +977,10 @@ export const channelFields = [ required: true, description: 'The new topic string. Does not support formatting or linkification.', }, -/* -------------------------------------------------------------------------- */ -/* channel:unarchive */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* channel:unarchive */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', diff --git a/packages/nodes-base/nodes/Slack/FileDescription.ts b/packages/nodes-base/nodes/Slack/FileDescription.ts index 1b78fc294b..e33b9e356e 100644 --- a/packages/nodes-base/nodes/Slack/FileDescription.ts +++ b/packages/nodes-base/nodes/Slack/FileDescription.ts @@ -36,9 +36,9 @@ export const fileOperations = [ export const fileFields = [ -/* -------------------------------------------------------------------------- */ -/* file:upload */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* file:upload */ + /* -------------------------------------------------------------------------- */ { displayName: 'Binary Data', name: 'binaryData', @@ -159,9 +159,10 @@ export const fileFields = [ }, ], }, -/* ----------------------------------------------------------------------- */ -/* file:getAll */ -/* ----------------------------------------------------------------------- */ + + /* ----------------------------------------------------------------------- */ + /* file:getAll */ + /* ----------------------------------------------------------------------- */ { displayName: 'Return All', name: 'returnAll', @@ -261,29 +262,29 @@ export const fileFields = [ value: 'all', }, { - name: 'Spaces', - value: 'spaces', - }, - { - name: 'Snippets', - value: 'snippets', + name: 'Google Docs', + value: 'gdocs', }, { name: 'Images', value: 'images', }, { - name: 'Google Docs', - value: 'gdocs', + name: 'Snippets', + value: 'snippets', }, { - name: 'Zips', - value: 'zips', + name: 'Spaces', + value: 'spaces', }, { name: 'pdfs', value: 'pdfs', }, + { + name: 'Zips', + value: 'zips', + }, ], default: ['all'], description: 'Filter files by type', @@ -300,9 +301,10 @@ export const fileFields = [ }, ], }, -/* ----------------------------------------------------------------------- */ -/* file:get */ -/* ----------------------------------------------------------------------- */ + + /* ----------------------------------------------------------------------- */ + /* file:get */ + /* ----------------------------------------------------------------------- */ { displayName: 'File ID', name: 'fileId', diff --git a/packages/nodes-base/nodes/Slack/GenericFunctions.ts b/packages/nodes-base/nodes/Slack/GenericFunctions.ts index e31a505892..43cc376b5c 100644 --- a/packages/nodes-base/nodes/Slack/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Slack/GenericFunctions.ts @@ -76,7 +76,7 @@ export async function slackApiRequest(this: IExecuteFunctions | IExecuteSingleFu } } -export async function slackApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string ,method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any +export async function slackApiRequestAllItems(this: IExecuteFunctions | ILoadOptionsFunctions, propertyName: string, method: string, endpoint: string, body: any = {}, query: IDataObject = {}): Promise { // tslint:disable-line:no-any const returnData: IDataObject[] = []; let responseData; query.page = 1; @@ -88,13 +88,13 @@ export async function slackApiRequestAllItems(this: IExecuteFunctions | ILoadOpt returnData.push.apply(returnData, responseData[propertyName]); } while ( (responseData.response_metadata !== undefined && - responseData.response_metadata.mext_cursor !== undefined && - responseData.response_metadata.next_cursor !== '' && - responseData.response_metadata.next_cursor !== null) || + responseData.response_metadata.mext_cursor !== undefined && + responseData.response_metadata.next_cursor !== '' && + responseData.response_metadata.next_cursor !== null) || (responseData.paging !== undefined && - responseData.paging.pages !== undefined && - responseData.paging.page !== undefined && - responseData.paging.page < responseData.paging.pages + responseData.paging.pages !== undefined && + responseData.paging.page !== undefined && + responseData.paging.page < responseData.paging.pages ) ); diff --git a/packages/nodes-base/nodes/Slack/MessageDescription.ts b/packages/nodes-base/nodes/Slack/MessageDescription.ts index ad5ac67f1b..9953441afe 100644 --- a/packages/nodes-base/nodes/Slack/MessageDescription.ts +++ b/packages/nodes-base/nodes/Slack/MessageDescription.ts @@ -31,9 +31,9 @@ export const messageOperations = [ export const messageFields = [ -/* -------------------------------------------------------------------------- */ -/* message:post */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* message:post */ + /* -------------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channel', @@ -382,6 +382,13 @@ export const messageFields = [ default: '', description: 'URL to an image to use as the icon for this message.', }, + { + displayName: 'Link Names', + name: 'link_names', + type: 'boolean', + default: false, + description: 'Find and link channel names and usernames.', + }, { displayName: 'Make Reply', name: 'thread_ts', @@ -389,20 +396,6 @@ export const messageFields = [ default: '', description: 'Provide another message\'s ts value to make this message a reply.', }, - { - displayName: 'Unfurl Links', - name: 'unfurl_links', - type: 'boolean', - default: false, - description: 'Pass true to enable unfurling of primarily text-based content.', - }, - { - displayName: 'Unfurl Media', - name: 'unfurl_media', - type: 'boolean', - default: true, - description: 'Pass false to disable unfurling of media content.', - }, { displayName: 'Markdown', name: 'mrkdwn', @@ -418,17 +411,25 @@ export const messageFields = [ description: 'Used in conjunction with thread_ts and indicates whether reply should be made visible to everyone in the channel or conversation.', }, { - displayName: 'Link Names', - name: 'link_names', + displayName: 'Unfurl Links', + name: 'unfurl_links', type: 'boolean', default: false, - description: 'Find and link channel names and usernames.', + description: 'Pass true to enable unfurling of primarily text-based content.', + }, + { + displayName: 'Unfurl Media', + name: 'unfurl_media', + type: 'boolean', + default: true, + description: 'Pass false to disable unfurling of media content.', }, ], }, -/* ----------------------------------------------------------------------- */ -/* message:update */ -/* ----------------------------------------------------------------------- */ + + /* ----------------------------------------------------------------------- */ + /* message:update */ + /* ----------------------------------------------------------------------- */ { displayName: 'Channel', name: 'channelId', diff --git a/packages/nodes-base/nodes/Slack/MessageInterface.ts b/packages/nodes-base/nodes/Slack/MessageInterface.ts index caff7c0765..463c2fa636 100644 --- a/packages/nodes-base/nodes/Slack/MessageInterface.ts +++ b/packages/nodes-base/nodes/Slack/MessageInterface.ts @@ -4,4 +4,3 @@ export interface IAttachment { item?: object[]; }; } - diff --git a/packages/nodes-base/nodes/Slack/ReactionDescription.ts b/packages/nodes-base/nodes/Slack/ReactionDescription.ts new file mode 100644 index 0000000000..0e41dc9282 --- /dev/null +++ b/packages/nodes-base/nodes/Slack/ReactionDescription.ts @@ -0,0 +1,101 @@ +import { INodeProperties } from 'n8n-workflow'; + +export const reactionOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'reaction', + ], + }, + }, + options: [ + { + name: 'Add', + value: 'add', + description: 'Adds a reaction to a message', + }, + { + name: 'Get', + value: 'get', + description: 'Get the reactions of a message', + }, + { + name: 'Remove', + value: 'remove', + description: 'Remove a reaction of a message', + }, + ], + default: 'add', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const reactionFields = [ + { + displayName: 'Channel', + name: 'channelId', + type: 'options', + typeOptions: { + loadOptionsMethod: 'getChannels', + }, + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'reaction', + ], + operation: [ + 'add', + 'get', + 'remove', + ], + }, + }, + description: 'Channel containing the message.', + }, + { + displayName: 'Emoji', + name: 'name', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'reaction', + ], + operation: [ + 'add', + 'remove', + ], + }, + }, + description: 'Name of emoji.', + placeholder: '+1', + }, + { + displayName: 'Timestamp', + name: 'timestamp', + type: 'string', + required: true, + default: '', + displayOptions: { + show: { + resource: [ + 'reaction', + ], + operation: [ + 'add', + 'get', + 'remove', + ], + }, + }, + description: `Timestamp of the message.`, + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Slack/Slack.node.ts b/packages/nodes-base/nodes/Slack/Slack.node.ts index 24553d7f79..096b479192 100644 --- a/packages/nodes-base/nodes/Slack/Slack.node.ts +++ b/packages/nodes-base/nodes/Slack/Slack.node.ts @@ -32,6 +32,16 @@ import { fileOperations, } from './FileDescription'; +import { + reactionFields, + reactionOperations, +} from './ReactionDescription'; + +import { + userFields, + userOperations, +} from './UserDescription'; + import { userProfileFields, userProfileOperations, @@ -46,6 +56,7 @@ import { import { IAttachment, } from './MessageInterface'; + import moment = require('moment'); interface Attachment { @@ -163,10 +174,18 @@ export class Slack implements INodeType { name: 'Message', value: 'message', }, + { + name: 'Reaction', + value: 'reaction', + }, { name: 'Star', value: 'star', }, + { + name: 'User', + value: 'user', + }, { name: 'User Profile', value: 'userProfile', @@ -184,6 +203,10 @@ export class Slack implements INodeType { ...starFields, ...fileOperations, ...fileFields, + ...reactionOperations, + ...reactionFields, + ...userOperations, + ...userFields, ...userProfileOperations, ...userProfileFields, ], @@ -217,7 +240,7 @@ export class Slack implements INodeType { // select them easily async getChannels(this: ILoadOptionsFunctions): Promise { const returnData: INodePropertyOptions[] = []; - const qs = { types: 'public_channel,private_channel' }; + const qs = { types: 'public_channel,private_channel', limit: 1000 }; const channels = await slackApiRequestAllItems.call(this, 'channels', 'GET', '/conversations.list', {}, qs); for (const channel of channels) { const channelName = channel.name; @@ -265,7 +288,7 @@ export class Slack implements INodeType { const operation = this.getNodeParameter('operation', 0) as string; for (let i = 0; i < length; i++) { - responseData = { error: 'Resource ' + resource + ' / operation ' + operation + ' not found!'}; + responseData = { error: 'Resource ' + resource + ' / operation ' + operation + ' not found!' }; qs = {}; if (resource === 'channel') { //https://api.slack.com/methods/conversations.archive @@ -383,6 +406,29 @@ export class Slack implements INodeType { }; responseData = await slackApiRequest.call(this, 'POST', '/conversations.leave', body, qs); } + //https://api.slack.com/methods/conversations.members + if (operation === 'member') { + const returnAll = this.getNodeParameter('returnAll', 0) as boolean; + const resolveData = this.getNodeParameter('resolveData', 0) as boolean; + qs.channel = this.getNodeParameter('channelId', i) as string; + if (returnAll) { + responseData = await slackApiRequestAllItems.call(this, 'members', 'GET', '/conversations.members', {}, qs); + responseData = responseData.map((member: string) => ({ member })); + } else { + qs.limit = this.getNodeParameter('limit', i) as number; + responseData = await slackApiRequest.call(this, 'GET', '/conversations.members', {}, qs); + responseData = responseData.members.map((member: string) => ({ member })); + } + + if (resolveData) { + const data: IDataObject[] = []; + for (const { member } of responseData) { + const { user } = await slackApiRequest.call(this, 'GET', '/users.info', {}, { user: member }); + data.push(user); + } + responseData = data; + } + } //https://api.slack.com/methods/conversations.open if (operation === 'open') { const options = this.getNodeParameter('options', i) as IDataObject; @@ -745,6 +791,36 @@ export class Slack implements INodeType { responseData = await slackApiRequest.call(this, 'POST', '/chat.update', body, qs); } } + if (resource === 'reaction') { + const channel = this.getNodeParameter('channelId', i) as string; + const timestamp = this.getNodeParameter('timestamp', i) as string; + //https://api.slack.com/methods/reactions.add + if (operation === 'add') { + const name = this.getNodeParameter('name', i) as string; + const body: IDataObject = { + channel, + name, + timestamp, + }; + responseData = await slackApiRequest.call(this, 'POST', '/reactions.add', body, qs); + } + //https://api.slack.com/methods/reactions.remove + if (operation === 'remove') { + const name = this.getNodeParameter('name', i) as string; + const body: IDataObject = { + channel, + name, + timestamp, + }; + responseData = await slackApiRequest.call(this, 'POST', '/reactions.remove', body, qs); + } + //https://api.slack.com/methods/reactions.get + if (operation === 'get') { + qs.channel = channel; + qs.timestamp = timestamp; + responseData = await slackApiRequest.call(this, 'GET', '/reactions.get', {}, qs); + } + } if (resource === 'star') { //https://api.slack.com/methods/stars.add if (operation === 'add') { @@ -879,6 +955,19 @@ export class Slack implements INodeType { responseData = responseData.file; } } + if (resource === 'user') { + //https://api.slack.com/methods/users.info + if (operation === 'info') { + qs.user = this.getNodeParameter('user', i) as string; + responseData = await slackApiRequest.call(this, 'GET', '/users.info', {}, qs); + responseData = responseData.user; + } + //https://api.slack.com/methods/users.getPresence + if (operation === 'getPresence') { + qs.user = this.getNodeParameter('user', i) as string; + responseData = await slackApiRequest.call(this, 'GET', '/users.getPresence', {}, qs); + } + } if (resource === 'userProfile') { //https://api.slack.com/methods/users.profile.set if (operation === 'update') { diff --git a/packages/nodes-base/nodes/Slack/StarDescription.ts b/packages/nodes-base/nodes/Slack/StarDescription.ts index 0f77db7596..66d95c127c 100644 --- a/packages/nodes-base/nodes/Slack/StarDescription.ts +++ b/packages/nodes-base/nodes/Slack/StarDescription.ts @@ -36,9 +36,9 @@ export const starOperations = [ export const starFields = [ -/* -------------------------------------------------------------------------- */ -/* star:add */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* star:add */ + /* -------------------------------------------------------------------------- */ { displayName: 'Options', name: 'options', @@ -67,13 +67,6 @@ export const starFields = [ default: '', description: 'Channel to add star to, or channel where the message to add star to was posted (used with timestamp).', }, - { - displayName: 'File ID', - name: 'fileId', - type: 'string', - default: '', - description: 'File to add star to.', - }, { displayName: 'File Comment', name: 'fileComment', @@ -81,6 +74,13 @@ export const starFields = [ default: '', description: 'File comment to add star to.', }, + { + displayName: 'File ID', + name: 'fileId', + type: 'string', + default: '', + description: 'File to add star to.', + }, { displayName: 'Timestamp', name: 'timestamp', @@ -90,9 +90,10 @@ export const starFields = [ }, ], }, -/* ----------------------------------------------------------------------- */ -/* star:delete */ -/* ----------------------------------------------------------------------- */ + + /* ----------------------------------------------------------------------- */ + /* star:delete */ + /* ----------------------------------------------------------------------- */ { displayName: 'Options', name: 'options', @@ -144,9 +145,10 @@ export const starFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* star:getAll */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* star:getAll */ + /* -------------------------------------------------------------------------- */ { displayName: 'Return All', name: 'returnAll', diff --git a/packages/nodes-base/nodes/Slack/UserDescription.ts b/packages/nodes-base/nodes/Slack/UserDescription.ts new file mode 100644 index 0000000000..7505a3b8d7 --- /dev/null +++ b/packages/nodes-base/nodes/Slack/UserDescription.ts @@ -0,0 +1,85 @@ +import { + INodeProperties, +} from 'n8n-workflow'; + +export const userOperations = [ + { + displayName: 'Operation', + name: 'operation', + type: 'options', + displayOptions: { + show: { + resource: [ + 'user', + ], + }, + }, + options: [ + { + name: 'Info', + value: 'info', + description: `Get information about a user`, + }, + { + name: 'Get Presence', + value: 'getPresence', + description: `Get online status of a user`, + }, + ], + default: 'info', + description: 'The operation to perform.', + }, +] as INodeProperties[]; + +export const userFields = [ + + /* -------------------------------------------------------------------------- */ + /* user:info */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'User ID', + name: 'user', + type: 'string', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + displayOptions: { + show: { + operation: [ + 'info', + ], + resource: [ + 'user', + ], + }, + }, + required: true, + description: 'The ID of the user to get information about.', + }, + + /* -------------------------------------------------------------------------- */ + /* user:getPresence */ + /* -------------------------------------------------------------------------- */ + { + displayName: 'User ID', + name: 'user', + type: 'string', + typeOptions: { + loadOptionsMethod: 'getUsers', + }, + default: '', + displayOptions: { + show: { + operation: [ + 'getPresence', + ], + resource: [ + 'user', + ], + }, + }, + required: true, + description: 'The ID of the user to get the online status of.', + }, +] as INodeProperties[]; diff --git a/packages/nodes-base/nodes/Slack/UserProfileDescription.ts b/packages/nodes-base/nodes/Slack/UserProfileDescription.ts index a3475ee993..9bf9d103ef 100644 --- a/packages/nodes-base/nodes/Slack/UserProfileDescription.ts +++ b/packages/nodes-base/nodes/Slack/UserProfileDescription.ts @@ -34,9 +34,9 @@ export const userProfileOperations = [ export const userProfileFields = [ -/* -------------------------------------------------------------------------- */ -/* userProfile:update */ -/* -------------------------------------------------------------------------- */ + /* -------------------------------------------------------------------------- */ + /* userProfile:update */ + /* -------------------------------------------------------------------------- */ { displayName: 'Additional Fields', name: 'additionalFields', @@ -144,9 +144,10 @@ export const userProfileFields = [ }, ], }, -/* -------------------------------------------------------------------------- */ -/* userProfile:get */ -/* -------------------------------------------------------------------------- */ + + /* -------------------------------------------------------------------------- */ + /* userProfile:get */ + /* -------------------------------------------------------------------------- */ { displayName: 'Additional Fields', name: 'additionalFields',