1
0
Fork 0
mirror of https://github.com/openstf/stf synced 2025-10-04 10:19:30 +02:00
OpenSTF/lib/units/api/controllers/users.js
2019-06-12 10:29:07 +02:00

398 lines
12 KiB
JavaScript

/**
* Copyright © 2019 code initially contributed by Orange SA, authors: Denis Barbaron - Licensed under the Apache license 2.0
**/
const dbapi = require('../../../db/api')
const _ = require('lodash')
const apiutil = require('../../../util/apiutil')
const lockutil = require('../../../util/lockutil')
const Promise = require('bluebird')
const wire = require('../../../wire')
const wireutil = require('../../../wire/util')
const userapi = require('./user')
/* --------------------------------- PRIVATE FUNCTIONS --------------------------------------- */
function userApiWrapper(fn, req, res) {
const email = req.swagger.params.email.value
dbapi.loadUser(email).then(function(user) {
if (!user) {
apiutil.respond(res, 404, 'Not Found (user)')
}
else {
req.user = user
fn(req, res)
}
})
.catch(function(err) {
apiutil.internalError(res, 'Failed to wrap "%s": ', fn.name, err.stack)
})
}
function getPublishedUser(user, userEmail, adminEmail, fields) {
let publishedUser = apiutil.publishUser(user)
if (userEmail !== adminEmail) {
publishedUser = _.pick(user, 'email', 'name', 'privilege')
}
if (fields) {
publishedUser = _.pick(publishedUser, fields.split(','))
}
return publishedUser
}
function removeUser(email, req, res) {
const groupOwnerState = req.swagger.params.groupOwner.value
const anyGroupOwnerState = typeof groupOwnerState === 'undefined'
const lock = {}
function removeGroupUser(owner, id) {
const lock = {}
return dbapi.lockGroupByOwner(owner, id).then(function(stats) {
if (!stats.replaced) {
return apiutil.lightComputeStats(res, stats)
}
lock.group = stats.changes[0].new_val
return owner === email ?
dbapi.deleteUserGroup(id) :
dbapi.removeGroupUser(id, email)
})
.finally(function() {
lockutil.unlockGroup(lock)
})
}
function deleteUserInDatabase(channel) {
return dbapi.removeUserAccessTokens(email).then(function() {
return dbapi.deleteUser(email).then(function() {
req.options.pushdev.send([
channel
, wireutil.envelope(new wire.DeleteUserMessage(
email
))
])
return 'deleted'
})
})
}
function computeUserGroupOwnership(groups) {
if (anyGroupOwnerState) {
return Promise.resolve(true)
}
return Promise.map(groups, function(group) {
if (!groupOwnerState && group.owner.email === email) {
return Promise.reject('filtered')
}
return !groupOwnerState || group.owner.email === email
})
.then(function(results) {
return _.without(results, false).length > 0
})
.catch(function(err) {
if (err === 'filtered') {
return false
}
throw err
})
}
if (req.user.email === email) {
return Promise.resolve('forbidden')
}
return dbapi.lockUser(email).then(function(stats) {
if (!stats.replaced) {
return apiutil.lightComputeStats(res, stats)
}
const user = lock.user = stats.changes[0].new_val
return dbapi.getGroupsByUser(user.email).then(function(groups) {
return computeUserGroupOwnership(groups).then(function(doContinue) {
if (!doContinue) {
return 'unchanged'
}
return Promise.each(groups, function(group) {
return removeGroupUser(group.owner.email, group.id)
})
.then(function() {
return deleteUserInDatabase(user.group)
})
})
})
})
.finally(function() {
lockutil.unlockUser(lock)
})
}
/* --------------------------------- PUBLIC FUNCTIONS --------------------------------------- */
function getUserInfo(req, email) {
const fields = req.swagger.params.fields.value
return dbapi.loadUser(email).then(function(user) {
if (user) {
return dbapi.getRootGroup().then(function(group) {
return getPublishedUser(user, req.user.email, group.owner.email, fields)
})
}
return false
})
}
function updateUserGroupsQuotas(req, res) {
const email = req.swagger.params.email.value
const duration =
typeof req.swagger.params.duration.value !== 'undefined' ?
req.swagger.params.duration.value :
null
const number =
typeof req.swagger.params.number.value !== 'undefined' ?
req.swagger.params.number.value :
null
const repetitions =
typeof req.swagger.params.repetitions.value !== 'undefined' ?
req.swagger.params.repetitions.value :
null
const lock = {}
lockutil.lockUser(email, res, lock).then(function(lockingSuccessed) {
if (lockingSuccessed) {
return dbapi.updateUserGroupsQuotas(email, duration, number, repetitions)
.then(function(stats) {
if (stats.replaced) {
return apiutil.respond(res, 200, 'Updated (user quotas)', {
user: apiutil.publishUser(stats.changes[0].new_val)
})
}
if ((duration === null || duration === lock.user.groups.quotas.allocated.duration) &&
(number === null || number === lock.user.groups.quotas.allocated.number) &&
(repetitions === null || repetitions === lock.user.groups.quotas.repetitions)
) {
return apiutil.respond(res, 200, 'Unchanged (user quotas)', {user: {}})
}
return apiutil.respond(
res
, 400
, 'Bad Request (quotas must be >= actual consumed resources)')
})
}
return false
})
.catch(function(err) {
apiutil.internalError(res, 'Failed to update user groups quotas: ', err.stack)
})
.finally(function() {
lockutil.unlockUser(lock)
})
}
function updateDefaultUserGroupsQuotas(req, res) {
const duration =
typeof req.swagger.params.duration.value !== 'undefined' ?
req.swagger.params.duration.value :
null
const number =
typeof req.swagger.params.number.value !== 'undefined' ?
req.swagger.params.number.value :
null
const repetitions =
typeof req.swagger.params.repetitions.value !== 'undefined' ?
req.swagger.params.repetitions.value :
null
const lock = {}
lockutil.lockUser(req.user.email, res, lock).then(function(lockingSuccessed) {
if (lockingSuccessed) {
return dbapi.updateDefaultUserGroupsQuotas(req.user.email, duration, number, repetitions)
.then(function(stats) {
if (stats.replaced) {
return apiutil.respond(res, 200, 'Updated (user default quotas)', {
user: apiutil.publishUser(stats.changes[0].new_val)
})
}
return apiutil.respond(res, 200, 'Unchanged (user default quotas)', {user: {}})
})
}
return false
})
.catch(function(err) {
apiutil.internalError(res, 'Failed to update default user groups quotas: ', err.stack)
})
.finally(function() {
lockutil.unlockUser(lock)
})
}
function getUserByEmail(req, res) {
const email = req.swagger.params.email.value
getUserInfo(req, email).then(function(user) {
if (user) {
apiutil.respond(res, 200, 'User Information', {user: user})
}
else {
apiutil.respond(res, 404, 'Not Found (user)')
}
})
.catch(function(err) {
apiutil.internalError(res, 'Failed to get user: ', err.stack)
})
}
function getUsers(req, res) {
const fields = req.swagger.params.fields.value
dbapi.getUsers().then(function(users) {
return dbapi.getRootGroup().then(function(group) {
apiutil.respond(res, 200, 'Users Information', {
users: users.map(function(user) {
return getPublishedUser(user, req.user.email, group.owner.email, fields)
})
})
})
})
.catch(function(err) {
apiutil.internalError(res, 'Failed to get users: ', err.stack)
})
}
function createUser(req, res) {
const email = req.swagger.params.email.value
const name = req.swagger.params.name.value
dbapi.createUser(email, name, req.user.ip).then(function(stats) {
if (!stats.inserted) {
apiutil.respond(res, 403, 'Forbidden (user already exists)')
}
else {
apiutil.respond(res, 201, 'Created (user)', {
user: apiutil.publishUser(stats.changes[0].new_val)
})
}
})
.catch(function(err) {
apiutil.internalError(res, 'Failed to create user: ', err.stack)
})
}
function deleteUsers(req, res) {
const emails = apiutil.getBodyParameter(req.body, 'emails')
const target = apiutil.getQueryParameter(req.swagger.params.redirected) ? 'user' : 'users'
function removeUsers(emails) {
let results = []
return Promise.each(emails, function(email) {
return removeUser(email, req, res).then(function(result) {
results.push(result)
})
})
.then(function() {
results = _.without(results, 'unchanged')
if (!results.length) {
return apiutil.respond(res, 200, `Unchanged (${target})`)
}
results = _.without(results, 'not found')
if (!results.length) {
return apiutil.respond(res, 404, `Not Found (${target})`)
}
results = _.without(results, 'forbidden')
if (!results.length) {
apiutil.respond(res, 403, `Forbidden (${target})`)
}
return apiutil.respond(res, 200, `Deleted (${target})`)
})
.catch(function(err) {
if (err !== 'busy') {
throw err
}
})
}
(function() {
if (typeof emails === 'undefined') {
return dbapi.getEmails().then(function(emails) {
return removeUsers(emails)
})
}
else {
return removeUsers(_.without(emails.split(','), ''))
}
})()
.catch(function(err) {
apiutil.internalError(res, 'Failed to delete ${target}: ', err.stack)
})
}
function deleteUser(req, res) {
apiutil.redirectApiWrapper('email', deleteUsers, req, res)
}
function createUserAccessToken(req, res) {
userApiWrapper(userapi.createAccessToken, req, res)
}
function deleteUserAccessToken(req, res) {
userApiWrapper(userapi.deleteAccessToken, req, res)
}
function deleteUserAccessTokens(req, res) {
userApiWrapper(userapi.deleteAccessTokens, req, res)
}
function getUserAccessToken(req, res) {
userApiWrapper(userapi.getAccessToken, req, res)
}
function getUserAccessTokens(req, res) {
userApiWrapper(userapi.getAccessTokens, req, res)
}
function getUserDevices(req, res) {
userApiWrapper(userapi.getUserDevices, req, res)
}
function getUserDevice(req, res) {
userApiWrapper(userapi.getUserDeviceBySerial, req, res)
}
function addUserDevice(req, res) {
userApiWrapper(userapi.addUserDevice, req, res)
}
function deleteUserDevice(req, res) {
userApiWrapper(userapi.deleteUserDeviceBySerial, req, res)
}
function remoteConnectUserDevice(req, res) {
userApiWrapper(userapi.remoteConnectUserDeviceBySerial, req, res)
}
function remoteDisconnectUserDevice(req, res) {
userApiWrapper(userapi.remoteDisconnectUserDeviceBySerial, req, res)
}
module.exports = {
updateUserGroupsQuotas: updateUserGroupsQuotas
, updateDefaultUserGroupsQuotas: updateDefaultUserGroupsQuotas
, getUsers: getUsers
, getUserByEmail: getUserByEmail
, getUserInfo: getUserInfo
, createUser: createUser
, deleteUser: deleteUser
, deleteUsers: deleteUsers
, createUserAccessToken: createUserAccessToken
, deleteUserAccessToken: deleteUserAccessToken
, deleteUserAccessTokens: deleteUserAccessTokens
, getUserAccessTokensV2: getUserAccessTokens
, getUserAccessToken: getUserAccessToken
, getUserDevicesV2: getUserDevices
, getUserDevice: getUserDevice
, addUserDeviceV3: addUserDevice
, deleteUserDevice: deleteUserDevice
, remoteConnectUserDevice: remoteConnectUserDevice
, remoteDisconnectUserDevice: remoteDisconnectUserDevice
}