mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 15:17:25 +01:00
feat(api): Send flag notifications to slack
This commit is contained in:
@@ -74,5 +74,9 @@
|
|||||||
"APP_ID": "appId",
|
"APP_ID": "appId",
|
||||||
"KEY": "key",
|
"KEY": "key",
|
||||||
"SECRET": "secret"
|
"SECRET": "secret"
|
||||||
|
},
|
||||||
|
"SLACK": {
|
||||||
|
"FLAGGING_URL": "https://hooks.slack.com/services/id/id/id",
|
||||||
|
"FLAGGING_FOOTER_LINK": "https://crookedneighbor.github.io/flag-o-rama/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
"version": "3.37.0",
|
"version": "3.37.0",
|
||||||
"main": "./website/server/index.js",
|
"main": "./website/server/index.js",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@slack/client": "slackhq/node-slack-sdk#2ee794cd31326c54f38c518eef2b9d223327d939",
|
||||||
"accepts": "^1.3.2",
|
"accepts": "^1.3.2",
|
||||||
"amazon-payments": "0.0.4",
|
"amazon-payments": "0.0.4",
|
||||||
"amplitude": "^2.0.3",
|
"amplitude": "^2.0.3",
|
||||||
@@ -89,12 +90,12 @@
|
|||||||
"superagent": "^1.8.3",
|
"superagent": "^1.8.3",
|
||||||
"swagger-node-express": "lefnire/swagger-node-express#habitrpg",
|
"swagger-node-express": "lefnire/swagger-node-express#habitrpg",
|
||||||
"universal-analytics": "~0.3.2",
|
"universal-analytics": "~0.3.2",
|
||||||
|
"useragent": "2.1.9",
|
||||||
"uuid": "^2.0.1",
|
"uuid": "^2.0.1",
|
||||||
"validator": "^4.9.0",
|
"validator": "^4.9.0",
|
||||||
"vinyl-buffer": "^1.0.0",
|
"vinyl-buffer": "^1.0.0",
|
||||||
"vinyl-source-stream": "^1.1.0",
|
"vinyl-source-stream": "^1.1.0",
|
||||||
"winston": "^2.1.0",
|
"winston": "^2.1.0"
|
||||||
"useragent": "2.1.9"
|
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
97
test/api/v3/unit/libs/slack.js
Normal file
97
test/api/v3/unit/libs/slack.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
/* eslint-disable camelcase */
|
||||||
|
import { IncomingWebhook } from '@slack/client';
|
||||||
|
import slack from '../../../../../website/server/libs/slack';
|
||||||
|
import { TAVERN_ID } from '../../../../../website/server/models/group';
|
||||||
|
|
||||||
|
describe('slack', () => {
|
||||||
|
describe('sendFlagNotification', () => {
|
||||||
|
let flagger, group, message;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
sandbox.stub(IncomingWebhook.prototype, 'send');
|
||||||
|
flagger = {
|
||||||
|
id: 'flagger-id',
|
||||||
|
profile: {
|
||||||
|
name: 'flagger',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
group = {
|
||||||
|
id: 'group-id',
|
||||||
|
privacy: 'private',
|
||||||
|
name: 'Some group',
|
||||||
|
type: 'guild',
|
||||||
|
};
|
||||||
|
message = {
|
||||||
|
id: 'chat-id',
|
||||||
|
user: 'Author',
|
||||||
|
uuid: 'author-id',
|
||||||
|
text: 'some text',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
IncomingWebhook.prototype.send.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sends a slack webhook', () => {
|
||||||
|
slack.sendFlagNotification({
|
||||||
|
flagger,
|
||||||
|
group,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
||||||
|
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||||
|
text: 'flagger (flagger-id) flagged a message',
|
||||||
|
attachments: [{
|
||||||
|
fallback: 'Flag Message',
|
||||||
|
color: 'danger',
|
||||||
|
author_name: 'Author - author-id',
|
||||||
|
title: 'Flag in Some group - (private guild)',
|
||||||
|
title_link: undefined,
|
||||||
|
text: 'some text',
|
||||||
|
footer: sandbox.match(/<.*?groupId=group-id&chatId=chat-id\|Flag this message>/),
|
||||||
|
mrkdwn_in: [
|
||||||
|
'text',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes a title link if guild is public', () => {
|
||||||
|
group.privacy = 'public';
|
||||||
|
|
||||||
|
slack.sendFlagNotification({
|
||||||
|
flagger,
|
||||||
|
group,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
|
||||||
|
attachments: [sandbox.match({
|
||||||
|
title: 'Flag in Some group',
|
||||||
|
title_link: sandbox.match(/.*\/#\/options\/groups\/guilds\/group-id/),
|
||||||
|
})],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('links to tavern', () => {
|
||||||
|
group.privacy = 'public';
|
||||||
|
group.name = 'Tavern';
|
||||||
|
group.id = TAVERN_ID;
|
||||||
|
|
||||||
|
slack.sendFlagNotification({
|
||||||
|
flagger,
|
||||||
|
group,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(IncomingWebhook.prototype.send).to.be.calledWithMatch({
|
||||||
|
attachments: [sandbox.match({
|
||||||
|
title: 'Flag in Tavern',
|
||||||
|
title_link: sandbox.match(/.*\/#\/options\/groups\/tavern/),
|
||||||
|
})],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { removeFromArray } from '../../libs/collectionManipulators';
|
import { removeFromArray } from '../../libs/collectionManipulators';
|
||||||
import { getUserInfo, getGroupUrl, sendTxn } from '../../libs/email';
|
import { getUserInfo, getGroupUrl, sendTxn } from '../../libs/email';
|
||||||
|
import slack from '../../libs/slack';
|
||||||
import pusher from '../../libs/pusher';
|
import pusher from '../../libs/pusher';
|
||||||
import nconf from 'nconf';
|
import nconf from 'nconf';
|
||||||
import Bluebird from 'bluebird';
|
import Bluebird from 'bluebird';
|
||||||
@@ -265,6 +266,12 @@ api.flagChat = {
|
|||||||
{name: 'GROUP_URL', content: groupUrl},
|
{name: 'GROUP_URL', content: groupUrl},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
slack.sendFlagNotification({
|
||||||
|
flagger: user,
|
||||||
|
group,
|
||||||
|
message,
|
||||||
|
});
|
||||||
|
|
||||||
res.respond(200, message);
|
res.respond(200, message);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
48
website/server/libs/slack.js
Normal file
48
website/server/libs/slack.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/* eslint-disable camelcase */
|
||||||
|
import { IncomingWebhook } from '@slack/client';
|
||||||
|
import { TAVERN_ID } from '../models/group';
|
||||||
|
import nconf from 'nconf';
|
||||||
|
|
||||||
|
const SLACK_FLAGGING_URL = nconf.get('SLACK:FLAGGING_URL');
|
||||||
|
const SLACK_FLAGGING_FOOTER_LINK = nconf.get('SLACK:FLAGGING_FOOTER_LINK');
|
||||||
|
const BASE_URL = nconf.get('BASE_URL');
|
||||||
|
|
||||||
|
let flagSlack = new IncomingWebhook(SLACK_FLAGGING_URL);
|
||||||
|
|
||||||
|
function sendFlagNotification ({
|
||||||
|
flagger,
|
||||||
|
group,
|
||||||
|
message,
|
||||||
|
}) {
|
||||||
|
let titleLink;
|
||||||
|
let title = `Flag in ${group.name}`;
|
||||||
|
let text = `${flagger.profile.name} (${flagger.id}) flagged a message`;
|
||||||
|
|
||||||
|
if (group.id === TAVERN_ID) {
|
||||||
|
titleLink = `${BASE_URL}/#/options/groups/tavern`;
|
||||||
|
} else if (group.privacy === 'public') {
|
||||||
|
titleLink = `${BASE_URL}/#/options/groups/guilds/${group.id}`;
|
||||||
|
} else {
|
||||||
|
title += ` - (${group.privacy} ${group.type})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
flagSlack.send({
|
||||||
|
text,
|
||||||
|
attachments: [{
|
||||||
|
fallback: 'Flag Message',
|
||||||
|
color: 'danger',
|
||||||
|
author_name: `${message.user} - ${message.uuid}`,
|
||||||
|
title,
|
||||||
|
title_link: titleLink,
|
||||||
|
text: message.text,
|
||||||
|
footer: `<${SLACK_FLAGGING_FOOTER_LINK}?groupId=${group.id}&chatId=${message.id}|Flag this message>`,
|
||||||
|
mrkdwn_in: [
|
||||||
|
'text',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
sendFlagNotification,
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user