All checks were successful
farmcontrol/farmcontrol-api/pipeline/head This commit looks good
This commit introduces a new feature for managing permission settings within the application. It includes the creation of a new `permissions.js` file for handling permission logic, a corresponding Mongoose schema for permission settings, and route handlers for CRUD operations on permission settings. Additionally, tests have been added to ensure the functionality of the new permission settings service. This enhancement improves the application's capability to manage user permissions effectively.
248 lines
5.6 KiB
JavaScript
248 lines
5.6 KiB
JavaScript
import config from '../../config.js';
|
|
import { userModel } from '../../database/schemas/management/user.schema.js';
|
|
import log4js from 'log4js';
|
|
import mongoose from 'mongoose';
|
|
import bcrypt from 'bcrypt';
|
|
import { nanoid } from 'nanoid';
|
|
import {
|
|
listObjects,
|
|
listObjectsByProperties,
|
|
getObject,
|
|
editObject,
|
|
getModelStats,
|
|
getModelHistory,
|
|
searchObjects,
|
|
getPropertyValues,
|
|
getObjectNeighbors,
|
|
} from '../../database/database.js';
|
|
|
|
const logger = log4js.getLogger('Users');
|
|
logger.level = config.server.logLevel;
|
|
|
|
const USER_POPULATE = ['profileImage', 'permissionSettings'];
|
|
|
|
export const listUsersRouteHandler = async (
|
|
req,
|
|
res,
|
|
page = 1,
|
|
limit = 25,
|
|
property = '',
|
|
filter = {},
|
|
search = '',
|
|
sort = '',
|
|
order = 'ascend'
|
|
) => {
|
|
const result = await listObjects({
|
|
model: userModel,
|
|
page,
|
|
limit,
|
|
property,
|
|
filter,
|
|
search,
|
|
sort,
|
|
order,
|
|
populate: USER_POPULATE,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error listing users.');
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`List of users (Page ${page}, Limit ${limit}). Count: ${result.length}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const listUsersByPropertiesRouteHandler = async (
|
|
req,
|
|
res,
|
|
properties = '',
|
|
filter = {},
|
|
masterFilter = {}
|
|
) => {
|
|
const result = await listObjectsByProperties({
|
|
model: userModel,
|
|
properties,
|
|
filter,
|
|
masterFilter,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error listing users.');
|
|
res.status(result.code).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`List of users. Count: ${result.length}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getUserPropertyValuesRouteHandler = async (req, res, property) => {
|
|
const result = await getPropertyValues({
|
|
model: userModel,
|
|
property,
|
|
});
|
|
res.send(result);
|
|
};
|
|
|
|
export const searchUsersRouteHandler = async (req, res, search) => {
|
|
const result = await searchObjects({
|
|
model: userModel,
|
|
search,
|
|
});
|
|
res.send(result);
|
|
};
|
|
|
|
export const getUserRouteHandler = async (req, res) => {
|
|
const id = req.params.id;
|
|
const result = await getObject({
|
|
model: userModel,
|
|
id,
|
|
populate: USER_POPULATE,
|
|
});
|
|
if (result?.error) {
|
|
logger.warn(`User not found with supplied id.`);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.debug(`Retreived user with ID: ${id}`);
|
|
res.send(result);
|
|
};
|
|
|
|
export const editUserRouteHandler = async (req, res) => {
|
|
// Get ID from params
|
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
|
|
|
logger.trace(`User with ID: ${id}`);
|
|
|
|
const updateData = {
|
|
updatedAt: new Date(),
|
|
name: req.body.name,
|
|
firstName: req.body.firstName,
|
|
lastName: req.body.lastName,
|
|
email: req.body.email,
|
|
profileImage: req.body.profileImage,
|
|
permissionSettings: Array.isArray(req.body.permissionSettings)
|
|
? req.body.permissionSettings.map((item) => item?._id || item)
|
|
: req.body.permissionSettings,
|
|
};
|
|
// Create audit log before updating
|
|
const result = await editObject({
|
|
model: userModel,
|
|
id,
|
|
updateData,
|
|
user: req.user,
|
|
populate: USER_POPULATE,
|
|
});
|
|
|
|
if (result.error) {
|
|
logger.error('Error editing user:', result.error);
|
|
res.status(result).send(result);
|
|
return;
|
|
}
|
|
|
|
logger.debug(`Edited user with ID: ${id}`);
|
|
|
|
res.send(result);
|
|
};
|
|
|
|
export const getUserStatsRouteHandler = async (req, res) => {
|
|
const result = await getModelStats({ model: userModel });
|
|
if (result?.error) {
|
|
logger.error('Error fetching user stats:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.trace('User stats:', result);
|
|
res.send(result);
|
|
};
|
|
|
|
export const getUserHistoryRouteHandler = async (req, res) => {
|
|
const from = req.query.from;
|
|
const to = req.query.to;
|
|
const result = await getModelHistory({ model: userModel, from, to });
|
|
if (result?.error) {
|
|
logger.error('Error fetching user history:', result.error);
|
|
return res.status(result.code).send(result);
|
|
}
|
|
logger.trace('User history:', result);
|
|
res.send(result);
|
|
};
|
|
|
|
export const setAppPasswordRouteHandler = async (req, res) => {
|
|
if (req.user._id.toString() !== req.params.id) {
|
|
return res
|
|
.status(403)
|
|
.send({ error: 'You are not authorized to set the app password for this user.' });
|
|
}
|
|
|
|
const id = new mongoose.Types.ObjectId(req.params.id);
|
|
|
|
logger.trace(`Setting app password for user with ID: ${id}`);
|
|
|
|
const userResult = await getObject({
|
|
model: userModel,
|
|
id,
|
|
});
|
|
|
|
if (userResult?.error) {
|
|
logger.warn('User not found with supplied id.');
|
|
return res.status(userResult.code).send(userResult);
|
|
}
|
|
|
|
const appPassword = nanoid(32);
|
|
const appPasswordHash = await bcrypt.hash(appPassword, 10);
|
|
|
|
const updateData = {
|
|
updatedAt: new Date(),
|
|
appPasswordHash,
|
|
};
|
|
|
|
const result = await editObject({
|
|
model: userModel,
|
|
id,
|
|
updateData,
|
|
user: req.user,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error setting app password:', result.error);
|
|
return res.status(result.code || 500).send(result);
|
|
}
|
|
|
|
logger.debug(`Set app password for user with ID: ${id}`);
|
|
|
|
res.send({ appPassword });
|
|
};
|
|
export const getUserNeighborsRouteHandler = async (
|
|
req,
|
|
res,
|
|
property = '',
|
|
filter = {},
|
|
search = '',
|
|
sort = '',
|
|
order = 'ascend',
|
|
id
|
|
) => {
|
|
if (!id) {
|
|
return res.status(400).send({ error: 'Missing id parameter', code: 400 });
|
|
}
|
|
|
|
const result = await getObjectNeighbors({
|
|
model: userModel,
|
|
id,
|
|
filter,
|
|
search,
|
|
sort,
|
|
order,
|
|
});
|
|
|
|
if (result?.error) {
|
|
logger.error('Error fetching user neighbors.');
|
|
return res.status(result.code).send(result);
|
|
}
|
|
|
|
logger.debug(`Retrieved user neighbors for ID: ${id}`);
|
|
res.send(result);
|
|
};
|
|
|