Yogu/site-manager

View on GitHub
src/server.js

Summary

Maintainability
F
4 days
Test Coverage
var http = require('http');
var express = require("express");
var socketio = require('socket.io');
var Controller = require('./controller.js');
var objects = require('./objects.js');
var expressValidator = require('express-validator');
var bodyParser = require('body-parser');

require('q').longStackSupport = true;

expressValidator.validator.extend('isIdentifier', function (str) {
    if (typeof str != 'string')
        return false;
    return str.match(/[a-zA-Z0-9\-]+/) !== null;
});

exports.start = function(port, dir) {
    var app = express();
    var server = http.createServer(app);
    app.use(express.static(__dirname+'/../public'));
    app.use(require('express-promise')());
    app.use(expressValidator());
    app.use(bodyParser.json());
    var io = socketio.listen(server);
    io.set('log level', 2 /* do not log debug messages */);

    var controller = new Controller(dir);

    server.listen(port, function() {
        console.log('server started on port ' + port + ' for root dir ' + dir);
    });

    app.get('/api/sites', function(req, res) {
        controller.getSites().then(function(sites) {
            res.json(objects.extract( { sites: sites }, {
                'sites[]': {
                    '*': true,
                    dbConfig: [ 'type', 'host', 'user', 'database', 'path' ]
                }
            }));
        }).catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.post('/api/sites', function(req, res) {
        req.checkBody('siteName').isIdentifier();
        req.checkBody('branch').isIdentifier();
        var errors = req.validationErrors();
        if (errors)
            return res.send('Validation errors: ' + JSON.stringify(errors), 400);

        var task = controller.manager.addSiteTask(req.body.siteName, req.body.branch);
        controller.manager.schedule(task);
        res.json({taskID: task.id});
    });

    app.post('/api/gitlab-merge-request', function(req, res) {
        if (req.body.object_kind != 'merge_request') {
            return res.send('Only merge_request events supported', 400);
        }

        if (req.body.object_attributes.action != 'open') {
            return res.send('Only considering "open" events', 200);
        }

        req.checkBody('object_attributes.source_branch').isIdentifier();
        req.checkBody('object_attributes.target_branch').isIdentifier();
        var errors = req.validationErrors();
        if (errors) {
            return res.send('Validation errors: ' + JSON.stringify(errors), 400);
        }

        var siteName = 'mr' + req.body.object_attributes.iid;
        var sourceBranch = req.body.object_attributes.source_branch;
        var targetBranch = req.body.object_attributes.target_branch;

        var task = controller.manager.createMergeRequestSiteTask(siteName, sourceBranch, targetBranch);
        controller.manager.schedule(task);

        res.json({taskID: task.id});
    });

    app.post('/api/reload', function(req, res) {
        controller.reload();
        res.send(202 /* accepted */);
    });

    app.post('/api/fetch', function(req, res) {
        controller.manager.schedule(controller.manager.fetchTask());
        res.send(202 /* accepted */);
    });

    app.post('/api/sites/:site/upgrade', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            site.schedule(site.upgradeTask());
            res.send(202 /* accepted */);
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.post('/api/sites/:site/upgrade/:revision', function(req, res) {
        var revision = req.params.revision;
        if (revision.match(/^[a-f0-9]+$/) === null) {
            res.send(400);
            return;
        }
        controller.getSite(req.params.site)
            .then(function(site) {
                site.schedule(site.upgradeToRevisionTask(revision));
                res.send(200 /* accepted */);
            })
            .catch(function(e) {
                console.error(e.stack);
                res.send(500);
            });
    });

    app.post('/api/sites/:site/backups', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            var message = String(req.body.message || '').trim();
            message = message ? 'manual: ' + message : 'manual';
            site.schedule(site.backupTask(message));
            res.send(202 /* accepted */);
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.post('/api/sites/:site/reset', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            site.schedule(site.resetTask());
            res.send(202 /* accepted */);
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.post('/api/sites/:site/reset-staging', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            site.schedule(site.resetStagingTask());
            res.send(202 /* accepted */);
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.delete('/api/sites/:site', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            controller.manager.schedule(controller.manager.deleteSiteTask(site));
            res.send(202 /* accepted */);
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.get('/api/sites/:site/backups', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            return site.getBackups();
        })
        .then(function(backups) {
            res.json(objects.extract( { backups: backups }, {'backups[]': '*'}));
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.get('/api/sites/:site/backups/:revision', function(req, res) {
        controller.getSite(req.params.site)
            .then(function(site) {
                return site.getBackup(req.params.revision);
            })
            .then(function(backup) {
                res.json(objects.extract(backup, '*'));
            })
            .catch(function(e) {
                console.error(e.stack);
                res.send(500);
            });
    });

    app.post('/api/sites/:site/backups/:revision/restore', function(req, res) {
        controller.getSite(req.params.site)
            .then(function(site) {
                site.schedule(site.restoreTask(req.params.revision));
                res.send(200 /* accepted */);
            })
            .catch(function(e) {
                console.error(e.stack);
                res.send(500);
            });
    });

    app.get('/api/tasks', function(req, res) {
        controller.manager.getTasks(0, 20)
        .then(function(tasks) {
            res.json(objects.extract( { tasks: tasks }, {'tasks[]': '*'}));
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.get('/api/sites/:site/tasks', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            return site.getTasks(0, 20);
        })
        .then(function(tasks) {
            res.json(objects.extract( { tasks: tasks }, {'tasks[]': '*'}));
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.get('/api/sites/:site/tasks/:id', function(req, res) {
        controller.getSite(req.params.site)
        .then(function(site) {
            return site.getTask(req.params.id);
        })
        .then(function(task) {
            res.json(objects.extract(task, '*'));
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    app.get('/api/tasks/:id', function(req, res) {
        controller.manager.getTask(req.params.id)
        .then(function(task) {
            res.json(objects.extract(task, '*'));
        })
        .catch(function(e) {
            console.error(e.stack);
            res.send(500);
        });
    });

    controller.on('task:schedule', function(task) {
        var context = task.context;
        task = objects.extract(task, '*');
        task.site = context.name || null; // site name, if not site manager
        io.sockets.emit('task:schedule', task);
    });

    controller.on('task:status', function(task) {
        io.sockets.emit('task:status', task.id, task.status);
    });

    controller.on('task:log', function(task, message) {
        io.sockets.emit('task:log', task.id, message);
    });

    controller.on('site:load', function(site) {
        io.sockets.emit('site:load', site.name, objects.extract(site, '*'));
    });

    controller.on('site:backups', function(site) {
        io.sockets.emit('site:backups', site.name);
    });

    controller.on('manager:load', function(sites) {
        io.sockets.emit('manager:load');
    });

    return server;
};