Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
424 changes: 261 additions & 163 deletions apps/meteor/app/slackbridge/server/RocketAdapter.ts

Large diffs are not rendered by default.

119 changes: 77 additions & 42 deletions apps/meteor/app/slackbridge/server/SlackAPI.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
// This is a JS File that was renamed to TS so it won't lose its git history when converted to TS
// TODO: Remove the following lint/ts instructions when the file gets properly converted
/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */
// @ts-nocheck
import { serverFetch as fetch } from '@rocket.chat/server-fetch';
import type {
ChatDeleteArguments,
ChatPostMessageArguments,
ChatPostMessageResponse,
ChatUpdateArguments,
ConversationsHistoryArguments,
ConversationsHistoryResponse,
ConversationsInfoResponse,
ConversationsListResponse,
ConversationsMembersResponse,
PinsListResponse,
ReactionsAddArguments,
ReactionsRemoveArguments,
UsersInfoResponse,
} from '@slack/web-api';

export class SlackAPI {
constructor(apiOrBotToken) {
import type { ISlackAPI } from './definition/ISlackAPI';

export class SlackAPI implements ISlackAPI {
private token: string;

constructor(apiOrBotToken: string) {
this.token = apiOrBotToken;
}

async getChannels(cursor = null) {
let channels = [];
async getChannels(cursor: string | null = null): Promise<Required<ConversationsListResponse>['channels']> {
let channels: ConversationsListResponse['channels'] = [];
const request = await fetch('https://slack.com/api/conversations.list', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -22,11 +37,11 @@ export class SlackAPI {
...(cursor && { cursor }),
},
});
const response = await request.json();
const response: ConversationsListResponse = await request.json();

if (response && response && Array.isArray(response.channels) && response.channels.length > 0) {
if (response && Array.isArray(response.channels) && response.channels.length > 0) {
channels = channels.concat(response.channels);
if (response.response_metadata && response.response_metadata.next_cursor) {
if (response.response_metadata?.next_cursor) {
const nextChannels = await this.getChannels(response.response_metadata.next_cursor);
channels = channels.concat(nextChannels);
}
Expand All @@ -35,8 +50,8 @@ export class SlackAPI {
return channels;
}

async getGroups(cursor = null) {
let groups = [];
async getGroups(cursor: string | null = null): Promise<Required<ConversationsListResponse>['channels']> {
let groups: ConversationsListResponse['channels'] = [];
const request = await fetch('https://slack.com/api/conversations.list', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -48,11 +63,11 @@ export class SlackAPI {
...(cursor && { cursor }),
},
});
const response = await request.json();
const response: ConversationsListResponse = await request.json();

if (response && response && Array.isArray(response.channels) && response.channels.length > 0) {
if (response && Array.isArray(response.channels) && response.channels.length > 0) {
groups = groups.concat(response.channels);
if (response.response_metadata && response.response_metadata.next_cursor) {
if (response.response_metadata?.next_cursor) {
const nextGroups = await this.getGroups(response.response_metadata.next_cursor);
groups = groups.concat(nextGroups);
}
Expand All @@ -61,7 +76,7 @@ export class SlackAPI {
return groups;
}

async getRoomInfo(roomId) {
async getRoomInfo(roomId: string): Promise<ConversationsInfoResponse['channel']> {
const request = await fetch(`https://slack.com/api/conversations.info`, {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -71,14 +86,19 @@ export class SlackAPI {
include_num_members: true,
},
});
const response = await request.json();
return response && response && request.status === 200 && request.ok && response.channel;
const response: ConversationsInfoResponse = await request.json();
return (response && request.status === 200 && request.ok && response.channel) || undefined;
}

async getMembers(channelId) {
const { num_members } = this.getRoomInfo(channelId);
async getMembers(channelId: string): Promise<ConversationsMembersResponse['members']> {
const roomInfo = await this.getRoomInfo(channelId);
if (!roomInfo?.num_members) {
return [];
}

const { num_members } = roomInfo;
const MAX_MEMBERS_PER_CALL = 100;
let members = [];
let members: ConversationsMembersResponse['members'] = [];
let currentCursor = '';
for (let index = 0; index < num_members; index += MAX_MEMBERS_PER_CALL) {
// eslint-disable-next-line no-await-in-loop
Expand All @@ -94,9 +114,9 @@ export class SlackAPI {
});
// eslint-disable-next-line no-await-in-loop
const response = await request.json();
if (response && response && request.status === 200 && request.ok && Array.isArray(response.members)) {
if (response && request.status === 200 && request.ok && Array.isArray(response.members)) {
members = members.concat(response.members);
const hasMoreItems = response.response_metadata && response.response_metadata.next_cursor;
const hasMoreItems = response.response_metadata?.next_cursor;
if (hasMoreItems) {
currentCursor = response.response_metadata.next_cursor;
}
Expand All @@ -105,7 +125,7 @@ export class SlackAPI {
return members;
}

async react(data) {
async react(data: ReactionsAddArguments): Promise<boolean> {
const request = await fetch('https://slack.com/api/reactions.add', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -114,10 +134,10 @@ export class SlackAPI {
params: data,
});
const response = await request.json();
return response && request.status === 200 && response && request.ok;
return response && request.status === 200 && request.ok;
}

async removeReaction(data) {
async removeReaction(data: ReactionsRemoveArguments): Promise<boolean> {
const request = await fetch('https://slack.com/api/reactions.remove', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -126,10 +146,10 @@ export class SlackAPI {
params: data,
});
const response = await request.json();
return response && request.status === 200 && response && request.ok;
return response && request.status === 200 && request.ok;
}

async removeMessage(data) {
async removeMessage(data: ChatDeleteArguments): Promise<boolean> {
const request = await fetch('https://slack.com/api/chat.delete', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -138,10 +158,10 @@ export class SlackAPI {
params: data,
});
const response = await request.json();
return response && request.status === 200 && response && request.ok;
return response && request.status === 200 && request.ok;
}

async sendMessage(data) {
async sendMessage(data: ChatPostMessageArguments): Promise<ChatPostMessageResponse> {
const request = await fetch('https://slack.com/api/chat.postMessage', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -152,7 +172,7 @@ export class SlackAPI {
return request.json();
}

async updateMessage(data) {
async updateMessage(data: ChatUpdateArguments): Promise<boolean> {
const request = await fetch('https://slack.com/api/chat.update', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -161,10 +181,10 @@ export class SlackAPI {
params: data,
});
const response = await request.json();
return response && request.status === 200 && response && request.ok;
return response && request.status === 200 && request.ok;
}

async getHistory(options) {
async getHistory(options: ConversationsHistoryArguments): Promise<ConversationsHistoryResponse> {
const request = await fetch(`https://slack.com/api/conversations.history`, {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -175,7 +195,7 @@ export class SlackAPI {
return response;
}

async getPins(channelId) {
async getPins(channelId: string): Promise<PinsListResponse['items'] | undefined> {
const request = await fetch('https://slack.com/api/pins.list', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -185,10 +205,10 @@ export class SlackAPI {
},
});
const response = await request.json();
return response && response && request.status === 200 && request.ok && response.items;
return (response && request.status === 200 && request.ok && response.items) || undefined;
}

async getUser(userId) {
async getUser(userId: string): Promise<UsersInfoResponse['user'] | undefined> {
const request = await fetch('https://slack.com/api/users.info', {
headers: {
Authorization: `Bearer ${this.token}`,
Expand All @@ -198,29 +218,44 @@ export class SlackAPI {
},
});
const response = await request.json();
return response && response && request.status === 200 && request.ok && response.user;
return (response && request.status === 200 && request.ok && response.user) || undefined;
}

async getFile(fileUrl: string): Promise<Buffer<ArrayBufferLike> | undefined> {
const request = await fetch(fileUrl, {
headers: {
Authorization: `Bearer ${this.token}`,
},
});

// #ToDo: Confirm this works the same way as the old https.get code
const fileBuffer = await request.buffer();
if (request.status !== 200 || !request.ok) {
return undefined;
}
return fileBuffer;
}

static async verifyToken(token) {
static async verifyToken(token: string): Promise<boolean> {
const request = await fetch('https://slack.com/api/auth.test', {
headers: {
Authorization: `Bearer ${token}`,
},
method: 'POST',
});
const response = await request.json();
return response && response && request.status === 200 && request.ok && response.ok;
return response && request.status === 200 && request.ok && response.ok;
}

static async verifyAppCredentials({ botToken, appToken }) {
static async verifyAppCredentials({ botToken, appToken }: { botToken: string; appToken: string }): Promise<boolean> {
const request = await fetch('https://slack.com/api/apps.connections.open', {
headers: {
Authorization: `Bearer ${appToken}`,
},
method: 'POST',
});
const response = await request.json();
const isAppTokenOk = response && response && request.status === 200 && request.ok && response.ok;
const isAppTokenOk = response && request.status === 200 && request.ok && response.ok;
const isBotTokenOk = await this.verifyToken(botToken);
return isAppTokenOk && isBotTokenOk;
}
Expand Down
Loading
Loading