UC done v1.0
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
const express = require('express');
|
||||
const {json} = require("body-parser");
|
||||
const cors = require('cors');
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 5000;
|
||||
|
||||
app.use(cors());
|
||||
app.use(json());
|
||||
|
||||
app.locals.apiKey = 'uc_api'
|
||||
|
||||
const checkJson = require('./middlewares/checkJson');
|
||||
const apiKeyValidation = require('./middlewares/apiKeyValidation');
|
||||
const setAdminValues = require('./middlewares/setAdminValues');
|
||||
|
||||
app.use(apiKeyValidation)
|
||||
app.use(checkJson)
|
||||
app.use(setAdminValues);
|
||||
|
||||
const usersRouter = require('./routes/users');
|
||||
const departmentsRouter = require('./routes/departments');
|
||||
const adminRouter = require('./routes/admin');
|
||||
|
||||
app.use('/users', usersRouter);
|
||||
app.use('/departments', departmentsRouter);
|
||||
app.use('/admin', adminRouter);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server running on http://localhost:${port}`);
|
||||
});
|
||||
|
||||
// Graceful shutdown function
|
||||
function gracefulShutdown() {
|
||||
console.log('\nGracefully shutting down from SIGINT (Ctrl-C)');
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
process.on('SIGTERM', gracefulShutdown);
|
||||
process.on('SIGINT', gracefulShutdown);
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "5ad08e32-9d5a-4054-b96f-ba361c02f30a",
|
||||
"dir_config": "{dir_1: {}}",
|
||||
"total_space": 0.1
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"adminKey": "590dceb42261808e4a804607b38eb119a09c93d84554bac0d23d705d5c6e8ca5",
|
||||
"ceoID": "5ad08e32-9d5a-4054-b96f-ba361c02f30a"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"id": "6cd67946-6fe7-46df-9740-25eea7b95f69",
|
||||
"name": "Programatori",
|
||||
"key": "a2bb3329528704715e29c27fd778892d177bcacfd73e38bde818aef560f4d549"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"1": "6cd67946-6fe7-46df-9740-25eea7b95f69"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"id": "5ad08e32-9d5a-4054-b96f-ba361c02f30a",
|
||||
"name": "Andrei Cerbu",
|
||||
"email": "a@c.com",
|
||||
"password": "4dd45a4455b1db1fd9c204a6d7c26f30"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,8 @@
|
||||
class DepartmentAlreadyExistsError extends Error {
|
||||
constructor(message = 'This department is already in system') {
|
||||
super(message);
|
||||
this.name = 'DepartmentAlreadyExistsError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DepartmentAlreadyExistsError
|
||||
@@ -0,0 +1,8 @@
|
||||
class DepartmentNotExistingError extends Error {
|
||||
constructor(message = 'Department not found') {
|
||||
super(message);
|
||||
this.name = 'DepartmentNotExistingError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DepartmentNotExistingError;
|
||||
@@ -0,0 +1,8 @@
|
||||
class ImproperDirStructureError extends Error {
|
||||
constructor(message = 'the provided structure is not a valid JSON') {
|
||||
super(message);
|
||||
this.name = 'ImproperDirStructureError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ImproperDirStructureError
|
||||
@@ -0,0 +1,8 @@
|
||||
class InvalidDepartmentJsonError extends Error {
|
||||
constructor(message = 'Invalid JSON format for security levels') {
|
||||
super(message);
|
||||
this.name = 'InvalidDepartmentJsonError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports=InvalidDepartmentJsonError;
|
||||
@@ -0,0 +1,8 @@
|
||||
class InvalidKeyErrorException extends Error {
|
||||
constructor(message = 'Invalid key for this operation') {
|
||||
super(message);
|
||||
this.name = 'InvalidKeyErrorException';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports=InvalidKeyErrorException;
|
||||
@@ -0,0 +1,8 @@
|
||||
class UserAlreadyExistsException extends Error {
|
||||
constructor(message = 'User already exists in system') {
|
||||
super(message);
|
||||
this.name = 'UserAlreadyExistsException';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserAlreadyExistsException
|
||||
@@ -0,0 +1,8 @@
|
||||
class UserNotExistingError extends Error {
|
||||
constructor(message = 'User not found in the system!') {
|
||||
super(message);
|
||||
this.name = 'UserNotExistingError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserNotExistingError
|
||||
@@ -0,0 +1,75 @@
|
||||
const httpStatus = {
|
||||
// Informational
|
||||
CONTINUE: 100,
|
||||
SWITCHING_PROTOCOLS: 101,
|
||||
PROCESSING: 102,
|
||||
|
||||
// Success
|
||||
OK: 200,
|
||||
CREATED: 201,
|
||||
ACCEPTED: 202,
|
||||
NO_CONTENT: 204,
|
||||
|
||||
// Redirection
|
||||
MOVED_PERMANENTLY: 301,
|
||||
FOUND: 302,
|
||||
SEE_OTHER: 303,
|
||||
NOT_MODIFIED: 304,
|
||||
TEMPORARY_REDIRECT: 307,
|
||||
|
||||
// Client Error
|
||||
BAD_REQUEST: 400,
|
||||
UNAUTHORIZED: 401,
|
||||
FORBIDDEN: 403,
|
||||
NOT_FOUND: 404,
|
||||
METHOD_NOT_ALLOWED: 405,
|
||||
CONFLICT: 409,
|
||||
GONE: 410,
|
||||
UNSUPPORTED_MEDIA_TYPE: 415,
|
||||
|
||||
// Server Error
|
||||
INTERNAL_SERVER_ERROR: 500,
|
||||
NOT_IMPLEMENTED: 501,
|
||||
SERVICE_UNAVAILABLE: 503
|
||||
};
|
||||
|
||||
const httpStatusMessages = {
|
||||
// Informational
|
||||
[httpStatus.CONTINUE]: "Continue",
|
||||
[httpStatus.SWITCHING_PROTOCOLS]: "Switching Protocols",
|
||||
[httpStatus.PROCESSING]: "Processing",
|
||||
|
||||
// Success
|
||||
[httpStatus.OK]: "OK",
|
||||
[httpStatus.CREATED]: "Created",
|
||||
[httpStatus.ACCEPTED]: "Accepted",
|
||||
[httpStatus.NO_CONTENT]: "No Content",
|
||||
|
||||
// Redirection
|
||||
[httpStatus.MOVED_PERMANENTLY]: "Moved Permanently",
|
||||
[httpStatus.FOUND]: "Found",
|
||||
[httpStatus.SEE_OTHER]: "See Other",
|
||||
[httpStatus.NOT_MODIFIED]: "Not Modified",
|
||||
[httpStatus.TEMPORARY_REDIRECT]: "Temporary Redirect",
|
||||
|
||||
// Client Error
|
||||
[httpStatus.BAD_REQUEST]: "Bad Request",
|
||||
[httpStatus.UNAUTHORIZED]: "Unauthorized",
|
||||
[httpStatus.FORBIDDEN]: "Forbidden",
|
||||
[httpStatus.NOT_FOUND]: "Not Found",
|
||||
[httpStatus.METHOD_NOT_ALLOWED]: "Method Not Allowed",
|
||||
[httpStatus.CONFLICT]: "Conflict",
|
||||
[httpStatus.GONE]: "Gone",
|
||||
[httpStatus.UNSUPPORTED_MEDIA_TYPE]: "Unsupported Media Type",
|
||||
|
||||
// Server Error
|
||||
[httpStatus.INTERNAL_SERVER_ERROR]: "Internal Server Error",
|
||||
[httpStatus.NOT_IMPLEMENTED]: "Not Implemented",
|
||||
[httpStatus.SERVICE_UNAVAILABLE]: "Service Unavailable"
|
||||
};
|
||||
|
||||
const httpHeaders = {
|
||||
JSON: { 'name': 'Content-Type', 'value': 'application/json' }
|
||||
};
|
||||
|
||||
module.exports = {httpStatus, httpStatusMessages, httpHeaders};
|
||||
@@ -0,0 +1,21 @@
|
||||
const {httpHeaders} = require("./httpResponses");
|
||||
|
||||
const headers = {
|
||||
[httpHeaders.JSON.name]: httpHeaders.JSON.value
|
||||
}
|
||||
|
||||
function sendResponse(res, statusCode, message, data = null, headers_parsed = {}) {
|
||||
Object.entries(headers).forEach(([key, value]) => {
|
||||
res.setHeader(key, value);
|
||||
});
|
||||
|
||||
// Set headers if provided
|
||||
Object.entries(headers_parsed).forEach(([key, value]) => {
|
||||
res.setHeader(key, value);
|
||||
});
|
||||
|
||||
// Send the response with status code, message, and optional data
|
||||
res.status(statusCode).json({ message, data });
|
||||
}
|
||||
|
||||
module.exports = { sendResponse };
|
||||
@@ -0,0 +1,12 @@
|
||||
const { sendResponse } = require('../helpers/responseHelper');
|
||||
const {httpStatus, httpStatusMessages} = require('../helpers/httpResponses')
|
||||
function apiKeyValidation(req, res, next) {
|
||||
const apiKey = req.headers['x-api-key'];
|
||||
|
||||
if (apiKey !== req.app.locals.apiKey) {
|
||||
return sendResponse(res, httpStatus.UNAUTHORIZED, httpStatusMessages[httpStatus.UNAUTHORIZED]);
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
module.exports = apiKeyValidation;
|
||||
@@ -0,0 +1,16 @@
|
||||
const { sendResponse } = require('../helpers/responseHelper');
|
||||
const {httpStatus, httpStatusMessages} = require("../helpers/httpResponses");
|
||||
|
||||
function checkJson(req, res, next) {
|
||||
if(req.method === 'GET'){
|
||||
next()
|
||||
}
|
||||
|
||||
if (['POST', 'PUT', 'PATCH'].includes(req.method) && req.headers['content-type'] !== 'application/json') {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, httpStatusMessages[httpStatus.BAD_REQUEST]);
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
module.exports = checkJson;
|
||||
@@ -0,0 +1,31 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
function SetAdminValuesMiddleware(req, res, next){
|
||||
if(!req.path.startsWith('/admin')){
|
||||
next();
|
||||
return res;
|
||||
}
|
||||
|
||||
try{
|
||||
const configFilePath = path.join(__dirname, '..', 'db', 'config.json');
|
||||
const config = JSON.parse(fs.readFileSync(configFilePath));
|
||||
|
||||
res.locals.adminKey = config.adminKey === undefined ? " " : config.adminKey;
|
||||
res.locals.ceoID = config.ceoID === undefined ? " " : config.ceoID;
|
||||
|
||||
next();
|
||||
|
||||
fs.writeFileSync(configFilePath, JSON.stringify(
|
||||
{
|
||||
adminKey: res.locals.adminKey,
|
||||
ceoID: res.locals.ceoID
|
||||
}, null, 2));
|
||||
return res;
|
||||
} catch(error){
|
||||
console.log(error.message);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SetAdminValuesMiddleware;
|
||||
@@ -0,0 +1,8 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const ceoRegisterModel = Joi.object({
|
||||
name: Joi.string().required(),
|
||||
email: Joi.string().email().required()
|
||||
});
|
||||
|
||||
module.exports = ceoRegisterModel;
|
||||
@@ -0,0 +1,7 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const departmentRegisterModel = Joi.object({
|
||||
name: Joi.string().required()
|
||||
});
|
||||
|
||||
module.exports = departmentRegisterModel
|
||||
@@ -0,0 +1,9 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const dirStructureModel = Joi.object({
|
||||
id: Joi.string().guid().required(),
|
||||
dir_config: Joi.string().required(),
|
||||
total_space: Joi.number().positive().required()
|
||||
});
|
||||
|
||||
module.exports = dirStructureModel
|
||||
@@ -0,0 +1,15 @@
|
||||
const usersRegisterModelSchema = require('./usersRegisterModel');
|
||||
const usersLoginModelSchema = require('./usersLoginModel');
|
||||
const dirStructureModelSchema = require('./dirStructureModel');
|
||||
const departmentRegisterModelSchema = require('./departmentRegisterModel');
|
||||
const ceoRegisterModelSchema = require('./ceoRegisterModel')
|
||||
|
||||
module.exports = {
|
||||
schemas: {
|
||||
dirStructureModelSchema,
|
||||
usersRegisterModelSchema,
|
||||
usersLoginModelSchema,
|
||||
departmentRegisterModelSchema,
|
||||
ceoRegisterModelSchema
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const usersLoginModel = Joi.object({
|
||||
email: Joi.string().email().required(),
|
||||
password: Joi.string().min(8).max(20).required()
|
||||
});
|
||||
|
||||
module.exports = usersLoginModel;
|
||||
@@ -0,0 +1,9 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
const usersRegisterModel = Joi.object({
|
||||
name: Joi.string().required(),
|
||||
email: Joi.string().email().required(),
|
||||
password: Joi.string().min(8).max(20).required()
|
||||
});
|
||||
|
||||
module.exports = usersRegisterModel;
|
||||
@@ -0,0 +1,152 @@
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const {v4: uuidv4} = require("uuid");
|
||||
const path = require("path");
|
||||
|
||||
const { sendResponse } = require('../helpers/responseHelper');
|
||||
const {httpStatus, httpStatusMessages} = require('../helpers/httpResponses')
|
||||
const {schemas} = require("../models/schemaMapper");
|
||||
const InvalidKeyErrorException = require("../exceptions/invalidKeyErrorException");
|
||||
const UserNotExistingError = require("../exceptions/userNotExistingError");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/reset_key', (req, res) => {
|
||||
|
||||
const adminKey= crypto.randomBytes(32).toString('hex');
|
||||
res.locals.adminKey = adminKey;
|
||||
sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK], adminKey);
|
||||
});
|
||||
|
||||
router.get('/reset', (req, res) => {
|
||||
try {
|
||||
const requestAdminKey = req.headers['admin-key'];
|
||||
|
||||
if (requestAdminKey !== res.locals.adminKey) {
|
||||
throw new InvalidKeyErrorException();
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'db', 'users.json'), '[]');
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'db', 'departments.json'), '[]');
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'db', 'security_levels.json'), '{}');
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'db', 'backup_schemas.json'), '{}');
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'db', 'config.json'), JSON.stringify({
|
||||
adminKey: ' ',
|
||||
ceoID: ' '
|
||||
}, null, 2));
|
||||
|
||||
const adminPassword = crypto.randomBytes(16).toString('hex'); // Generating random password
|
||||
const ceoID = uuidv4();
|
||||
res.locals.ceoID = ceoID;
|
||||
const adminAccount = {
|
||||
id: ceoID,
|
||||
name: 'CEO',
|
||||
email: 'ceo@yourfirm.com',
|
||||
password: adminPassword
|
||||
};
|
||||
|
||||
const usersData = [adminAccount];
|
||||
fs.writeFileSync(path.join(__dirname, '..', 'db', 'users.json'),
|
||||
JSON.stringify(usersData, null, 2));
|
||||
|
||||
sendResponse(res, httpStatus.CREATED, httpStatusMessages[httpStatus.CREATED]);
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
if(error instanceof InvalidKeyErrorException){
|
||||
return sendResponse(res, httpStatus.UNAUTHORIZED, error.message);
|
||||
}
|
||||
|
||||
sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
const validateRegisterCeoBody = (req, res, next) => {
|
||||
const { error, value } = schemas.ceoRegisterModelSchema.validate(req.body);
|
||||
if (error) {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
|
||||
}
|
||||
req.jsonModel = value;
|
||||
next();
|
||||
}
|
||||
|
||||
router.put('/change_admin_credentials', validateRegisterCeoBody, (req, res) => {
|
||||
try {
|
||||
const requestAdminKey = req.headers['admin-key'];
|
||||
if (requestAdminKey !== res.locals.adminKey) {
|
||||
throw new InvalidKeyErrorException();
|
||||
}
|
||||
|
||||
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
|
||||
const usersData = JSON.parse(fs.readFileSync(usersFilePath, 'utf8'));
|
||||
|
||||
const adminIndex = usersData.findIndex(user => user.id === res.locals.ceoID);
|
||||
if (adminIndex === -1) {
|
||||
throw new UserNotExistingError();
|
||||
}
|
||||
|
||||
const { name, email } = req.body; // Using req.body instead of req.jsonModel
|
||||
const newPassword = crypto.randomBytes(16).toString('hex'); // Generate new random password
|
||||
|
||||
// Update the user data
|
||||
usersData[adminIndex] = {
|
||||
id: res.locals.ceoID,
|
||||
name: name,
|
||||
email: email,
|
||||
password: newPassword
|
||||
};
|
||||
|
||||
// Write the updated user data back to the file
|
||||
fs.writeFileSync(usersFilePath, JSON.stringify(usersData, null, 2));
|
||||
|
||||
sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
if (error instanceof InvalidKeyErrorException) {
|
||||
return sendResponse(res, httpStatus.UNAUTHORIZED, error.message);
|
||||
}
|
||||
if (error instanceof UserNotExistingError) {
|
||||
return sendResponse(res, httpStatus.NOT_FOUND, error.message);
|
||||
}
|
||||
|
||||
sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR])
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/validate_admin_password', (req, res) => {
|
||||
try {
|
||||
const requestAdminKey = req.headers['admin-key'];
|
||||
if (requestAdminKey !== res.locals.adminKey) {
|
||||
throw new InvalidKeyErrorException();
|
||||
}
|
||||
|
||||
if(req.body.password === undefined){
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, httpStatusMessages[httpStatus.BAD_REQUEST]);
|
||||
}
|
||||
const password = req.body.password;
|
||||
|
||||
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
|
||||
const usersData = fs.readFileSync(usersFilePath, 'utf8');
|
||||
const usersJson = JSON.parse(usersData);
|
||||
|
||||
const user = usersJson.find(user => user.id === res.locals.ceoID);
|
||||
if(user.password !== password){
|
||||
return sendResponse(res, httpStatus.UNAUTHORIZED, httpStatusMessages[httpStatus.UNAUTHORIZED]);
|
||||
}
|
||||
|
||||
sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
if(error instanceof InvalidKeyErrorException){
|
||||
return sendResponse(res, httpStatus.UNAUTHORIZED, error.message);
|
||||
}
|
||||
|
||||
sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
router.use((req, res) => {
|
||||
return sendResponse(res, httpStatus.NOT_FOUND, "Path not found");
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,224 @@
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const { sendResponse } = require('../helpers/responseHelper');
|
||||
const {httpStatus, httpStatusMessages} = require('../helpers/httpResponses')
|
||||
const {schemas} = require("../models/schemaMapper");
|
||||
|
||||
const DepartmentAlreadyExistsError = require("../exceptions/departmentAlreadyExistsError");
|
||||
const InvalidDepartmentJsonError = require("../exceptions/invalidDepartmentJsonError");
|
||||
const DepartmentNotExistingError = require("../exceptions/departmentNotExistingError");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
try {
|
||||
const departmentsFilePath = path.join(__dirname, '..', 'db', 'departments.json');
|
||||
const departmentsData = fs.readFileSync(departmentsFilePath, 'utf8');
|
||||
const departments = JSON.parse(departmentsData);
|
||||
|
||||
|
||||
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK], departments);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function generateAESKey() {
|
||||
return crypto.randomBytes(32).toString('hex');
|
||||
}
|
||||
|
||||
router.post('/', validateRegisterBody, createDepartment, addSecurityLevel, (req, res) => {
|
||||
return res;
|
||||
});
|
||||
|
||||
function validateRegisterBody(req, res, next) {
|
||||
const { error, value } = schemas.departmentRegisterModelSchema.validate(req.body);
|
||||
if (error) {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
|
||||
}
|
||||
req.jsonModel = value;
|
||||
next();
|
||||
}
|
||||
|
||||
function createDepartment(req, res, next) {
|
||||
try {
|
||||
const { name } = req.jsonModel;
|
||||
|
||||
const departmentsFilePath = path.join(__dirname, '..', 'db', 'departments.json');
|
||||
const departmentsData = fs.readFileSync(departmentsFilePath, 'utf8');
|
||||
const departments = JSON.parse(departmentsData);
|
||||
|
||||
const existingDepartment = departments.find(department => department.name === name);
|
||||
if (existingDepartment) {
|
||||
throw new DepartmentAlreadyExistsError();
|
||||
}
|
||||
|
||||
const departmentId = uuidv4();
|
||||
const aesKey = generateAESKey();
|
||||
const newDepartment = {
|
||||
id: departmentId,
|
||||
name: name,
|
||||
key: aesKey
|
||||
};
|
||||
|
||||
departments.push(newDepartment);
|
||||
fs.writeFileSync(departmentsFilePath, JSON.stringify(departments, null, 2));
|
||||
|
||||
req.departmentId = departmentId;
|
||||
next();
|
||||
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
if (error instanceof DepartmentAlreadyExistsError) {
|
||||
return sendResponse(res, httpStatus.CONFLICT, error.message);
|
||||
}
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
}
|
||||
|
||||
function addSecurityLevel(req, res) {
|
||||
try {
|
||||
const { departmentId } = req;
|
||||
|
||||
const securityLevelsFilePath = path.join(__dirname, '..', 'db', 'security_levels.json');
|
||||
const securityLevelsData = fs.readFileSync(securityLevelsFilePath, 'utf8');
|
||||
const securityLevels = JSON.parse(securityLevelsData);
|
||||
|
||||
const nextIndex = Object.keys(securityLevels).length + 1;
|
||||
securityLevels[nextIndex] = departmentId;
|
||||
|
||||
fs.writeFileSync(securityLevelsFilePath, JSON.stringify(securityLevels, null, 2));
|
||||
|
||||
return sendResponse(res, httpStatus.CREATED, httpStatusMessages[httpStatus.CREATED]);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
router.put('/', validateDepartmentsJson, validateSecurityLevels, updateSecurityLevels);
|
||||
|
||||
function validateDepartmentsJson(req, res, next) {
|
||||
try {
|
||||
for (const key in req.body) {
|
||||
if (!Number.isInteger(parseInt(key)) || typeof req.body[key] !== 'string') {
|
||||
throw new InvalidDepartmentJsonError();
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function validateSecurityLevels(req, res, next) {
|
||||
try {
|
||||
const securityLevelsFilePath = path.join(__dirname, '..', 'db', 'security_levels.json');
|
||||
const securityLevelsData = fs.readFileSync(securityLevelsFilePath, 'utf8');
|
||||
const securityLevels = JSON.parse(securityLevelsData);
|
||||
|
||||
if (Object.keys(req.body).length !== Object.keys(securityLevels).length) {
|
||||
throw new InvalidDepartmentJsonError('Number of keys does not match the database');
|
||||
}
|
||||
|
||||
const encounteredValues = new Set();
|
||||
const securityLevelValues = Object.values(securityLevels);
|
||||
|
||||
for (const key in req.body) {
|
||||
const requestBodyValue = req.body[key];
|
||||
if (!securityLevels.hasOwnProperty(key)) {
|
||||
throw new InvalidDepartmentJsonError('Invalid key found in request body');
|
||||
}
|
||||
const securityLevelValue = securityLevels[key];
|
||||
|
||||
if (!securityLevelValues.includes(securityLevelValue)) {
|
||||
throw new InvalidDepartmentJsonError('Values do not match the database');
|
||||
}
|
||||
|
||||
if (encounteredValues.has(requestBodyValue)) {
|
||||
throw new InvalidDepartmentJsonError('Duplicate values found in request body');
|
||||
}
|
||||
|
||||
encounteredValues.add(requestBodyValue);
|
||||
}
|
||||
|
||||
next();
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function updateSecurityLevels(req, res) {
|
||||
try {
|
||||
const securityLevelsFilePath = path.join(__dirname, '..', 'db', 'security_levels.json');
|
||||
fs.writeFileSync(securityLevelsFilePath, JSON.stringify(req.body, null, 2));
|
||||
|
||||
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
router.delete('/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
try {
|
||||
deleteDepartment(id, res);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
|
||||
if (error instanceof DepartmentNotExistingError) {
|
||||
return sendResponse(res, httpStatus.NOT_FOUND, error.message);
|
||||
}
|
||||
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
function deleteDepartment(id, res) {
|
||||
const departmentsFilePath = path.join(__dirname, '..', 'db', 'departments.json');
|
||||
const departmentsData = fs.readFileSync(departmentsFilePath, 'utf8');
|
||||
const departmentsJson = JSON.parse(departmentsData);
|
||||
|
||||
const index = departmentsJson.findIndex(department => department.id === id);
|
||||
if (index === -1) {
|
||||
throw new DepartmentNotExistingError();
|
||||
}
|
||||
|
||||
departmentsJson.splice(index, 1);
|
||||
fs.writeFileSync(departmentsFilePath, JSON.stringify(departmentsJson, null, 2));
|
||||
|
||||
const securityLevelsFilePath = path.join(__dirname, '..', 'db', 'security_levels.json');
|
||||
const securityLevelsData = fs.readFileSync(securityLevelsFilePath, 'utf8');
|
||||
const securityLevelsJson = JSON.parse(securityLevelsData);
|
||||
|
||||
const securityIndex = securityLevelsJson.findIndex(level => level.id === id);
|
||||
if (securityIndex !== -1) {
|
||||
securityLevelsJson.splice(securityIndex, 1);
|
||||
fs.writeFileSync(securityLevelsFilePath, JSON.stringify(securityLevelsJson, null, 2));
|
||||
}
|
||||
|
||||
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
router.use((req, res) => {
|
||||
return sendResponse(res, httpStatus.NOT_FOUND, "Path not found");
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -0,0 +1,199 @@
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const { sendResponse } = require('../helpers/responseHelper');
|
||||
const {httpStatus, httpStatusMessages} = require('../helpers/httpResponses')
|
||||
const {schemas} = require("../models/schemaMapper");
|
||||
|
||||
const UserAlreadyExistsException =require('../exceptions/userAlreadyExistsError');
|
||||
const UserNotExistingError = require("../exceptions/userNotExistingError");
|
||||
const ImproperDirStructureError = require("../exceptions/improperDirStructureError");
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
||||
router.get('/', async(req, res) => {
|
||||
try {
|
||||
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
|
||||
const usersData = fs.readFileSync(usersFilePath, 'utf8');
|
||||
const usersJson = JSON.parse(usersData);
|
||||
|
||||
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK], usersJson)
|
||||
} catch (error) {
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR])
|
||||
}
|
||||
});
|
||||
|
||||
const validateRegisterBody = (req, res, next) => {
|
||||
const { error, value } = schemas.usersRegisterModelSchema.validate(req.body);
|
||||
if (error) {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
|
||||
}
|
||||
req.jsonModel = value;
|
||||
next();
|
||||
}
|
||||
|
||||
router.post('/register', validateRegisterBody, async (req, res) => {
|
||||
try {
|
||||
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
|
||||
const usersData = fs.readFileSync(usersFilePath, 'utf8');
|
||||
const usersJson = JSON.parse(usersData);
|
||||
|
||||
const { name, email, password } = req.jsonModel;
|
||||
|
||||
const existingUser = usersJson.find(user => user.email === email);
|
||||
if (existingUser) {
|
||||
throw new UserAlreadyExistsException();
|
||||
}
|
||||
|
||||
const userId = uuidv4();
|
||||
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
|
||||
|
||||
const newUser = {
|
||||
id: userId,
|
||||
name: name,
|
||||
email: email,
|
||||
password: hashedPassword
|
||||
};
|
||||
|
||||
usersJson.push(newUser);
|
||||
fs.writeFileSync(usersFilePath, JSON.stringify(usersJson, null, 2));
|
||||
|
||||
return sendResponse(res, httpStatus.CREATED, httpStatusMessages[httpStatus.CREATED]);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
|
||||
if (error instanceof UserAlreadyExistsException) {
|
||||
return sendResponse(res, httpStatus.CONFLICT, error.message);
|
||||
}
|
||||
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const validateLoginBody = (req, res, next) => {
|
||||
const { error, value } = schemas.usersLoginModelSchema.validate(req.body);
|
||||
if (error) {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
|
||||
}
|
||||
req.jsonModel = value;
|
||||
next();
|
||||
}
|
||||
|
||||
router.post('/login', validateLoginBody, async (req, res) => {
|
||||
try {
|
||||
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
|
||||
const usersData = fs.readFileSync(usersFilePath, 'utf8');
|
||||
const usersJson = JSON.parse(usersData);
|
||||
|
||||
const { email, password } = req.jsonModel;
|
||||
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
|
||||
const user = usersJson.find(user => user.email === email && user.password === hashedPassword);
|
||||
|
||||
if (!user) {
|
||||
throw new UserNotExistingError('Invalid email or password');
|
||||
}
|
||||
|
||||
return sendResponse(res, httpStatus.OK, 'Login successful');
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
|
||||
if (error instanceof UserNotExistingError) {
|
||||
return sendResponse(res, httpStatus.UNAUTHORIZED, error.message);
|
||||
}
|
||||
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const validateDirStructureBody = (req, res, next) => {
|
||||
const { error, value } = schemas.dirStructureModelSchema.validate(req.body);
|
||||
if (error) {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
|
||||
}
|
||||
req.jsonModel = value;
|
||||
next();
|
||||
};
|
||||
|
||||
router.put('/dir_structure', validateDirStructureBody, (req, res) => {
|
||||
try {
|
||||
const { id, dir_config, total_space } = req.jsonModel;
|
||||
|
||||
const backupFilePath = path.join(__dirname, '..', 'db', 'backup_schemas.json');
|
||||
let backupArray = [];
|
||||
if (fs.existsSync(backupFilePath)) {
|
||||
const backupData = fs.readFileSync(backupFilePath, 'utf8');
|
||||
try {
|
||||
backupArray = JSON.parse(backupData);
|
||||
} catch (jsonParseError) {
|
||||
throw new ImproperDirStructureError();
|
||||
}
|
||||
}
|
||||
|
||||
const existingIndex = backupArray.findIndex(item => item.id === id);
|
||||
if (existingIndex !== -1) {
|
||||
backupArray[existingIndex] = {
|
||||
id: id,
|
||||
dir_config: dir_config,
|
||||
total_space: total_space
|
||||
};
|
||||
} else {
|
||||
backupArray.push({
|
||||
id: id,
|
||||
dir_config: dir_config,
|
||||
total_space: total_space
|
||||
});
|
||||
}
|
||||
|
||||
fs.writeFileSync(backupFilePath, JSON.stringify(backupArray, null, 2));
|
||||
|
||||
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
if (error instanceof ImproperDirStructureError) {
|
||||
return sendResponse(res, httpStatus.BAD_REQUEST, error.message);
|
||||
}
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.delete('/:id', async (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
try {
|
||||
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
|
||||
const usersData = fs.readFileSync(usersFilePath, 'utf8');
|
||||
const usersJson = JSON.parse(usersData);
|
||||
|
||||
const index = usersJson.findIndex(user => user.id === id);
|
||||
if (index === -1) {
|
||||
throw new UserNotExistingError();
|
||||
}
|
||||
|
||||
usersJson.splice(index, 1);
|
||||
fs.writeFileSync(usersFilePath, JSON.stringify(usersJson, null, 2));
|
||||
|
||||
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
|
||||
if (error instanceof UserNotExistingError) {
|
||||
return sendResponse(res, httpStatus.NOT_FOUND, error.message);
|
||||
}
|
||||
|
||||
return sendResponse(res, httpStatus.INTERNAL_SERVER_ERROR, httpStatusMessages[httpStatus.INTERNAL_SERVER_ERROR]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
router.use((req, res) => {
|
||||
return sendResponse(res, httpStatus.NOT_FOUND, "Path not found");
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user