UI Admin aproape finalizat

This commit is contained in:
andrei-mihnea-cerbu
2024-04-03 02:09:12 +03:00
parent fb957a6f97
commit af8c295d75
134 changed files with 5014 additions and 1045 deletions
+41
View File
@@ -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);
+1
View File
@@ -0,0 +1 @@
{}
+4
View File
@@ -0,0 +1,4 @@
{
"adminKey": "9ded8e96a7a03fb7ce23a19b4f6a3d08ac42926aa96664af941e4d02e0b93f0d",
"ceoID": "a7635c7a-d6a0-43dc-8e24-552ab33239b8"
}
+12
View File
@@ -0,0 +1,12 @@
[
{
"id": "16183532-3090-4e24-8def-aa29f316c1c5",
"name": "Programatori",
"key": "66238d3abd92e43486a1f8526ff83646a2481b4fb669667daf81ecc71e8211e3"
},
{
"id": "897b883b-7638-452e-bed9-81e8da2ec0c3",
"name": "Contabili",
"key": "55956d2a1cad9e3952f3756ded721724f71baada95c9addbf46f72defa06d354"
}
]
+5
View File
@@ -0,0 +1,5 @@
{
"1": "f1444987-c0c2-4ce8-89e3-b21f302bff7f",
"2": "16183532-3090-4e24-8def-aa29f316c1c5",
"3": "897b883b-7638-452e-bed9-81e8da2ec0c3"
}
+16
View File
@@ -0,0 +1,16 @@
[
{
"id": "a7635c7a-d6a0-43dc-8e24-552ab33239b8",
"name": "CEO",
"email": "ceo@yourfirm.com",
"password": "405ee6885be5385223830874bd6dcfca",
"department": ""
},
{
"id": "ffc90aca-bb31-4641-9a43-30b343924e8a",
"name": "Andrei",
"email": "a@c.com",
"password": "5447045dc3cfaafdb49b365e31dad41eb88616b0b1449930e55fd3a70bd8cee4",
"department": "16183532-3090-4e24-8def-aa29f316c1c5"
}
]
@@ -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 EmailAlreadyInSystemError extends Error {
constructor(message = "Email is already in system!") {
super(message);
this.name = 'EmailAlreadyInSystem';
}
}
module.exports = EmailAlreadyInSystemError
@@ -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
+75
View File
@@ -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};
+21
View File
@@ -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;
+16
View File
@@ -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,26 @@
const path = require("path");
const fs = require("fs");
function SetAdminValuesMiddleware(req, res, next){
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,7 @@
const Joi = require('joi');
const emailVerificationModel = Joi.object({
email: Joi.string().email().required()
});
module.exports = emailVerificationModel;
+21
View File
@@ -0,0 +1,21 @@
const usersRegisterModelSchema = require('./usersRegisterModel');
const usersLoginModelSchema = require('./usersLoginModel');
const usersModifyModelSchema = require('./usersModifyModel');
const dirStructureModelSchema = require('./dirStructureModel');
const departmentRegisterModelSchema = require('./departmentRegisterModel');
const ceoRegisterModelSchema = require('./ceoRegisterModel');
const emailVerificationSchema = require('./emailVerificationModel');
const userDepartmentPatchSchema = require('./userDepartmentPatchModel');
module.exports = {
schemas: {
dirStructureModelSchema,
usersRegisterModelSchema,
usersLoginModelSchema,
usersModifyModelSchema,
departmentRegisterModelSchema,
ceoRegisterModelSchema,
emailVerificationSchema,
userDepartmentPatchSchema
},
};
@@ -0,0 +1,7 @@
const Joi = require("joi");
const UserDepartmentPatchModel = Joi.object({
department: Joi.string().uuid().required()
});
module.exports = UserDepartmentPatchModel;
+8
View File
@@ -0,0 +1,8 @@
const Joi = require('joi');
const usersLoginModel = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().required()
});
module.exports = usersLoginModel;
@@ -0,0 +1,9 @@
const Joi = require('joi');
const usersModifyModel = Joi.object({
name: Joi.string().required(),
email: Joi.string().email().required(),
password: Joi.string().min(8).max(20).required()
});
module.exports = usersModifyModel;
@@ -0,0 +1,10 @@
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(),
department: Joi.string().uuid().required()
});
module.exports = usersRegisterModel;
+153
View File
@@ -0,0 +1,153 @@
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) {
console.log(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;
+224
View File
@@ -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;
+359
View File
@@ -0,0 +1,359 @@
const express = require('express');
const fs = require('fs');
const path = require('path');
const {v4: uuidv4, validate} = 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 EmailAlreadyInSystemError = require("../exceptions/emailAlreadyInSystemError");
const {HttpStatusCode} = require("axios");
const DepartmentAlreadyExistsError = require("../exceptions/departmentAlreadyExistsError");
const DepartmentNotExistingError = require("../exceptions/departmentNotExistingError");
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, department} = 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,
department: department
};
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;
let userIndex = usersJson.findIndex(user => user.email === email);
if (userIndex === -1) {
throw new UserNotExistingError('Invalid email');
}
let hashedPassword = '';
if(usersJson[userIndex].id === res.locals.ceoID) {
hashedPassword = password;
}
else{
hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
}
console.log(email);
console.log(password);
userIndex = usersJson.findIndex(user => user.email === email && user.password === hashedPassword);
console.log(userIndex);
if (userIndex === -1) {
throw new UserNotExistingError('Invalid email or password');
}
const user = usersJson[userIndex];
return sendResponse(res, httpStatus.OK, {
id: user.id,
name: user.name,
email: email,
password: password,
department: user.department
});
} 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 validateEmailValidationBody = (req, res, next) => {
const {error, value} = schemas.emailVerificationSchema.validate(req.body);
if (error) {
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
}
req.jsonModel = value;
next();
}
router.post('/validate_email', validateEmailValidationBody, (req, res) => {
try {
const {email} = req.jsonModel;
const usersFilePath = path.join(__dirname, '..', 'db', 'users.json');
const usersData = fs.readFileSync(usersFilePath, 'utf8');
const usersJson = JSON.parse(usersData);
if (usersJson.some(user => user.email === email)) {
throw new EmailAlreadyInSystemError();
}
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
} catch (error) {
console.error(`Error: ${error.message}`);
if (error instanceof EmailAlreadyInSystemError) {
return sendResponse(res, httpStatus.CONFLICT, 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]);
}
});
const validateUserDepartmentPatch = (req, res, next) => {
const {error, value} = schemas.userDepartmentPatchSchema.validate(req.body);
if (error) {
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
}
req.jsonModel = value;
next();
};
router.patch('/:id', validateUserDepartmentPatch, async (req, res) => {
const id = req.params.id;
console.log('esti aici');
try {
const department_id = req.jsonModel.department;
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();
}
const departmentsFilePath = path.join(__dirname, '..', 'db', 'departments.json');
const departmentsData = fs.readFileSync(departmentsFilePath, 'utf8');
const departments = JSON.parse(departmentsData);
console.log(departments);
const indexDepartment = departments.findIndex(department => department.id === department_id);
if (indexDepartment === -1) {
throw new DepartmentNotExistingError();
}
usersJson[index].department = department_id;
fs.writeFileSync(usersFilePath, JSON.stringify(usersJson, null, 2));
return sendResponse(res, httpStatus.OK, httpStatusMessages[httpStatus.OK]);
}catch(error){
console.log(error);
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]);
}
});
const validateModifyUserBody = (req, res, next) => {
const {error, value} = schemas.usersModifyModelSchema.validate(req.body);
if (error) {
return sendResponse(res, httpStatus.BAD_REQUEST, error.details[0].message);
}
req.jsonModel = value;
next();
};
router.put('/:id', validateModifyUserBody, 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 {name, email, password} = req.jsonModel;
if (usersJson.some(user => user.email === email && user.id !== id)) {
throw new EmailAlreadyInSystemError();
}
let index = usersJson.findIndex(user => user.id === id);
if (index === -1) {
throw new UserNotExistingError();
}
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
usersJson[index] = {
id: id,
name: name,
email: email,
password: hashedPassword
}
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 EmailAlreadyInSystemError) {
return sendResponse(res, httpStatus.CONFLICT, 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;