Selaa lähdekoodia

Added HTTP API route to annoy people on Slack

Fela Maslen 7 vuotta sitten
vanhempi
commit
a83bb1351c

+ 2 - 0
src/server/config.js

@@ -9,6 +9,8 @@ if (__DEV__) {
 module.exports = () => ({
     __PROD__,
     __DEV__,
+    annoyMessage: '%s: please complete your time sheets for the previous week.',
+    completeMessage: 'Everybody has done their time sheets. *High five*',
     slack: {
         token: process.env.SLACK_TOKEN || '',
         webhookUrl: process.env.SLACK_WEBHOOK_URL || ''

+ 47 - 2
src/server/modules/slack.js

@@ -1,14 +1,58 @@
-const { WebClient: SlackWebClient } = require('@slack/client');
+const { WebClient, IncomingWebhook } = require('@slack/client');
 const humanizeDuration = require('humanize-duration');
+const { sprintf } = require('sprintf-js');
 
 const EMAIL_REGEX = /^(.*)@(.*)$/;
 
+function generateAnnoyMessage(config, now, usersList) {
+    if (!usersList.length) {
+        const isMonday = now.weekday() === 1;
+        if (isMonday) {
+            return config.completeMessage;
+        }
+
+        return null;
+    }
+
+    return sprintf(config.annoyMessage, usersList.join(', '));
+}
+
+function annoySlackUsers(config, logger, now, users) {
+    const usersList = users.map(({ id }) => `<@${id}>`);
+
+    const message = generateAnnoyMessage(config, now, usersList);
+
+    if (!message) {
+        logger.debug('[SLACK] Not annoying users');
+
+        return null;
+    }
+
+    logger.debug('[SLACK] Annoying users...');
+    const t0 = Date.now();
+
+    const webhook = new IncomingWebhook(config.slack.webhookUrl);
+
+    return new Promise((resolve, reject) => {
+        webhook.send(message, err => {
+            const t1 = Date.now();
+            logger.debug(`[SLACK] Took ${humanizeDuration(t1 - t0)} to send message to Slack channel`);
+
+            if (err) {
+                return reject(err);
+            }
+
+            return resolve(message);
+        });
+    });
+}
+
 function getAllSlackUsersWithNames(config, logger) {
     return new Promise((resolve, reject) => {
         logger.debug('[SLACK] Getting all Slack user details...');
         const t0 = Date.now();
 
-        const webClient = new SlackWebClient(config.slack.token);
+        const webClient = new WebClient(config.slack.token);
 
         webClient.users.list({}, (err, info) => {
             if (err) {
@@ -43,6 +87,7 @@ function getAllSlackUsersWithNames(config, logger) {
 }
 
 module.exports = {
+    annoySlackUsers,
     getAllSlackUsersWithNames
 };
 

+ 65 - 0
src/server/routes/annoy.js

@@ -0,0 +1,65 @@
+const moment = require('moment');
+
+const {
+    getUsers
+} = require('server/modules/users');
+
+const {
+    getAllSlackUsersWithNames,
+    annoySlackUsers
+} = require('server/modules/slack');
+
+const {
+    getAllUsersOnHoliday
+} = require('server/modules/whosoff');
+
+const {
+    getUsersWithMissingTimesheets
+} = require('server/modules/synergist');
+
+function getPreviousWeekPeriod(now) {
+    const start = now.clone()
+        .startOf('isoWeek')
+        .subtract(1, 'weeks');
+
+    const end = now.clone()
+        .startOf('isoWeek')
+        .subtract(1, 'days')
+        .endOf('day');
+
+    return { start, end };
+}
+
+function annoyUsers(config, db, logger) {
+    return async (req, res) => {
+        const now = moment();
+
+        const range = getPreviousWeekPeriod(now);
+
+        const validUsers = await getUsers(db);
+
+        const validUserEmails = validUsers.map(({ email }) => email.toLowerCase());
+
+        const [slackUsers, usersOnHoliday] = await Promise.all([
+            getAllSlackUsersWithNames(config, logger),
+            getAllUsersOnHoliday(config, logger, now)
+        ]);
+
+        const users = slackUsers.filter(({ email }) =>
+            validUserEmails.includes(email) &&
+            !usersOnHoliday.includes(email)
+        );
+
+        const usersMissingTimesheet = await getUsersWithMissingTimesheets(config, logger, range, users);
+
+        await annoySlackUsers(config, logger, now, usersMissingTimesheet);
+
+        res.json({ ok: true });
+    };
+}
+
+module.exports = {
+    getPreviousWeekPeriod,
+    annoyUsers
+};
+

+ 5 - 2
src/server/routes/index.js

@@ -1,8 +1,9 @@
 const { Router } = require('express');
 
 const { employees } = require('server/routes/employees');
+const { annoyUsers } = require('server/routes/annoy');
 
-function apiRoutes(config, db) {
+function apiRoutes(config, db, logger) {
     const router = new Router();
 
     router.get('/health', (req, res) => {
@@ -11,6 +12,8 @@ function apiRoutes(config, db) {
 
     router.use('/employees', employees(config, db));
 
+    router.post('/annoy', annoyUsers(config, db, logger));
+
     // eslint-disable-next-line no-unused-vars
     router.use((err, req, res, next) => {
         let statusCode = 500;
@@ -19,7 +22,7 @@ function apiRoutes(config, db) {
         }
 
         res.status(statusCode)
-            .json({ err: err.message });
+            .json({ err: err.stack });
     });
 
     return router;

+ 80 - 0
test/server/routes/annoy.spec.js

@@ -0,0 +1,80 @@
+const { expect } = require('chai');
+const itEach = require('it-each');
+const moment = require('moment');
+
+const {
+    getPreviousWeekPeriod
+} = require('server/routes/annoy');
+
+describe('Annoy route', () => {
+    describe('getPreviousWeekPeriod', () => {
+        itEach();
+
+        it.each([
+            {
+                key: 'Monday-1',
+                now: '2019-01-14T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Tuesday-1',
+                now: '2019-01-15T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Wednesday-1',
+                now: '2019-01-16T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Thursday-1',
+                now: '2019-01-17T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Friday-1',
+                now: '2019-01-18T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Saturday-1',
+                now: '2019-01-19T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Sunday-1',
+                now: '2019-01-20T06:00Z',
+                start: '2019-01-07T00:00:00.000Z',
+                end: '2019-01-13T23:59:59.999Z'
+            },
+            {
+                key: 'Monday-2',
+                now: '2019-01-21T06:00Z',
+                start: '2019-01-14T00:00:00.000Z',
+                end: '2019-01-20T23:59:59.999Z'
+            },
+            {
+                key: 'Tuesday-2',
+                now: '2019-01-21T06:00Z',
+                start: '2019-01-14T00:00:00.000Z',
+                end: '2019-01-20T23:59:59.999Z'
+            }
+        ], 'should fetch the start and end of the previous working week', ({ now, start, end }) => {
+
+            const {
+                start: startResult,
+                end: endResult
+            } = getPreviousWeekPeriod(moment(now));
+
+            expect(startResult.toISOString()).to.equal(start);
+            expect(endResult.toISOString()).to.equal(end);
+        });
+    });
+});
+