teambot-club/teambot

View on GitHub
bot/index.js

Summary

Maintainability
D
1 day
Test Coverage
var hasOauthServer = false,
    express = require('express'),
    botContext = require('bot/bot-context'),
    hookService = require('server/services/hook'),
    bodyParser = require('body-parser'),
    _skill;

var teambot = function() {
    var Botkit = require('botkit'),
        skillsLoader = require('bot/skills-loader'),
        settingsProvider = require('server/providers/settings-provider'),
        winston = require('winston'),
        middleware = require('bot/middleware');
    require('winston-mongodb').MongoDB;

    function log(message) {
        if (botContext.controller) {
            botContext.controller.log(message);
        }
    }

    function start(callback, skill) {
        _skill = skill;

        process.on('uncaughtException', function(err) {
            console.error(err, 'Uncaught Exception thrown');
            restart();
        });

        settingsProvider.getByScope('general', function(err, config) {
            var mongoUri = config.mongo,
                mongoStorage = require('botkit-storage-mongo')({ mongoUri: mongoUri });

            botContext.controller = Botkit.slackbot({
                logger: new winston.Logger({
                    levels: winston.config.syslog.levels,
                    transports: [
                        botContext.production ?
                        new(winston.transports.MongoDB)({ 'db': mongoUri + '/admin' }) :
                        new(winston.transports.Console)()
                    ]
                }),
                interactive_replies: true,
                debug: false,
                storage: mongoStorage,
                log: config.logging,
                logLevel: config.verbose

            });

            skillsLoader.installPredefinedSkills(botContext.controller, middleware, skill, function() {

                settingsProvider.getByScope('slack', function(err, config) {

                    if (!config || !config.clientId || !config.clientSecret || !config.redirectUri) {
                        console.log('Slack app is not configured!');
                        return;
                    }

                    // connect the bot to a stream of messages 
                    if (botContext.bot) {
                        return;
                    }

                    startSlackApp(config.clientId, config.clientSecret, config.redirectUri);

                    if (callback) {
                        callback();
                    }

                    console.log('Yor teambot is started successfully');
                });
            });

        });

    }

    function loadLocalUsers() {
        botContext.controller.storage.users.all(function(err, users) {
            if (err) {
                return;
            }
            botContext.localUsers = users;
        });
    }

    function startSlackApp(clientId, clientSecret, redirectUri) {

        loadLocalUsers();

        if (!hasOauthServer) {
            botContext.controller.configureSlackApp({
                clientId: clientId,
                clientSecret: clientSecret,
                redirectUri: redirectUri,
                scopes: ['bot']
            });

            settingsProvider.getByScope('general', function(err, config) {

                botContext.controller.setupWebserver(config.botkit, function() {
                    botContext.controller.createOauthEndpoints(botContext.controller.webserver, function(err, req, res) {
                        if (err) {
                            res.status(500).send(err);
                        } else {
                            settingsProvider.getByScope('general', function(err, config) {
                                loadLocalUsers();
                                res.redirect(req.protocol + '://' + req.hostname + ':' + config.server + '/#/done');
                            });
                        }
                    });
                });

                hasOauthServer = true;

                var hooksServer = express();
                hooksServer.use(bodyParser.json());

                // slack hooks
                botContext.controller.createWebhookEndpoints(hooksServer);
                // external hooks
                hooksServer.post('/hooks/:skill', hookService.postHook);

                hooksServer.listen(config.hooks, function() {
                    console.log('Hooks Server started on port ' + config.hooks);
                });

            });
        }

        function trackBot(bot) {
            botContext.bot = bot;
            botContext.controller.on('interactive_message_callback', function postInteractiveMessage(bot, message) {
                var callbackParts = message.callback_id.split(':');
                var skill = callbackParts[0];
                if (callbackParts.length > 1) {
                    var buttonsGroup = callbackParts[1];
                }

                try {
                    require(skill);
                } catch (ex) {
                    return bot.reply(message, "Invalid callbackId '" + message.callback_id + "'. The '" + skill + "' skill is not installed.");
                }

                try {
                    var targetButtonsFunction = require(skill + '/buttons');
                } catch (ex) {
                    return bot.reply(message, "Invalid callbackId '" + message.callback_id + "'. The '" + skill + "' skill does not support button clicks handling.");
                }

                try {
                    targetButtonsFunction(buttonsGroup, message, botContext.controller, bot);
                } catch (ex) {
                    return bot.reply(message, "Invalid callbackId '" + message.callback_id + "'. An exception occurred during button click handling: '" + ex.message + "'");
                }
            });
        }

        botContext.controller.on('create_bot', function(bot, config) {

            if (botContext.bot) {
                // already online! do nothing.
            } else {
                bot.startRTM(function(err) {
                    if (!err) {
                        trackBot(bot);
                    }

                    bot.startPrivateConversation({ user: config.createdBy }, function(err, convo) {
                        if (err) {
                            log(err);
                        } else {
                            convo.say('I am a bot that has just joined your team');
                            convo.say('You must now /invite me to a channel so that I can be of use!');
                        }
                    });
                });
            }
        });

        botContext.controller.storage.teams.all(function(err, teams) {
            if (err) {
                throw new Error(err);
            }

            // connect all teams with bots up to slack!
            for (var t in teams) {
                if (teams[t].bot) {
                    botContext.controller.spawn(teams[t]).startRTM(function(err, bot) {
                        if (err) {
                            log('Error connecting bot to Slack:', err);
                        } else {
                            trackBot(bot);
                        }
                    });
                }
            }
        });
    }

    function restart(callback) {
        if (botContext.bot) {
            botContext.bot.closeRTM();
            botContext.bot = null;
            botContext.controller = null;
            botContext.localUsers = null;
        }

        start(callback, _skill);
    }

    function installSkill(skillName, callback) {
        skillsLoader.install(botContext.controller, middleware, skillName, callback);
    }

    return {
        start: start,
        restart: restart,
        log: log,
        installSkill: installSkill
    };

}();

module.exports = teambot;