Next.js+React web interface for controlling HAProxy clusters (groups of servers), in conjunction with with https://gitgud.io/fatchan/haproxy-protection.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

94 lines
3.1 KiB

const db = require('../db.js');
const { validClustersString, makeArrayIfSingle, extractMap, dynamicResponse } = require('../util.js');
exports.clustersPage = async (app, req, res, next) => {
return app.render(req, res, '/clusters', {
csrf: req.csrfToken(),
});
};
exports.clustersJson = async (req, res, next) => {
return res.json({
csrf: req.csrfToken(),
user: res.locals.user,
});
}
/**
* POST /cluster
* set active cluster
*/
exports.setCluster = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
return dynamicResponse(req, res, 403, { error: 'Changing cluster is only supported on enterprise plans' });
}
if (req.body == null || req.body.cluster == null) {
return dynamicResponse(req, res, 404, { error: 'Invalid cluster' });
}
req.body.cluster = parseInt(req.body.cluster, 10) || 0;
if (!Number.isSafeInteger(req.body.cluster)
|| req.body.cluster > res.locals.user.clusters.length-1) {
return dynamicResponse(req, res, 404, { error: 'Invalid cluster' });
}
try {
await db.db.collection('accounts')
.updateOne({_id: res.locals.user.username}, {$set: {activeCluster: req.body.cluster }});
} catch (e) {
return next(e);
}
return dynamicResponse(req, res, 302, { redirect: '/account' });
};
/**
* POST /cluster/add
* add cluster
*/
exports.addCluster = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
return dynamicResponse(req, res, 403, { error: 'Adding clusters is only supported on enterprise plans' });
}
if (!req.body || !req.body.cluster
|| typeof req.body.cluster !== 'string'
|| !validClustersString(req.body.cluster)) {
return dynamicResponse(req, res, 400, { error: 'Invalid cluster' });
}
try {
await db.db.collection('accounts')
.updateOne({_id: res.locals.user.username}, {$addToSet: {clusters: req.body.cluster }});
} catch (e) {
return next(e);
}
return dynamicResponse(req, res, 302, { redirect: '/clusters' });
};
/**
* POST /cluster/delete
* delete cluster
*/
exports.deleteClusters = async (req, res, next) => {
if (res.locals.user.username !== "admin") {
return dynamicResponse(req, res, 403, { error: 'Removing clusters is only supported on enterprise plans' });
}
//TODO: warning modal and extra "confirm" param before deleting cluster
const existingClusters = new Set(res.locals.user.clusters);
req.body.cluster = makeArrayIfSingle(req.body.cluster);
if (!req.body || !req.body.cluster
|| !req.body.cluster.some(c => existingClusters.has(c))) {
return dynamicResponse(req, res, 400, { error: 'Invalid cluster' });
}
const filteredClusters = res.locals.clusters.filter(c => !req.body.cluster.includes(c));
// if (filteredClusters.length === 0) {
// return dynamicResponse(req, res, 400, { error: 'Cannot delete last cluster' });
// }
let newActiveCluster = res.locals.user.activeCluster;
if (res.locals.user.activeCluster > filteredClusters.length-1) {
newActiveCluster = 0;
}
try {
await db.db.collection('accounts')
.updateOne({_id: res.locals.user.username}, {$set: {clusters: filteredClusters, activeCluster: newActiveCluster }});
} catch (e) {
return next(e);
}
return dynamicResponse(req, res, 302, { redirect: '/clusters' });
};