Skip to content

Commit 9cb1fe0

Browse files
committed
Update to Slack's conversations API after the old one was turned off.
1 parent f64aff3 commit 9cb1fe0

File tree

2 files changed

+47
-58
lines changed

2 files changed

+47
-58
lines changed

index.js

Lines changed: 45 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ var fs = require('fs');
2525
var express = require('express');
2626
var app = express();
2727

28-
var WebClient = require('@slack/client').WebClient;
28+
var WebClient = require('@slack/web-api').WebClient;
2929

3030
var config = JSON.parse(fs.readFileSync(process.argv[2]));
3131

@@ -50,7 +50,6 @@ function makeResponseCache(getter) {
5050

5151
var getTeamInfo = makeResponseCache(() => slack.team.info());
5252
var getUsersList = makeResponseCache(() => slack.users.list());
53-
var getImList = makeResponseCache(() => slack.im.list());
5453

5554
function escapeHTML(s) {
5655
return s.replace(/[&"<>]/g, function (c) {
@@ -103,6 +102,11 @@ function sendChannelFeed(req, res, count, info, messages, team, users) {
103102
var usersById = {};
104103
for (var u of users) usersById[u.id] = u;
105104

105+
if (!info.name) {
106+
// happens on IMs (FIXME not good for links)
107+
info.name = usersById[info.user].name;
108+
}
109+
106110
items = [];
107111
for (var message of messages) {
108112
var title = processMessageText(message.text || '', false, usersById, team);
@@ -124,6 +128,9 @@ function sendChannelFeed(req, res, count, info, messages, team, users) {
124128
if (message.subtype) {
125129
content += '<p style="font-size: 80%; color: #666666;">' + message.subtype + '</p>';
126130
}
131+
if (message.parent_user_id) {
132+
content += '<p style="font-size: 80%; color: #666666;">reply to ' + (usersById[message.parent_user_id].real_name || usersById[message.parent_user_id].name) + '</p>';
133+
}
127134
items.push({
128135
author: [{
129136
name: author.real_name + ' (' + author.name + ')',
@@ -238,14 +245,16 @@ function channelItem(channel, usersById, team, feedUrl) {
238245
}
239246

240247
app.get('/channels.xml', (req, res) => {
241-
Promise.all([slack.channels.list(), slack.groups.list(), getImList(), getTeamInfo(), getUsersList()])
242-
.then(args => {
243-
var channels = args[0].channels;
244-
var groups = args[1].groups;
245-
var ims = args[2].ims;
246-
var team = args[3].team;
247-
var users = args[4].members;
248-
248+
Promise.all([
249+
// for mpims we additionally want the members - the old groups.list API included that, but conversations.list does not
250+
slack.conversations.list({types: 'public_channel,private_channel,mpim,im'})
251+
.then(result => Promise.all(result.channels.filter(c => c.is_mpim).map(c => slack.conversations.members({channel: c.id}).then(m => { c.members = m.members; })))
252+
.then(_ => result)
253+
),
254+
getTeamInfo(),
255+
getUsersList()
256+
])
257+
.then(([{channels}, {team}, {members: users}]) => {
249258
for (var channel of channels) channelsByIdCache[channel.id] = channel;
250259

251260
var usersById = {};
@@ -257,12 +266,6 @@ app.get('/channels.xml', (req, res) => {
257266
for (var channel of channels) {
258267
items.push(channelItem(channel, usersById, team, feedUrl));
259268
}
260-
for (var group of groups) {
261-
items.push(channelItem(group, usersById, team, feedUrl));
262-
}
263-
for (var im of ims) {
264-
items.push(channelItem(im, usersById, team, feedUrl));
265-
}
266269
items.sort((i1, i2) => (i1.date < i2.date) ? 1 : (i1.date > i2.date) ? -1 : 0);
267270

268271
// feedvalidator says entries should have unique updated time stamps, which our #general and #random don't
@@ -290,6 +293,7 @@ app.get('/channels.xml', (req, res) => {
290293
})
291294
.catch(e => {
292295
res.status(500).send(e.toString() + '\n' + e.stack);
296+
console.log('Error building channels.xml:', e);
293297
});
294298
});
295299

@@ -299,52 +303,37 @@ app.get('/channel.xml', (req, res) => {
299303
if (!channelid) {
300304
res.status(404).send('id parameter needed\n');
301305
}
302-
else if (channelid.startsWith('C')) {
303-
Promise.all([slack.channels.info(channelid), slack.channels.history(channelid, {count: count}), getTeamInfo(), getUsersList()])
304-
.then(args => {
305-
info = args[0].channel;
306-
info.name_display_prefix = '#';
307-
sendChannelFeed(req, res, count, info, args[1].messages, args[2].team, args[3].members);
308-
})
309-
.catch(e => {
310-
res.status(500).send(e.toString() + '\n' + e.stack);
311-
});
312-
}
313-
else if (channelid.startsWith('G')) {
314-
Promise.all([slack.groups.info(channelid), slack.groups.history(channelid, {count: count}), getTeamInfo(), getUsersList()])
315-
.then(args => {
316-
info = args[0].group;
317-
info.name_display_prefix = info.is_mpim ? '' : '=';
318-
sendChannelFeed(req, res, count, info, args[1].messages, args[2].team, args[3].members);
319-
})
320-
.catch(e => {
321-
res.status(500).send(e.toString() + '\n' + e.stack);
322-
});
323-
}
324-
else if (channelid.startsWith('D')) {
325-
Promise.all([getImList(), slack.im.history(channelid, {count: count}), getTeamInfo(), getUsersList()])
326-
.then(args => {
327-
var info = { id: channelid, name: 'unknown IM', name_display_prefix: '@' };
328-
for (var i of args[0].ims) {
329-
if (i.id == channelid) {
330-
for (var u of args[3].members) {
331-
if (u.id == i.user) {
332-
info.name = u.name;
333-
break;
306+
else {
307+
Promise.all([
308+
slack.conversations.info({channel: channelid}),
309+
// for thread parents we additionally want the replies - the old channels.history API included those, but conversations.history does not
310+
// Note that this means we will miss new replies to old threads whose parent has already dropped out - I don't see any way around this in the API docs.
311+
slack.conversations.history({channel: channelid, count: count})
312+
.then(
313+
result => Promise.all(result.messages.filter(m => m.thread_ts !== undefined).map(
314+
m => slack.conversations.replies({channel: channelid, ts: m.thread_ts, limit: count})
315+
.then(replies => {
316+
for (var m of replies.messages) {
317+
if (!result.messages.find(rm => rm.ts == m.ts)) {
318+
result.messages.push(m);
319+
}
334320
}
335-
}
336-
break;
337-
}
338-
}
339-
sendChannelFeed(req, res, count, info, args[1].messages, args[2].team, args[3].members);
321+
})
322+
))
323+
.then(_ => result)
324+
),
325+
getTeamInfo(),
326+
getUsersList()
327+
])
328+
.then(([{channel}, {messages}, {team}, {members}]) => {
329+
info = channel;
330+
info.name_display_prefix = channelid.startsWith('C') ? '#' : channelid.startsWith('D') ? '@' : channel.is_mpim ? '' : channelid.startsWith('G') ? '=' : '?';
331+
sendChannelFeed(req, res, count, info, messages, team, members);
340332
})
341333
.catch(e => {
342334
res.status(500).send(e.toString() + '\n' + e.stack);
343335
});
344336
}
345-
else {
346-
res.status(404).send('unknown id type ' + channelid + '\n');
347-
}
348337
});
349338

350339
app.listen(config.port, () => {

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "slack-atom-bridge",
3-
"version": "1.0.0",
3+
"version": "2.0.0",
44
"description": "Converts Slack content into Atom feeds for local archival.",
55
"main": "index.js",
66
"scripts": {
@@ -10,7 +10,7 @@
1010
"license": "MIT",
1111
"private": true,
1212
"dependencies": {
13-
"@slack/client": "^3.6.0",
13+
"@slack/web-api": "^6.0.0",
1414
"express": "^4.14.0",
1515
"feed": "^0.3.0"
1616
}

0 commit comments

Comments
 (0)