UC /users v1.0
This commit is contained in:
@@ -10,6 +10,9 @@ app.use(cors({
|
|||||||
}));
|
}));
|
||||||
app.use(json());
|
app.use(json());
|
||||||
|
|
||||||
|
const {apiKey} = require('./config.json');
|
||||||
|
app.locals.apiKey = apiKey;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
usersDB,
|
usersDB,
|
||||||
departmentsDB,
|
departmentsDB,
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"apiKey": "uc_api"
|
||||||
|
}
|
||||||
@@ -31,6 +31,48 @@ class JSONDatabase {
|
|||||||
console.error('Error writing file:', error);
|
console.error('Error writing file:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isKeyValue(key, value) {
|
||||||
|
const data = this.readFile();
|
||||||
|
if (!data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
if (item[key] === value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
findIndexByKeyValueInArray(key, value) {
|
||||||
|
const data = this.readFile();
|
||||||
|
if (!data || !Array.isArray(data)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
if (data[i][key] === value) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
findByKeyValue(key, value) {
|
||||||
|
const data = this.readFile();
|
||||||
|
if (!data || !Array.isArray(data)) {
|
||||||
|
return null; // Database read failed or data is not an array
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
if (item[key] === value) {
|
||||||
|
return item; // Return the object containing the specified key-value pair
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // No matching key-value pair found
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const usersDB = new JSONDatabase(path.join(__dirname, 'users.json'));
|
const usersDB = new JSONDatabase(path.join(__dirname, 'users.json'));
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
const Joi = require('joi');
|
||||||
|
|
||||||
|
const ceoModifyModel = Joi.object({
|
||||||
|
name: Joi.string().required().messages({
|
||||||
|
'any.required': 'CEO name is required',
|
||||||
|
'string.empty': 'CEO name must not be empty'
|
||||||
|
}),
|
||||||
|
email: Joi.string().email().required().messages({
|
||||||
|
'any.required': 'CEO email is required',
|
||||||
|
'string.empty': 'CEO email must not be empty',
|
||||||
|
'string.email': 'CEO email must be a valid email address'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ceoModifyModel;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const Joi = require('joi');
|
||||||
|
|
||||||
|
const ceoPasswordModel = Joi.object({
|
||||||
|
password: Joi.string().required().messages({
|
||||||
|
'any.required': 'Password is required',
|
||||||
|
'string.empty': 'Password must not be empty'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = ceoPasswordModel;
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
const Joi = require('joi');
|
|
||||||
|
|
||||||
const ceoRegisterModel = Joi.object({
|
|
||||||
name: Joi.string().required(),
|
|
||||||
email: Joi.string().email().required()
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = ceoRegisterModel;
|
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
|
|
||||||
const departmentRegisterModel = Joi.object({
|
const departmentRegisterModel = Joi.object({
|
||||||
name: Joi.string().required()
|
name: Joi.string().required().messages({
|
||||||
|
'any.required': 'Department name is required',
|
||||||
|
'string.empty': 'Department name must not be empty'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = departmentRegisterModel
|
module.exports = departmentRegisterModel
|
||||||
@@ -1,9 +1,20 @@
|
|||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
|
|
||||||
const dirStructureModel = Joi.object({
|
const dirStructureModel = Joi.object({
|
||||||
id: Joi.string().guid().required(),
|
id: Joi.string().guid().required().messages({
|
||||||
dir_config: Joi.string().required(),
|
'any.required': 'ID is required',
|
||||||
total_space: Joi.number().positive().required()
|
'string.empty': 'ID must not be empty',
|
||||||
|
'string.guid': 'ID must be a valid GUID'
|
||||||
|
}),
|
||||||
|
dir_config: Joi.string().required().messages({
|
||||||
|
'any.required': 'Directory configuration is required',
|
||||||
|
'string.empty': 'Directory configuration must not be empty'
|
||||||
|
}),
|
||||||
|
total_space: Joi.number().positive().required().messages({
|
||||||
|
'any.required': 'Total space is required',
|
||||||
|
'number.positive': 'Total space must be a positive number',
|
||||||
|
'number.base': 'Total space must be a number'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = dirStructureModel
|
module.exports = dirStructureModel
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
|
|
||||||
const emailVerificationModel = Joi.object({
|
const emailVerificationModel = Joi.object({
|
||||||
email: Joi.string().email().required()
|
email: Joi.string().email().required().messages({
|
||||||
|
'string.empty': 'Email can\'t be empty.',
|
||||||
|
'string.email': 'Invalid email format.',
|
||||||
|
'any.required': 'Email is required'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = emailVerificationModel;
|
module.exports = emailVerificationModel;
|
||||||
@@ -3,9 +3,10 @@ const usersLoginModelSchema = require('./usersLoginModel');
|
|||||||
const usersModifyModelSchema = require('./usersModifyModel');
|
const usersModifyModelSchema = require('./usersModifyModel');
|
||||||
const dirStructureModelSchema = require('./dirStructureModel');
|
const dirStructureModelSchema = require('./dirStructureModel');
|
||||||
const departmentRegisterModelSchema = require('./departmentRegisterModel');
|
const departmentRegisterModelSchema = require('./departmentRegisterModel');
|
||||||
const ceoRegisterModelSchema = require('./ceoRegisterModel');
|
const ceoModifyModelSchema = require('./ceoModifyModel');
|
||||||
const emailVerificationSchema = require('./emailVerificationModel');
|
const emailVerificationSchema = require('./emailVerificationModel');
|
||||||
const userDepartmentPatchSchema = require('./userDepartmentPatchModel');
|
const userDepartmentPatchSchema = require('./userDepartmentPatchModel');
|
||||||
|
const ceoPasswordModelSchema = require('./ceoPasswordModel');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
schemas: {
|
schemas: {
|
||||||
@@ -14,8 +15,9 @@ module.exports = {
|
|||||||
usersLoginModelSchema,
|
usersLoginModelSchema,
|
||||||
usersModifyModelSchema,
|
usersModifyModelSchema,
|
||||||
departmentRegisterModelSchema,
|
departmentRegisterModelSchema,
|
||||||
ceoRegisterModelSchema,
|
ceoModifyModelSchema,
|
||||||
emailVerificationSchema,
|
emailVerificationSchema,
|
||||||
userDepartmentPatchSchema
|
userDepartmentPatchSchema,
|
||||||
|
ceoPasswordModelSchema
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
const Joi = require("joi");
|
const Joi = require("joi");
|
||||||
|
|
||||||
const UserDepartmentPatchModel = Joi.object({
|
const UserDepartmentPatchModel = Joi.object({
|
||||||
department: Joi.string().uuid().required()
|
id: Joi.string().uuid().required().messages({
|
||||||
|
'any.required': 'User ID is required',
|
||||||
|
'string.empty': 'User ID must not be empty',
|
||||||
|
'string.uuid': 'User ID must be a valid UUID'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = UserDepartmentPatchModel;
|
module.exports = UserDepartmentPatchModel;
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
|
|
||||||
const usersLoginModel = Joi.object({
|
const usersLoginModel = Joi.object({
|
||||||
email: Joi.string().email().required(),
|
email: Joi.string().email().required().messages({
|
||||||
password: Joi.string().required()
|
'any.required': 'Email is required',
|
||||||
|
'string.empty': 'Email must not be empty',
|
||||||
|
'string.email': 'Email must be a valid email address'
|
||||||
|
}),
|
||||||
|
password: Joi.string().required().messages({
|
||||||
|
'any.required': 'Password is required',
|
||||||
|
'string.empty': 'Password must not be empty'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = usersLoginModel;
|
module.exports = usersLoginModel;
|
||||||
@@ -1,9 +1,21 @@
|
|||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
|
|
||||||
const usersModifyModel = Joi.object({
|
const usersModifyModel = Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required().messages({
|
||||||
email: Joi.string().email().required(),
|
'any.required': 'User name is required',
|
||||||
password: Joi.string().min(8).max(20).required()
|
'string.empty': 'User name must not be empty'
|
||||||
|
}),
|
||||||
|
email: Joi.string().email().required().messages({
|
||||||
|
'any.required': 'User email is required',
|
||||||
|
'string.empty': 'User email must not be empty',
|
||||||
|
'string.email': 'User email must be a valid email address'
|
||||||
|
}),
|
||||||
|
password: Joi.string().min(8).max(20).required().messages({
|
||||||
|
'any.required': 'Password is required',
|
||||||
|
'string.empty': 'Password must not be empty',
|
||||||
|
'string.min': 'Password must be at least {#limit} characters long',
|
||||||
|
'string.max': 'Password must be at most {#limit} characters long'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = usersModifyModel;
|
module.exports = usersModifyModel;
|
||||||
@@ -1,10 +1,26 @@
|
|||||||
const Joi = require('joi');
|
const Joi = require('joi');
|
||||||
|
|
||||||
const usersRegisterModel = Joi.object({
|
const usersRegisterModel = Joi.object({
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required().messages({
|
||||||
email: Joi.string().email().required(),
|
'any.required': 'User name is required',
|
||||||
password: Joi.string().min(8).max(20).required(),
|
'string.empty': 'User name must not be empty'
|
||||||
department: Joi.string().uuid().required()
|
}),
|
||||||
|
email: Joi.string().email().required().messages({
|
||||||
|
'any.required': 'Email is required',
|
||||||
|
'string.empty': 'Email must not be empty',
|
||||||
|
'string.email': 'Email must be a valid email address'
|
||||||
|
}),
|
||||||
|
password: Joi.string().min(8).max(20).required().messages({
|
||||||
|
'any.required': 'Password is required',
|
||||||
|
'string.empty': 'Password must not be empty',
|
||||||
|
'string.min': 'Password must be at least {#limit} characters long',
|
||||||
|
'string.max': 'Password must be at most {#limit} characters long'
|
||||||
|
}),
|
||||||
|
department: Joi.string().uuid().required().messages({
|
||||||
|
'any.required': 'Department ID is required',
|
||||||
|
'string.empty': 'Department ID must not be empty',
|
||||||
|
'string.uuid': 'Department ID must be a valid UUID'
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = usersRegisterModel;
|
module.exports = usersRegisterModel;
|
||||||
@@ -1,34 +1,171 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
const { v4: uuidv4 } = require('uuid');
|
||||||
|
|
||||||
|
const {schemas} = require('../models/schemaMapper');
|
||||||
|
const {httpStatus} = require("../helpers/httpResponses");
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
function validateBody(req, res, next) {
|
function validateBody(req, res, next) {
|
||||||
|
let validationSchema = undefined;
|
||||||
|
|
||||||
|
switch(req.path){
|
||||||
|
case '/register':
|
||||||
|
validationSchema = schemas.usersRegisterModelSchema;
|
||||||
|
break;
|
||||||
|
case '/login':
|
||||||
|
validationSchema = schemas.usersLoginModelSchema;
|
||||||
|
break;
|
||||||
|
case '/validate_email':
|
||||||
|
validationSchema = schemas.emailVerificationSchema;
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
if(req.method === 'PUT'){
|
||||||
|
validationSchema = schemas.usersModifyModelSchema;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'change_department':
|
||||||
|
validationSchema = schemas.userDepartmentPatchSchema;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
validationSchema = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(validationSchema);
|
||||||
|
|
||||||
|
if(validationSchema !== undefined){
|
||||||
|
const {error} = validationSchema.validate(req.body);
|
||||||
|
if(error){
|
||||||
|
const errorMessage = error.details.map(detail => detail.message).join(', ');
|
||||||
|
return res.status(httpStatus.BAD_REQUEST).json({ message: errorMessage });
|
||||||
|
}
|
||||||
|
}
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
router.post('/register', validateBody, (req, res) => {
|
router.post('/register', validateBody, (req, res) => {
|
||||||
|
const usersDB = req.app.get('usersDB');
|
||||||
|
const usersJson = usersDB.readFile();
|
||||||
|
|
||||||
const { name, email, password, department } = req.body;
|
const { name, email, password, department } = req.body;
|
||||||
|
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
|
||||||
|
|
||||||
|
const newUser = {
|
||||||
|
id: uuidv4(),
|
||||||
|
name: name,
|
||||||
|
email: email,
|
||||||
|
password: hashedPassword,
|
||||||
|
department: department
|
||||||
|
}
|
||||||
|
|
||||||
|
usersJson.push(newUser);
|
||||||
|
usersDB.writeFile(usersJson);
|
||||||
|
|
||||||
|
return res.status(httpStatus.CREATED).json({message: "User successfully created.", data: newUser});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/login', validateBody, (req, res) => {
|
router.post('/login', validateBody, (req, res) => {
|
||||||
|
const usersDB = req.app.get('usersDB');
|
||||||
const { email, password } = req.body;
|
const { email, password } = req.body;
|
||||||
|
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
|
||||||
|
|
||||||
|
if(usersDB.findIndexByKeyValueInArray('email', email) !==
|
||||||
|
usersDB.findIndexByKeyValueInArray('password', hashedPassword)){
|
||||||
|
return res.status(httpStatus.NOT_FOUND).json({message: 'Invalid credentials.'});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(httpStatus.Ok).json({message: 'Logged in.'});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post('/email-validation', validateBody, (req, res) => {
|
router.post('/validate_email', validateBody, (req, res) => {
|
||||||
|
const usersDB = req.app.get('usersDB');
|
||||||
const { email } = req.body;
|
const { email } = req.body;
|
||||||
|
|
||||||
|
if(usersDB.isKeyValue("email", email)){
|
||||||
|
return res.status(httpStatus.CONFLICT).json({"message": "Email already in system."});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(httpStatus.OK).json({"message": "Email is valid."});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
|
const usersDB = req.app.get('usersDB');
|
||||||
|
return res.status(httpStatus.OK).json({
|
||||||
|
message: "Fetched users",
|
||||||
|
data: usersDB.readFile()
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/', validateBody, (req, res) => {
|
router.put('/', validateBody, (req, res) => {
|
||||||
|
const usersDB = req.app.get('usersDB');
|
||||||
|
let usersJson = usersDB.readFile();
|
||||||
|
|
||||||
const { name, email, password } = req.body;
|
const { name, email, password } = req.body;
|
||||||
|
const userIndex = usersDB.findIndexByKeyValueInArray('email', email);
|
||||||
|
if(userIndex === -1){
|
||||||
|
return res.status(httpStatus.NOT_FOUND).json({message: 'User not found.'});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hashedPassword = crypto.createHash('sha256').update(password).digest('hex');
|
||||||
|
let userInfo = usersJson[userIndex];
|
||||||
|
userInfo = {
|
||||||
|
id: userInfo.id,
|
||||||
|
name: name,
|
||||||
|
email: email,
|
||||||
|
password: hashedPassword,
|
||||||
|
department: userInfo.department
|
||||||
|
}
|
||||||
|
|
||||||
|
usersJson[userIndex] = userInfo;
|
||||||
|
usersDB.writeFile(usersJson);
|
||||||
|
|
||||||
|
return res.status(httpStatus.OK).json({message: 'Information modified'});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.patch('/change-department', validateBody, (req, res) => {
|
router.patch('/change_department', validateBody, (req, res) => {
|
||||||
|
const usersDB = req.app.get('usersDB');
|
||||||
const { id, department } = req.body;
|
const { id, department } = req.body;
|
||||||
|
|
||||||
|
const userIndex = usersDB.findIndexByKeyValueInArray('id', id);
|
||||||
|
if(userIndex === -1){
|
||||||
|
return res.status(httpStatus.NOT_FOUND).json({message: "User not found."});
|
||||||
|
}
|
||||||
|
|
||||||
|
let usersJson = usersDB.readFile();
|
||||||
|
let userInfo = usersJson[userIndex];
|
||||||
|
|
||||||
|
userInfo = {
|
||||||
|
id: userInfo.id,
|
||||||
|
name: userInfo.name,
|
||||||
|
email: userInfo.email,
|
||||||
|
password: userInfo.password,
|
||||||
|
department: department
|
||||||
|
}
|
||||||
|
|
||||||
|
usersJson[userIndex] = userInfo
|
||||||
|
usersDB.writeFile(usersJson);
|
||||||
|
|
||||||
|
return res.status(httpStatus.Ok).json({message: "Department modified."});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/get_decrypt_keys', (req, res) => {
|
router.get('/get_decrypt_keys', (req, res) => {
|
||||||
|
const ceoDB = req.app.get('ceoDB');
|
||||||
|
const departmentsDB = req.app.get('departmentsDB');
|
||||||
|
const ceoPassword = req.headers['ceo_password'];
|
||||||
|
const {password} = ceoDB.readFile()
|
||||||
|
|
||||||
|
if(ceoPassword !== password){
|
||||||
|
return res.status(httpStatus.UNAUTHORIZED).json({message: 'Invalid CEO password.'});
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(httpStatus.OK).json({
|
||||||
|
message: 'Departments fetched.',
|
||||||
|
data: departmentsDB.readFile()
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.use((req, res) => {
|
||||||
|
return res.status(httpStatus.NOT_FOUND).json({message: "Endpoint not found"});
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -70,7 +70,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
fetch(endpoint, {
|
fetch(endpoint, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': id
|
'Authorization': id,
|
||||||
|
'x-api-key': "uc_api"
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(async response => {
|
.then(async response => {
|
||||||
@@ -116,7 +117,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
fetch(endpoint, {
|
fetch(endpoint, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': id
|
'Authorization': id,
|
||||||
|
'x-api-key': "uc_api"
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(async response => {
|
.then(async response => {
|
||||||
@@ -162,7 +164,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
fetch(endpoint, {
|
fetch(endpoint, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': id
|
'Authorization': id,
|
||||||
|
'x-api-key': "uc_api"
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(async response => {
|
.then(async response => {
|
||||||
|
|||||||
Reference in New Issue
Block a user