controllers/admin/app.js
/* jshint maxlen: 120 */
var express = require('express');
var router = express.Router();
var security = require('../security');
var Models = require('telepat-models');
var async = require('async');
var uuid = require('uuid');
router.use('/add', security.tokenValidation);
/**
* @api {post} /admin/app/add AppCreate
* @apiDescription Creates a application for the admin.
The request body should contain the application itself.
* @apiName AdminAppAdd
* @apiGroup Admin
* @apiVersion 0.4.0
*
* @apiHeader {String} Content-type application/json
* @apiHeader {String} Authorization
The authorization token obtained in the login endpoint.
Should have the format: <i>Bearer $TOKEN</i>
*
* @apiExample {json} Client Request
* {
* "icon": "fa-bullhorn",
* "name": "The Voice",
* "keys": [
* "3406870085495689e34d878f09faf52c"
* ]
* }
*
* @apiSuccessExample {json} Success Response
* {
* "status": 200,
* "content": {
* "admin_id": "email@example.com",
* "icon": "fa-bullhorn",
* "name": "The Voice",
* "type": "application",
* "keys": [
* "3406870085495689e34d878f09faf52c"
* ]
* }
* }
*
*/
router.post('/add', function (req, res, next) {
var newApp = req.body;
if (!newApp.name)
return next(new Models.TelepatError(Models.TelepatError.errors.MissingRequiredField, ['name']));
if(newApp.keys && newApp.keys.length != 0 && !Array.isArray(newApp.keys)) {
return next(new Models.TelepatError(Models.TelepatError.errors.InvalidFieldValue,
['"keys" is not an array']));
} else if (!newApp.keys || newApp.keys.length == 0) {
newApp['keys'] = [uuid.v4()];
}
newApp['admins'] = [req.user.id];
Models.Application.create(newApp, function (err, res1) {
if (err)
next(err);
else {
app.messagingClient.sendSystemMessages('_all', 'update_app', [{appId: res1.id, appObject: res1}], function(err) {
if (err)
Models.TelepatLogger.error('There was an error trying to send system message: ' + err.message);
});
Models.Application.loadedAppModels[res1.id] = res1;
res.status(200).json({status: 200, content: res1});
}
});
});
router.use('/remove',
security.tokenValidation);
/**
* @api {delete} /admin/app/remove RemoveApp
* @apiDescription Removes an application from the admin.
* @apiName AdminAppRemove
* @apiGroup Admin
* @apiVersion 0.4.0
*
* @apiHeader {String} Content-type application/json
* @apiHeader {String} Authorization
The authorization token obtained in the login endpoint.
Should have the format: <i>Bearer $TOKEN</i>
*
* @apiSuccessExample {json} Success Response
* {
* "status": 200,
* "content": "App removed"
* }
*
* @apiError (404) [011]ApplicationNotFound Application with that ID doesn't exist.
*
* @apiErrorExample {json} Error Response
* {
* "code": "011",
* "status": 404,
* "message": "Application with ID $APPID does not exist."
* }
*
*/
router.delete('/remove', function (req, res, next) {
var appId = req.body.id;
if (!appId)
return next(new Models.TelepatError(Models.TelepatError.errors.MissingRequiredField, ['id']));
if (!Models.Application.loadedAppModels[appId]) {
return next(new Models.TelepatError(Models.TelepatError.errors.ApplicationNotFound,
[appId]));
}
if (Models.Application.loadedAppModels[appId].admins.indexOf(req.user.id) === -1) {
return next(new Models.TelepatError(Models.TelepatError.errors.ApplicationForbidden));
}
Models.Application.delete(appId, function (err, res1) {
if (err)
next(err);
else {
app.messagingClient.sendSystemMessages('_all', 'delete_app', [{id: appId}], function(err) {
if (err)
Models.TelepatLogger.error('There was an error trying to send system message: ' + err.message);
});
delete Models.Application.loadedAppModels[appId];
res.status(200).json({status: 200, content: 'App removed'});
}
});
});
router.use('/update',
security.tokenValidation);
/**
* @api {post} /admin/app/update UpdateApp
* @apiDescription Updates an app
* @apiName AdminAppUpdate
* @apiGroup Admin
* @apiVersion 0.4.0
*
* @apiHeader {String} Content-type application/json
* @apiHeader {String} Authorization
The authorization token obtained in the login endpoint.
Should have the format: <i>Bearer $TOKEN</i>
*
* @apiExample {json} Client Request
* {
* "patches": [
* {
* "op": "replace",
* "path": "application/application_id/field_name",
* "value": "new value"
* }
* ]
* }
*
* @apiSuccessExample {json} Success Response
* {
* "status": 200,
* "content": "Updated"
* }
*
* @apiError (404) [011]ApplicationNotFound Application with that ID doesn't exist.
*
* @apiErrorExample {json} Error Response
* {
* "code": "011",
* "status": 404,
* "message": "Application with ID $APPID does not exist."
* }
*
*/
router.post('/update', function (req, res, next) {
if (Object.getOwnPropertyNames(req.body).length === 0) {
return next(new Models.TelepatError(Models.TelepatError.errors.RequestBodyEmpty));
} else if (!Array.isArray(req.body.patches)) {
return next(new Models.TelepatError(Models.TelepatError.errors.InvalidFieldValue,
['"patches" is not an array']));
} else if (req.body.patches.length == 0) {
return next(new Models.TelepatError(Models.TelepatError.errors.InvalidFieldValue,
['"patches" array is empty']));
} else {
var errors = false;
var appId = null;
req.body.patches.forEach(function(patch) {
if (!patch.path || errors)
return;
appId = patch.path.split('/')[1];
if (!appId) {
errors = true;
return next(new Models.TelepatError(Models.TelepatError.errors.InvalidPatch, ['missing ID in path']));
}
if (!Models.Application.loadedAppModels[appId]) {
return next(new Models.TelepatError(Models.TelepatError.errors.ApplicationNotFound,
[appId]));
}
if (Models.Application.loadedAppModels[appId].admins.indexOf(req.user.id) === -1) {
errors = true;
return next(new Models.TelepatError(Models.TelepatError.errors.ApplicationForbidden));
}
});
if (errors)
return;
Models.Application.update(appId, req.body.patches, function (err, result) {
if (err)
return next(err);
else {
app.messagingClient.sendSystemMessages('_all', 'update_app', [{appId: result.id, appObject: result}], function(err) {
if (err)
return Models.TelepatLogger.error('There was an error trying to send system message: ' + err.message);
});
Models.Application.loadedAppModels[appId] = result;
res.status(200).json({status: 200, content: 'Updated'});
}
});
}
});
router.use('/authorize',
security.tokenValidation,
security.applicationIdValidation,
security.adminAppValidation);
/**
* @api {post} /admin/app/authorize AuthorizeAdmin
* @apiDescription Authorizes an admin to an application
* @apiName AdminAuthorize
* @apiGroup Admin
* @apiVersion 0.4.0
*
* @apiHeader {String} Content-type application/json
* @apiHeader {String} Authorization
The authorization token obtained in the login endpoint.
Should have the format: <i>Bearer $TOKEN</i>
* @apiHeader {String} X-BLGREQ-APPID Custom header which contains the application ID
*
* @apiParam {string} email Email address of the admin to authorize for the application
*
* @apiExample {json} Client Request
* {
* "email": "admin@telepat.io"
* }
*
* @apiSuccessExample {json} Success Response
* {
* "status": 200,
* "content": "Admin added to application"
* }
*
* @apiError (404) [011]ApplicationNotFound Application with that ID doesn't exist.
* @apiError (404) [033]AdminNotFound Admin with that email address does not exist
* @apiError (409) [017]AdminAlreadyAuthorized Admin with email address already authorized for application
*
* @apiErrorExample {json} Error Response
* {
* "code": "011",
* "status": 404,
* "message": "Application with ID $APPID does not exist."
* }
*/
router.post('/authorize', function(req, res, next) {
if (Object.getOwnPropertyNames(req.body).length === 0) {
return next(new Models.TelepatError(Models.TelepatError.errors.RequestBodyEmpty));
} else if (!req.body.email) {
return next(new Models.TelepatError(Models.TelepatError.errors.MissingRequiredField, ['email']));
}
var appId = req._telepat.applicationId;
var adminEmail = req.body.email;
async.waterfall([
function(callback) {
Models.Admin({email: adminEmail}, callback);
},
function(admin, callback) {
if (Models.Application.loadedAppModels[appId].admins.indexOf(admin.id) !== -1) {
return callback(new Models.TelepatError(Models.TelepatError.errors.AdminAlreadyAuthorized));
}
var patches = [Models.Delta.formPatch(Models.Application.loadedAppModels[appId], 'append', {admins: admin.id})];
Models.Application.update(appId, patches, callback);
}
], function(err, application) {
if (err) return next(err);
Models.Application.loadedAppModels[appId] = application;
res.status(200).json({status: 200, content: 'Admin added to application'});
});
});
router.use('/deauthorize',
security.tokenValidation,
security.applicationIdValidation,
security.adminAppValidation);
/**
* @api {post} /admin/app/deauthorize DeauthorizeAdmin
* @apiDescription Deauthorizes an admin from an application
* @apiName AdminDeauthorize
* @apiGroup Admin
* @apiVersion 0.4.0
*
* @apiHeader {String} Content-type application/json
* @apiHeader {String} Authorization
The authorization token obtained in the login endpoint.
Should have the format: <i>Bearer $TOKEN</i>
* @apiHeader {String} X-BLGREQ-APPID Custom header which contains the application ID
*
* @apiParam {string} email Email address of the admin to deauthorize from the application
*
* @apiExample {json} Client Request
* {
* "email": "admin@telepat.io"
* }
*
* @apiSuccessExample {json} Success Response
* {
* "status": 200,
* "content": "Admin removed from application"
* }
*
* @apiError (404) [011]ApplicationNotFound Application with that ID doesn't exist.
* @apiError (404) [033]AdminNotFound Admin with that email address does not exist.
* @apiError (404) [019]AdminNotFoundInApplication Admin does not belong to this application.
* @apiError (409) [018]AdminDeauthorizeLastAdmin Admin with email address cannot be deauthorized because he's the
* only one left. We can't have "orphan" applications.
*
* @apiErrorExample {json} Error Response
* {
* "code": "011",
* "status": 404,
* "message": "Application with ID $APPID does not exist."
* }
*
*/
router.post('/deauthorize', function(req, res, next) {
if (Object.getOwnPropertyNames(req.body).length === 0) {
return next(new Models.TelepatError(Models.TelepatError.errors.RequestBodyEmpty));
} else if (!req.body.email) {
return next(new Models.TelepatError(Models.TelepatError.errors.MissingRequiredField, ['email']));
}
var appId = req._telepat.applicationId;
var adminEmail = req.body.email;
if (adminEmail == req.user.email && Models.Application.loadedAppModels[appId].admins.indexOf(req.user.id) == 0
&& Models.Application.loadedAppModels[appId].admins.length == 1) {
return next(new Models.TelepatError(Models.TelepatError.errors.AdminDeauthorizeLastAdmin));
}
async.waterfall([
function(callback) {
Models.Admin({email: adminEmail}, callback);
},
function(admin, callback) {
if (Models.Application.loadedAppModels[appId].admins.indexOf(admin.id) === -1) {
return callback(new Models.TelepatError(Models.TelepatError.errors.AdminNotFoundInApplication, [adminEmail]));
} else {
var patches = [Models.Delta.formPatch(Models.Application.loadedAppModels[appId], 'remove', {admins: admin.id})];
Models.Application.update(appId, patches, callback);
}
}
], function(err, application) {
if (err) return next(err);
Models.Application.loadedAppModels[appId] = application;
res.status(200).json({status: 200, content: 'Admin removed from application'});
});
});
module.exports = router;