reconstruire UC inceput
@@ -0,0 +1,45 @@
|
|||||||
|
General Overview
|
||||||
|
-
|
||||||
|
|
||||||
|
The UC serves as the main logistic station for all the client/CEO applications which are used
|
||||||
|
inside the corporation. This UC stores
|
||||||
|
- credentials for the users and ceo;
|
||||||
|
- registered departments, as well security levels and the encrypting/decrypting keys for the files;
|
||||||
|
- backup schemes for each user, as well as the IP, as well as the IPs where each computer is located;
|
||||||
|
|
||||||
|
The main endpoints of the application are:
|
||||||
|
|
||||||
|
- <b>Users</b>:
|
||||||
|
|
||||||
|
- Can register/login in the system;
|
||||||
|
- Update the information (username, email, password);
|
||||||
|
- Change the working department (the client app will prompt the CEO password request to proceed);
|
||||||
|
- Retrieve the full list of departments for the sign-up / 'change department' procedure;
|
||||||
|
- Retrieve the full list of users and their IPs for sharing a file
|
||||||
|
|
||||||
|
|
||||||
|
- <b>CEO</b>:
|
||||||
|
|
||||||
|
- Can log in the system;
|
||||||
|
- Can change the email (the password can only be retrieved by the admin);
|
||||||
|
- Delete users from the system;
|
||||||
|
- Create / Delete departments, as well as managing the security levels of each department;
|
||||||
|
- Retrieve the full list of users and their IPs for sharing a file
|
||||||
|
|
||||||
|
|
||||||
|
- <b>Admin</b>:
|
||||||
|
|
||||||
|
- Reset the server to default state;
|
||||||
|
- Retrieve the CEO login information, as well as a list of all users in the system;
|
||||||
|
|
||||||
|
|
||||||
|
- <b>Backup Schemes</b>:
|
||||||
|
|
||||||
|
- At a request, will get the ID of a user, their IP and the backup directory structure to place it in the scheme,
|
||||||
|
as well as the data size of the backup
|
||||||
|
|
||||||
|
|
||||||
|
Other Features
|
||||||
|
-
|
||||||
|
The UC will also create a separate process which at a set interval of time will retrieve from the admin config, as
|
||||||
|
well as from the CEO config, the ID so that it will be used to authenticate the users at their endpoints.
|
||||||
@@ -8,23 +8,21 @@ const port = process.env.PORT || 5000;
|
|||||||
app.use(cors());
|
app.use(cors());
|
||||||
app.use(json());
|
app.use(json());
|
||||||
|
|
||||||
app.locals.apiKey = 'uc_api'
|
|
||||||
|
|
||||||
const checkJson = require('./middlewares/checkJson');
|
const checkJson = require('./middlewares/checkJson');
|
||||||
const apiKeyValidation = require('./middlewares/apiKeyValidation');
|
const apiKeyValidation = require('./middlewares/apiKeyValidation');
|
||||||
const setAdminValues = require('./middlewares/setAdminValues');
|
|
||||||
|
|
||||||
app.use(apiKeyValidation)
|
app.use(apiKeyValidation)
|
||||||
app.use(checkJson)
|
app.use(checkJson)
|
||||||
app.use(setAdminValues);
|
|
||||||
|
|
||||||
const usersRouter = require('./routes/users');
|
const usersRouter = require('./routes/users');
|
||||||
const departmentsRouter = require('./routes/departments');
|
|
||||||
const adminRouter = require('./routes/admin');
|
const adminRouter = require('./routes/admin');
|
||||||
|
const ceoRouter = require('./routes/ceo');
|
||||||
|
const backupSchemesRouter = require('./routes/backup_schemes');
|
||||||
|
|
||||||
app.use('/users', usersRouter);
|
app.use('/users', usersRouter);
|
||||||
app.use('/departments', departmentsRouter);
|
|
||||||
app.use('/admin', adminRouter);
|
app.use('/admin', adminRouter);
|
||||||
|
app.use('/ceo', ceoRouter);
|
||||||
|
app.use('/backup_schemes', backupSchemesRouter);
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server running on http://localhost:${port}`);
|
console.log(`Server running on http://localhost:${port}`);
|
||||||
@@ -32,8 +30,7 @@ app.listen(port, () => {
|
|||||||
|
|
||||||
// Graceful shutdown function
|
// Graceful shutdown function
|
||||||
function gracefulShutdown() {
|
function gracefulShutdown() {
|
||||||
console.log('\nGracefully shutting down from SIGINT (Ctrl-C)');
|
console.log('\nShutting down!');
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
{}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"adminKey": "9ded8e96a7a03fb7ce23a19b4f6a3d08ac42926aa96664af941e4d02e0b93f0d",
|
|
||||||
"ceoID": "a7635c7a-d6a0-43dc-8e24-552ab33239b8"
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"id": "16183532-3090-4e24-8def-aa29f316c1c5",
|
|
||||||
"name": "Programatori",
|
|
||||||
"key": "66238d3abd92e43486a1f8526ff83646a2481b4fb669667daf81ecc71e8211e3"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "897b883b-7638-452e-bed9-81e8da2ec0c3",
|
|
||||||
"name": "Contabili",
|
|
||||||
"key": "55956d2a1cad9e3952f3756ded721724f71baada95c9addbf46f72defa06d354"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"1": "f1444987-c0c2-4ce8-89e3-b21f302bff7f",
|
|
||||||
"2": "16183532-3090-4e24-8def-aa29f316c1c5",
|
|
||||||
"3": "897b883b-7638-452e-bed9-81e8da2ec0c3"
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class DepartmentAlreadyExistsError extends Error {
|
|
||||||
constructor(message = 'This department is already in system') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'DepartmentAlreadyExistsError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = DepartmentAlreadyExistsError
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class DepartmentNotExistingError extends Error {
|
|
||||||
constructor(message = 'Department not found') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'DepartmentNotExistingError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = DepartmentNotExistingError;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class EmailAlreadyInSystemError extends Error {
|
|
||||||
constructor(message = "Email is already in system!") {
|
|
||||||
super(message);
|
|
||||||
this.name = 'EmailAlreadyInSystem';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = EmailAlreadyInSystemError
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class ImproperDirStructureError extends Error {
|
|
||||||
constructor(message = 'the provided structure is not a valid JSON') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'ImproperDirStructureError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ImproperDirStructureError
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class InvalidDepartmentJsonError extends Error {
|
|
||||||
constructor(message = 'Invalid JSON format for security levels') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'InvalidDepartmentJsonError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports=InvalidDepartmentJsonError;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class InvalidKeyErrorException extends Error {
|
|
||||||
constructor(message = 'Invalid key for this operation') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'InvalidKeyErrorException';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports=InvalidKeyErrorException;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class UserAlreadyExistsException extends Error {
|
|
||||||
constructor(message = 'User already exists in system') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'UserAlreadyExistsException';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = UserAlreadyExistsException
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
class UserNotExistingError extends Error {
|
|
||||||
constructor(message = 'User not found in the system!') {
|
|
||||||
super(message);
|
|
||||||
this.name = 'UserNotExistingError';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = UserNotExistingError
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,153 +1,20 @@
|
|||||||
const express = require('express');
|
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();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get('/reset_key', (req, res) => {
|
function validateBody(req, res, next) {
|
||||||
|
|
||||||
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();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
router.put('/change_admin_credentials', validateRegisterCeoBody, (req, res) => {
|
router.post('/reset_server', validateBody, (req, res) => {
|
||||||
try {
|
// Handle reset server logic here
|
||||||
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) => {
|
router.get('/ceo', validateBody, (req, res) => {
|
||||||
try {
|
// Retrieve CEO info
|
||||||
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) => {
|
router.get('/users', validateBody, (req, res) => {
|
||||||
return sendResponse(res, httpStatus.NOT_FOUND, "Path not found");
|
// Retrieve all users in the system
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
function validateBody(req, res, next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
router.patch('/', validateBody, (req, res) => {
|
||||||
|
const { id, ip, backup_schema, size } = req.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/', validateBody, (req, res) => {
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
function validateBody(req, res, next) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
router.post('/login', validateBody, (req, res) => {
|
||||||
|
const { email, password } = req.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/set_security_levels', validateBody, (req, res) => {
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/users/delete/:id', validateBody, (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/departments', validateBody, (req, res) => {
|
||||||
|
const { name } = req.body;
|
||||||
|
// Generate key with crypto of 32Hex
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/departments/:id', validateBody, (req, res) => {
|
||||||
|
const { id } = req.params;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.put('/', validateBody, (req, res) => {
|
||||||
|
const { email } = req.body;
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/', validateBody, (req, res) => {
|
||||||
|
// Send CEO info
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/get_decrypt_keys', (req, res) => {
|
||||||
|
// Get all departments
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -1,359 +1,34 @@
|
|||||||
const express = require('express');
|
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();
|
const router = express.Router();
|
||||||
|
|
||||||
|
function validateBody(req, res, next) {
|
||||||
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();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
router.post('/register', validateRegisterBody, async (req, res) => {
|
router.post('/register', validateBody, (req, res) => {
|
||||||
try {
|
const { name, email, password, department } = req.body;
|
||||||
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]);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('/login', validateBody, (req, res) => {
|
||||||
const validateLoginBody = (req, res, next) => {
|
const { email, password } = req.body;
|
||||||
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) => {
|
router.post('/email-validation', validateBody, (req, res) => {
|
||||||
const {error, value} = schemas.emailVerificationSchema.validate(req.body);
|
const { email } = 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]);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/', (req, res) => {
|
||||||
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) => {
|
router.put('/', validateBody, (req, res) => {
|
||||||
const {error, value} = schemas.userDepartmentPatchSchema.validate(req.body);
|
const { name, email, password } = 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) => {
|
router.patch('/change-department', validateBody, (req, res) => {
|
||||||
const {error, value} = schemas.usersModifyModelSchema.validate(req.body);
|
const { id, department } = 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.get('/get_decrypt_keys', (req, res) => {
|
||||||
router.use((req, res) => {
|
|
||||||
return sendResponse(res, httpStatus.NOT_FOUND, "Path not found");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -1,4 +1,31 @@
|
|||||||
|
General overview
|
||||||
|
-
|
||||||
|
|
||||||
For the use of the admin console, start with 'npm run start' the UI frontend.
|
For the use of the admin console, start with 'npm run start' the UI frontend.
|
||||||
To see/modify the initial login credentials check the /config/config.json file.
|
To see/modify the initial login credentials check the /config/config.json file.
|
||||||
|
|
||||||
WITHOUT SETTING THE CONFIG FILE FOR THE SERVER (API KEY) THE SERVER WILL NOT START!
|
WITHOUT SETTING THE CONFIG FILE, THE SERVER WILL NOT WORK AS INTENDED!
|
||||||
|
(click on the 'Reset UC' when first configuring the server to bring the
|
||||||
|
UC at the initial state)
|
||||||
|
|
||||||
|
Because the client and CEO apps are dependent on the Central Unit (UC), we strongly
|
||||||
|
suggest you to make backup at a regular interval in case of hardware failing you will
|
||||||
|
only have to deploy the server with the configurations already existing.
|
||||||
|
|
||||||
|
Important aspects:
|
||||||
|
-
|
||||||
|
|
||||||
|
- The starting/stopping of the UC is handled by this 'Admin Console'. The server will not
|
||||||
|
work if the server which servers as the 'Admin Console' is not running.
|
||||||
|
- The main server will run at the port 5000, so make sure to configure your routers to
|
||||||
|
enable routing to the server;
|
||||||
|
- The client and CEO backup system of their applications will need access at ports 5001 and 5002,
|
||||||
|
so also make sure to open those ports as well;
|
||||||
|
- If the CEO wants to change the email address linked to the account, his password will be changed
|
||||||
|
to a low-risk password, so make sure after any release to specify the account information;
|
||||||
|
|
||||||
|
Closing thoughts
|
||||||
|
-
|
||||||
|
|
||||||
|
We really hope that you will enjoy our application and for any issues, feel free to contact us at
|
||||||
|
'username@ourdomain.com' for troubleshooting and other problems.
|
||||||
@@ -7,6 +7,26 @@ const cookieParser = require('cookie-parser');
|
|||||||
|
|
||||||
const checkSession = require('./middlewares/checkSession');
|
const checkSession = require('./middlewares/checkSession');
|
||||||
|
|
||||||
|
process.on('SIGINT', shutdown);
|
||||||
|
process.on('SIGTERM', shutdown);
|
||||||
|
|
||||||
|
function shutdown() {
|
||||||
|
console.log('Received kill signal, shutting down gracefully.');
|
||||||
|
const serverProcess = app.get('serverProcess');
|
||||||
|
if (serverProcess && typeof serverProcess.kill === 'function') {
|
||||||
|
console.log('Shutting down server process...');
|
||||||
|
serverProcess.kill(); // Send SIGTERM to server process
|
||||||
|
|
||||||
|
serverProcess.on('exit', () => {
|
||||||
|
console.log('Server process terminated.');
|
||||||
|
process.exit(0); // Exit main process cleanly
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log('No server process or cannot be killed, exiting.');
|
||||||
|
process.exit(0); // Exit main process cleanly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
app.set('serverProcess', null);
|
app.set('serverProcess', null);
|
||||||
@@ -18,7 +38,7 @@ app.use(bodyParser.json());
|
|||||||
app.use(express.static(path.join(__dirname, 'public', 'html')));
|
app.use(express.static(path.join(__dirname, 'public', 'html')));
|
||||||
app.use('/css', express.static(path.join(__dirname, 'public', 'css')));
|
app.use('/css', express.static(path.join(__dirname, 'public', 'css')));
|
||||||
app.use('/js', express.static(path.join(__dirname, 'public', 'js')));
|
app.use('/js', express.static(path.join(__dirname, 'public', 'js')));
|
||||||
app.use('/images', express.static(path.join(__dirname, 'public', 'assets')));
|
app.use('/images', express.static(path.join(__dirname, 'public', 'images')));
|
||||||
|
|
||||||
app.use(checkSession);
|
app.use(checkSession);
|
||||||
|
|
||||||
@@ -31,3 +51,5 @@ const PORT = process.env.PORT || 80;
|
|||||||
app.listen(PORT, () => {
|
app.listen(PORT, () => {
|
||||||
console.log(`Server is running on port ${PORT}`);
|
console.log(`Server is running on port ${PORT}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ body, html {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|||||||
@@ -13,78 +13,9 @@ body, html {
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.overlay {
|
|
||||||
display: none;
|
|
||||||
position: fixed;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.85);
|
|
||||||
z-index: 2;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ceo-validation-form {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
width: 300px;
|
|
||||||
padding: 20px;
|
|
||||||
background: #1B1A55;
|
|
||||||
border-radius: 10px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ceo-validation-form h2 {
|
|
||||||
text-align: center;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-actions {
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-actions button {
|
|
||||||
padding: 10px 20px;
|
|
||||||
margin: 0 10px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
text-align: center;
|
|
||||||
color: white;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
width: 80%;
|
|
||||||
padding: 1rem;
|
|
||||||
margin: 0.7rem;
|
|
||||||
background-color: #1B1A55;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#back_button {
|
|
||||||
background-color: #f44336;
|
|
||||||
width: 35%;
|
|
||||||
height: auto;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#submit_button {
|
|
||||||
background-color: #4CAF50;
|
|
||||||
width: 35%;
|
|
||||||
height: auto;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
opacity: 0;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
.fade-in {
|
||||||
|
animation: fadeInAnimation 0.5s ease-in forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-out {
|
||||||
|
animation: fadeOutAnimation 0.5s ease-out forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeInAnimation {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOutAnimation {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,10 +5,28 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" href="/images/hard-disk.ico" type="image/x-icon">
|
<link rel="icon" href="/images/hard-disk.ico" type="image/x-icon">
|
||||||
<link rel="stylesheet" type="text/css" href="/css/login.css">
|
<link rel="stylesheet" type="text/css" href="/css/login.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/transition.css">
|
||||||
<script src="/js/login.js"></script>
|
<script src="/js/login.js"></script>
|
||||||
|
<script>
|
||||||
|
function fadeIn() {
|
||||||
|
document.querySelector('.container').classList.remove('fade-out');
|
||||||
|
document.querySelector('.container').classList.add('fade-in');
|
||||||
|
}
|
||||||
|
|
||||||
|
function fadeOut(destination) {
|
||||||
|
const container = document.querySelector('.container');
|
||||||
|
container.classList.remove('fade-in');
|
||||||
|
container.classList.add('fade-out');
|
||||||
|
|
||||||
|
container.addEventListener('animationend', () => {
|
||||||
|
window.location.href = destination;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<title>Login</title>
|
<title>Login</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body onload="fadeIn()">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<h1>DO WE KNOW</h1>
|
<h1>DO WE KNOW</h1>
|
||||||
|
|||||||
@@ -5,12 +5,28 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" href="/images/hard-disk.ico" type="image/x-icon">
|
<link rel="icon" href="/images/hard-disk.ico" type="image/x-icon">
|
||||||
<link rel="stylesheet" href="/css/main_menu.css">
|
<link rel="stylesheet" href="/css/main_menu.css">
|
||||||
|
<link rel="stylesheet" href="/css/transition.css">
|
||||||
|
|
||||||
<script src="/js/main_menu.js"></script>
|
<script src="/js/main_menu.js"></script>
|
||||||
|
<script>
|
||||||
|
function fadeIn() {
|
||||||
|
document.querySelector('.container').classList.remove('fade-out');
|
||||||
|
document.querySelector('.container').classList.add('fade-in');
|
||||||
|
}
|
||||||
|
|
||||||
|
function fadeOut() {
|
||||||
|
document.querySelector('.container').classList.remove('fade-in');
|
||||||
|
document.querySelector('.container').classList.add('fade-out');
|
||||||
|
// Redirect after fadeOut animation completes (adjust timeout as needed)
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = 'your_redirect_url.html';
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
<title>Main Page</title>
|
<title>Main Page</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body onload="fadeIn()">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="main_block">
|
<div class="main_block">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@@ -28,7 +44,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="content_buttons">
|
<div class="content_buttons">
|
||||||
<button id="ceo_info" name="menu_button">Get CEO Info</button>
|
<button id="ceo_info" name="menu_button">Get CEO Info</button>
|
||||||
<button id="set_conf" name="menu_button">Set Server Conf File</button>
|
<button id="users_info" name="menu_button">Get All Users</button>
|
||||||
|
</div>
|
||||||
|
<div class="content_buttons">
|
||||||
|
<button id="reset_uc" name="menu_button">Reset UC</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 298 KiB After Width: | Height: | Size: 298 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
@@ -26,7 +26,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
document.cookie = `email=${result.user.email};`;
|
document.cookie = `email=${result.user.email};`;
|
||||||
document.cookie = `name=${result.user.name};`;
|
document.cookie = `name=${result.user.name};`;
|
||||||
|
|
||||||
window.location.href = '/';
|
fadeOut('/');
|
||||||
} else {
|
} else {
|
||||||
alert('Incorrect credentials. Please try again.');
|
alert('Incorrect credentials. Please try again.');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const startUcButton = document.getElementById('start_uc');
|
const startUcButton = document.getElementById('start_uc');
|
||||||
const stopUcButton = document.getElementById('stop_uc');
|
const stopUcButton = document.getElementById('stop_uc');
|
||||||
const ceoInfoButton = document.getElementById('ceo_info');
|
const ceoInfoButton = document.getElementById('ceo_info');
|
||||||
const setConfButton = document.getElementById('set_conf');
|
const usersInfoButton = document.getElementById('users_info');
|
||||||
|
const resetUcButton = document.getElementById('reset_uc');
|
||||||
const logoutButton = document.getElementById('logout');
|
const logoutButton = document.getElementById('logout');
|
||||||
|
|
||||||
startUcButton.addEventListener('click', () => {
|
startUcButton.addEventListener('click', () => {
|
||||||
@@ -63,11 +64,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
console.log('Ceo Info Button pressed');
|
console.log('Ceo Info Button pressed');
|
||||||
})
|
})
|
||||||
|
|
||||||
setConfButton.addEventListener('click', () => {
|
usersInfoButton.addEventListener('click', () => {
|
||||||
|
console.log('Users Info Button pressed');
|
||||||
|
})
|
||||||
|
|
||||||
|
resetUcButton.addEventListener('click', () => {
|
||||||
console.log('Set Conf Button pressed');
|
console.log('Set Conf Button pressed');
|
||||||
})
|
})
|
||||||
|
|
||||||
logoutButton.addEventListener('click', function() {
|
logoutButton.addEventListener('click', () => {
|
||||||
console.log('Logout button was clicked');
|
console.log('Logout button was clicked');
|
||||||
|
|
||||||
const deleteCookie = (name) => {
|
const deleteCookie = (name) => {
|
||||||
@@ -77,6 +82,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
deleteCookie('email');
|
deleteCookie('email');
|
||||||
deleteCookie('name');
|
deleteCookie('name');
|
||||||
|
|
||||||
window.location.href = '/login';
|
fadeOut('/login');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fs = require('fs').promises;
|
|
||||||
const { fork } = require('child_process');
|
const { fork } = require('child_process');
|
||||||
const httpStatus = require('../helpers/status_codes');
|
const httpStatus = require('../helpers/status_codes');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
const backendPath = path.join(__dirname, '..', '..', 'backend');
|
const backendPath = path.join(__dirname, '..', '..', 'backend');
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
@@ -15,44 +13,38 @@ router.get('/', (req, res) => {
|
|||||||
router.post('/server', async (req, res) => {
|
router.post('/server', async (req, res) => {
|
||||||
const action = req.body.action;
|
const action = req.body.action;
|
||||||
let serverProcess = req.app.get('serverProcess');
|
let serverProcess = req.app.get('serverProcess');
|
||||||
const configFilePath = path.join(backendPath, 'config', 'config.json');
|
|
||||||
|
|
||||||
try {
|
|
||||||
await fs.access(configFilePath);
|
|
||||||
} catch (error) {
|
|
||||||
if(action === 'start'){
|
|
||||||
return res.status(httpStatus.BAD_REQUEST).send({ message: 'Config file is missing, cannot start server.' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action === 'start') {
|
if (action === 'start') {
|
||||||
if (serverProcess) {
|
if (serverProcess) {
|
||||||
return res.status(httpStatus.BAD_REQUEST).send({message: 'Server is already running.'});
|
return res.status(httpStatus.BAD_REQUEST).send({message: 'Server is already running.'});
|
||||||
}
|
}
|
||||||
const serverPath = path.join(backendPath, 'src', 'app.js');
|
const serverPath = path.join(backendPath, 'src', 'app.js');
|
||||||
serverProcess = fork(serverPath);
|
serverProcess = fork(serverPath, [], { stdio: 'inherit' }); // Add stdio: 'inherit' to see child process logs in the parent process console
|
||||||
|
|
||||||
serverProcess.on('message', (msg) => {
|
serverProcess.on('message', (msg) => {
|
||||||
console.log('Message from server:', msg);
|
console.log('Message from server:', msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
serverProcess.on('close', (code) => {
|
serverProcess.on('close', (code, signal) => {
|
||||||
console.log(`Server process exited with code ${code}`);
|
console.log(`Server process exited with code ${code} and signal ${signal}`);
|
||||||
req.app.set('serverProcess', null);
|
req.app.set('serverProcess', null);
|
||||||
});
|
});
|
||||||
|
|
||||||
req.app.set('serverProcess', serverProcess); // Update the serverProcess in app
|
req.app.set('serverProcess', serverProcess); // Update the serverProcess in the app
|
||||||
res.status(httpStatus.OK).json({message: 'Server starting...'});
|
res.status(httpStatus.OK).json({message: 'Server starting...'});
|
||||||
} else if (action === 'stop') {
|
} else if (action === 'stop') {
|
||||||
if (!serverProcess) {
|
if (!serverProcess) {
|
||||||
return res.status(httpStatus.BAD_REQUEST).json({message: 'Server is not running.'});
|
return res.status(httpStatus.BAD_REQUEST).json({message: 'Server is not running.'});
|
||||||
}
|
}
|
||||||
serverProcess.kill();
|
serverProcess.kill('SIGTERM');
|
||||||
req.app.set('serverProcess', null);
|
|
||||||
res.status(httpStatus.OK).json({message: 'Server stopping...'});
|
res.status(httpStatus.OK).json({message: 'Server stopping...'});
|
||||||
} else {
|
} else {
|
||||||
res.status(httpStatus.BAD_REQUEST).json({message: 'Invalid action.'});
|
res.status(httpStatus.BAD_REQUEST).json({message: 'Invalid action.'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.post('ceo_credentials', (req, res) => {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
{
|
|
||||||
"id": "ffc90aca-bb31-4641-9a43-30b343924e8a",
|
|
||||||
"name": "Andrei",
|
|
||||||
"email": "a@c.com",
|
|
||||||
"password": "andreicerbu",
|
|
||||||
"department": "16183532-3090-4e24-8def-aa29f316c1c5"
|
|
||||||
}
|
|
||||||