Feature/slack status change (#995)

* Added methods to set and get the user's status.

* Fixed set status message

* Improvements to #993

* 💄 small cosmetic change

Co-authored-by: Tobias Schulz-Hess <tobias+xps@schulz-hess.de>
Co-authored-by: Tobias Schulz-Hess <tobias.schulz-hess@xing.com>
This commit is contained in:
Ricardo Espinoza 2020-10-02 01:31:41 -04:00 committed by GitHub
parent fe802c8f76
commit 39c173a272
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 268 additions and 0 deletions

View file

@ -10,6 +10,8 @@ const userScopes = [
'files:write',
'stars:read',
'stars:write',
'users.profile:read',
'users.profile:write'
];
export class SlackOAuth2Api implements ICredentialType {

View file

@ -16,26 +16,37 @@ import {
channelFields,
channelOperations,
} from './ChannelDescription';
import {
messageFields,
messageOperations,
} from './MessageDescription';
import {
starFields,
starOperations,
} from './StarDescription';
import {
fileFields,
fileOperations,
} from './FileDescription';
import {
userProfileFields,
userProfileOperations,
} from './UserProfileDescription';
import {
slackApiRequest,
slackApiRequestAllItems,
validateJSON,
} from './GenericFunctions';
import {
IAttachment,
} from './MessageInterface';
import moment = require('moment');
interface Attachment {
fields: {
@ -156,6 +167,10 @@ export class Slack implements INodeType {
name: 'Star',
value: 'star',
},
{
name: 'User Profile',
value: 'userProfile',
},
],
default: 'message',
description: 'The resource to operate on.',
@ -169,6 +184,8 @@ export class Slack implements INodeType {
...starFields,
...fileOperations,
...fileFields,
...userProfileOperations,
...userProfileFields,
],
};
@ -218,6 +235,22 @@ export class Slack implements INodeType {
return returnData;
},
// Get all the team fields to display them to user so that he can
// select them easily
async getTeamFields(this: ILoadOptionsFunctions): Promise<INodePropertyOptions[]> {
const returnData: INodePropertyOptions[] = [];
const { profile: { fields } } = await slackApiRequest.call(this, 'GET', '/team.profile.get');
console.log(fields);
for (const field of fields) {
const fieldName = field.label;
const fieldId = field.id;
returnData.push({
name: fieldName,
value: fieldId,
});
}
return returnData;
},
}
};
@ -232,6 +265,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!'};
qs = {};
if (resource === 'channel') {
//https://api.slack.com/methods/conversations.archive
@ -848,6 +882,55 @@ export class Slack implements INodeType {
responseData = responseData.file;
}
}
if (resource === 'userProfile') {
//https://api.slack.com/methods/users.profile.set
if (operation === 'update') {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const timezone = this.getTimezone();
const body: IDataObject = {};
Object.assign(body, additionalFields);
if (body.status_expiration === undefined) {
body.status_expiration = 0;
} else {
body.status_expiration = moment.tz(body.status_expiration as string, timezone).unix();
}
if (body.customFieldUi) {
const customFields = (body.customFieldUi as IDataObject).customFieldValues as IDataObject[];
body.fields = {};
for (const customField of customFields) {
//@ts-ignore
body.fields[customField.id] = {
value: customField.value,
alt: customField.alt,
};
}
}
responseData = await slackApiRequest.call(this, 'POST', '/users.profile.set', { profile: body }, qs);
responseData = responseData.profile;
}
//https://api.slack.com/methods/users.profile.get
if (operation === 'get') {
const additionalFields = this.getNodeParameter('additionalFields', i) as IDataObject;
const body: IDataObject = {};
Object.assign(body, additionalFields);
responseData = await slackApiRequest.call(this, 'POST', '/users.profile.get', body);
responseData = responseData.profile;
}
}
if (Array.isArray(responseData)) {
returnData.push.apply(returnData, responseData as IDataObject[]);
} else {

View file

@ -0,0 +1,183 @@
import {
INodeProperties,
} from 'n8n-workflow';
import { text } from 'express';
export const userProfileOperations = [
{
displayName: 'Operation',
name: 'operation',
type: 'options',
displayOptions: {
show: {
resource: [
'userProfile',
],
},
},
options: [
{
name: 'Get',
value: 'get',
description: `Get your user's profile`,
},
{
name: 'Update',
value: 'update',
description: `Update user's profile`,
},
],
default: 'get',
description: 'The operation to perform.',
},
] as INodeProperties[];
export const userProfileFields = [
/* -------------------------------------------------------------------------- */
/* userProfile:update */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'userProfile',
],
operation: [
'update',
],
},
},
options: [
{
displayName: 'Custom Fields',
name: 'customFieldUi',
placeholder: 'Add Custom Fields',
type: 'fixedCollection',
typeOptions: {
multipleValues: true,
},
default: {},
options: [
{
name: 'customFieldValues',
displayName: 'Custom Field',
values: [
{
displayName: 'Field ID',
name: 'id',
type: 'options',
typeOptions: {
loadOptionsMethod: 'getTeamFields',
},
default: '',
description: 'ID of the field to set.',
},
{
displayName: 'Field Value',
name: 'value',
type: 'string',
default: '',
description: 'Value of the field to set.',
},
{
displayName: 'Alt',
name: 'alt',
type: 'string',
default: '',
},
],
},
],
},
{
displayName: 'Email',
name: 'email',
type: 'string',
default: '',
description: `This field can only be changed by admins for users on paid teams.`,
},
{
displayName: 'First Name',
name: 'first_name',
type: 'string',
default: '',
},
{
displayName: 'Last Name',
name: 'last_name',
type: 'string',
default: '',
},
{
displayName: 'Status Emoji',
name: 'status_emoji',
type: 'string',
default: '',
description: `is a string referencing an emoji enabled for the Slack team, such as :mountain_railway:`,
},
{
displayName: 'Status Expiration',
name: 'status_expiration',
type: 'dateTime',
default: '',
description: `is an integer specifying seconds since the epoch, more commonly known as "UNIX time". Providing 0 or omitting this field results in a custom status that will not expire`,
},
{
displayName: 'Status Text',
name: 'status_text',
type: 'string',
default: '',
description: `allows up to 100 characters, though we strongly encourage brevity.`,
},
{
displayName: 'User ID',
name: 'user',
type: 'string',
default: '',
description: `ID of user to change. This argument may only be specified by team admins on paid teams.`,
},
],
},
/* -------------------------------------------------------------------------- */
/* userProfile:get */
/* -------------------------------------------------------------------------- */
{
displayName: 'Additional Fields',
name: 'additionalFields',
type: 'collection',
placeholder: 'Add Field',
default: {},
displayOptions: {
show: {
resource: [
'userProfile',
],
operation: [
'get',
],
},
},
options: [
{
displayName: 'Include Labels',
name: 'include_labels',
type: 'boolean',
default: false,
description: `Include labels for each ID in custom profile fields`,
},
{
displayName: 'User ID',
name: 'user',
type: 'string',
default: '',
description: `User to retrieve profile info for`,
},
],
},
] as INodeProperties[];