Centralized errors and added their translations. Didn't test

This commit is contained in:
leca 2024-10-31 06:33:57 +03:00
parent 47e90764e7
commit 7a2ab7dd5b
26 changed files with 543 additions and 359 deletions

52
messages/en-US/msgs.json Normal file
View File

@ -0,0 +1,52 @@
{
"authentication not found": "Authentication token not found!",
"authentication invalid": "Authentication token is invalid",
"user duplicate": "Such user already exists!",
"user invalid syntax": "Invalid syntax in one of user's parameters!",
"user already in group": "User is already in group!",
"username taken": "Username is taken!",
"username not found": "Such username not found!",
"username required": "Username is required!",
"password required": "Password is required!",
"password invalid": "Wrong password!",
"group name taken": "Group name is taken!",
"group name not found": "Group with such name not found!",
"group id not found": "Group with such ID not found!",
"group not an owner": "You are not an owner of this group!",
"group not a member": "You are not a member of this group!",
"abstract product not found": "Such abstract product is not found!",
"hash without file": "Please, supply a hash of an image!",
"file without hash": "Please, supply an image!",
"abstract product invalid syntax": "Invalid syntax in one of user's parameters!",
"barcode not found": "Such barcode not found!",
"barcode duplicate": "Such barcode already exists!",
"barcode too long": "This barcode is too long!",
"barcode invalid syntax": "Invalid syntax in barcode!",
"abstract product name not found": "Abstract product with such name not found!",
"abstract product name duplicate": "Abstract product with such name already exists!",
"abstract product name too long": "Abstract product name is too long!",
"abstract product name invalid syntax": "Invalid syntax in abstract product name!",
"net weight too long": "Specified net weight is too long!",
"net weight invalid syntax": "Invalid syntax in specified net weight!",
"image hash too long": "Specified image hash is too long!",
"image hash invalid syntax": "Invalid syntax in specified image hash!",
"category too long": "Specified category is too long!",
"category invalid syntax": "Invalid syntax in specified category!",
"category not found": "Such category not found!",
"unit too long": "Specified unit is too long!",
"unit invalid syntax": "Invalid syntax in specified unit!",
"product not found": "Such product not found!",
"product invalid syntax": "Invalid syntax in one of product's parameters!",
"abstract product id not found": "Specified abstract product id not found!",
"abstract product id invalid syntax": "Invalid syntax in abstract product id!",
"expiry date too long": "Specified expiry date is too long!",
"expiry date invalid syntax": "Invalid syntax in specified expiry date!",
"categories not found": "Such category not found!",
"categories duplicate": "Such category already exists!",
"categories invalid syntax": "Invalid syntax in one of category parameters!",
"ok": "Successfull.",
"invalid syntax": "Invalid syntax!",
"png only": "Only .png files are allowed!",
"too long": "Specified value is too long!",
"unknown": "Unknown server error. Please, contact the develoeper!"
}

52
messages/ru-RU/msgs.json Normal file
View File

@ -0,0 +1,52 @@
{
"authentication not found": "Токен аутентификации не найден!",
"authentication invalid": "Токен аутентификации неверен!",
"user duplicate": "Такой пользователь уже существует!",
"user invalid syntax": "Неправильный синткасис в одном из параметров пользователя!",
"user already in group": "Пользователь уже в группе!",
"username taken": "Имя пользователя занято!",
"username not found": "Такое имя пользователя не найдено!",
"username required": "Требуется имя пользователя!",
"password required": "Требуется пароль!",
"password invalid": "Неверный пароль!",
"group name taken": "Такое имя группы уже существует!",
"group name not found": "Группы с таким именем не существует!",
"group id not found": "Группы с таким ID не существует!",
"group not an owner": "Вы не владелец этой группы!",
"group not a member": "Вы не участник этой группы!",
"abstract product not found": "Такой абстрактный продукт не найден!",
"hash without file": "Пожалуйста, укажите хеш изображения!",
"file without hash": "Пожалуйста, укажите изображение!",
"abstract product invalid syntax": "Неправильный синткасис в одном из параметров абстрактного продукта!",
"barcode not found": "Такой штрихкод не найден!",
"barcode duplicate": "Такой штрихкод уже существует!",
"barcode too long": "Этот штрихкод слишком большой!",
"barcode invalid syntax": "Этот штрихкод неверен!",
"abstract product name not found": "абстрактного продукта с таким именем не найдено!",
"abstract product name duplicate": "абстрактный продукт с таким именем уже существует!",
"abstract product name too long": "Имя абстрактного продукта слишком длинное!",
"abstract product name invalid syntax": "Неверный синткасис в имени абстрактного продукта!",
"net weight too long": "Указанный вес нетто слишком длинный!",
"net weight invalid syntax": "Неверный указанный вес нетто!",
"image hash too long": "Указанный хеш изображения слишком длинный!",
"image hash invalid syntax": "Неверный указанный хеш изображения!",
"category too long": "Указанная категория слишком длинная!",
"category invalid syntax": "Неверный синткасис в категории!",
"category not found": "Такая категория не найдена!!",
"unit too long": "Указанная единица измерения слишком длинная!",
"unit invalid syntax": "Неправильный синткасис в указанной единице измерения!",
"product not found": "Такой продукт не найден!",
"product invalid syntax": "Неверный синткасис в одном из параметров продукта!",
"abstract product id not found": "Абстрактный продукт с таким ID не найден!",
"abstract product id invalid syntax": "Неверный синткасис ID абстрактного продукта!",
"expiry date too long": "Указанная дата годен до слишком длинная!",
"expiry date invalid syntax": "Неверный синткасис в указанной дате годен до!",
"categories not found": "Накая категория не найдена!",
"categories duplicate": "Такая категория уже существует!",
"categories invalid syntax": "Неверный синткасис одного из параметров категории!",
"ok": "Успешно.",
"invalid syntax": "Неправильный синткасис!",
"png only": "Разрешены только файлы формата .png!",
"too long": "Указанное значение слишком длинное!",
"unknown": "Неизвестная ошибка сервера! Пожалуйста, сообщите разработчику!"
}

View File

@ -1,41 +1,32 @@
import AbstractProductService from '../services/abstractproduct.js';
import statuses from '../utils/status.js';
import log from '../utils/log.js';
import fs from 'fs';
import path from 'path';
import customError from '../response/customError.js';
import responseCodes from '../response/responseCodes.js';
import translate from '../utils/translate.js';
const TAG = "/controllers/abstractproduct.js";
class AbstractProductController {
async create(req, res) {
try {
const { groupId, localId, barcode, name, net_weight, image_filename, category, unit } = req.body;
const tempPath = req.file.path;
const targetPath = path.join(path.resolve(path.dirname('')), `/uploads/${image_filename}.png`);
if (path.extname(req.file.originalname).toLowerCase() !== ".png") {
return res.status(400).send("Only .png files are allowed")
fs.rmSync(tempPath);
throw new customError(`create abstract product only png allowed`, responseCodes.responses.general.png_only);
}
//fs.renameSync(tempPath, targetPath);
fs.copyFileSync(tempPath, targetPath);
fs.rmSync(tempPath);
await AbstractProductService.create(groupId, localId, barcode, name, net_weight, image_filename, category, unit);
return res.status(200).send("Successfull");
} catch (e) {
switch (e.status) {
case statuses.duplicate:
return res.status(400).send(e.message);
default:
log.error(e.original);
return res.status(500).send(e.message);
}
}
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async update(req, res) {
try {
let { groupId, localId, barcode, name, net_weight, image_filename, category, unit } = req.body;
const tempPath = req.file.path;
@ -49,31 +40,21 @@ class AbstractProductController {
if (net_weight) await AbstractProductService.updateNetWeight(groupId, localId, net_weight);
if (image_filename && tempPath) {
//fs.renameSync(tempPath, targetPath);
fs.copyFileSync(tempPath, targetPath);
fs.rmSync(tempPath);
await AbstractProductService.updateImageFilename(groupId, localId, image_filename);
} else if (image_filename && !tempPath) {
return res.status(400).send("You must supply image file along with its hash");
throw new customError(`Abstract product update image hash without file`, responseCodes.responses.abstractproducts.hash_without_file);
} else if (!image_file && tempPath) {
return res.status(400).send("You must supply image file hash along with file");
fs.rmSync(tempPath);
throw new customError(`Abstract product update file without image hash`, responseCodes.responses.abstractproducts.file_without_hash);
}
if (category) await AbstractProductService.updateCategory(groupId, localId, category);
if (unit) await AbstractProductService.updateUnit(groupId, localId, unit);
return res.status(200).send("Successfull");
} catch (e) {
switch (e.status) {
case statuses.invalid_syntax:
log.error(e.original);
return res.status(400).send(e.message);
default:
log.error(e.original);
return res.status(500).send(e.message);
}
}
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
};

View File

@ -1,25 +1,23 @@
import CategoryService from "../services/category.js";
import log from "../utils/log.js";
import translate from "../utils/translate.js";
const TAG = "controllers/category.js";
class CategoryController {
async create(req, res) {
try {
const { localId, categoryName, groupId } = req.body;
await CategoryService.create(groupId, localId, categoryName);
return res.status(200).send("Success");
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/create: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async update(req, res) {
try {
const { localId, groupId, name } = req.body;
await CategoryService.update(groupId, localId, name);
return res.status(200).send("Success");
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/update: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
};

View File

@ -2,14 +2,13 @@ import GroupService from '../services/group.js';
import UserService from '../services/user.js';
import jwt from 'jsonwebtoken';
import config from '../../config.json' with {type: "json"};
import statuses from '../utils/status.js';
import log from '../utils/log.js';
import translate from '../utils/translate.js';
const TAG = "/controllers/group.js";
class GroupController {
async create(req, res) {
try {
let { groupName } = req.params;
let user = jwt.decode(req.headers.authorization.split(' ')[1], config.secret);
@ -18,33 +17,26 @@ class GroupController {
log.info(`New group with name ${groupName} was just created by user ${user.login.username}`);
UserService.joinGroup(user.login.id, status.id);
return res.status(200).send("Successfull");
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/create: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async join(req, res) {
try {
let { groupId } = req.params;
let user = jwt.decode(req.headers.authorization.split(' ')[1], config.secret);
let status = await UserService.joinGroup(user.login.id, groupId);
if (status == statuses.duplicate) return res.status(400).send("Already in group");
await UserService.joinGroup(user.login.id, groupId);
log.info(`User ${user.login.username} has just joined group with ID ${groupId}`);
return res.status(200).send("Successfull");
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/join: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async updatePassword(req, res) {
try {
let { groupId } = req.params;
let { password } = req.body;
await GroupService.updatePassword(groupId, password);
log.info(`Password for group with ID ${groupId} was updated`);
return res.status(200).send("Successfull");
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/updatePassword ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
}

View File

@ -1,29 +1,19 @@
import ProductService from '../services/product.js';
import statuses from '../utils/status.js';
import log from '../utils/log.js';
import translate from '../utils/translate.js';
const TAG = "/controllers/product.js"
class AbstractProductController {
async create(req, res) {
try {
const { groupId, localId, abstract_product_id, amount, date_of_production, expiry_date } = req.body;
await ProductService.create(groupId, localId, abstract_product_id, amount, date_of_production, expiry_date);
return res.status(200).send("Successfull");
} catch (e) {
switch (e.status) {
case statuses.duplicate:
return res.status(400).send(e.message);
default:
log.error(e.original)
return res.status(500).send(e.message)
}
}
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async update(req, res) {
try {
let { groupId, localId, abstract_product_id, amount, date_of_production, expiry_date } = req.body;
if (abstract_product_id) await ProductService.updateAbstractProductId(groupId, localId, abstract_product_id);
@ -33,15 +23,8 @@ class AbstractProductController {
if (date_of_production) await ProductService.updateDateOfProduction(groupId, localId, date_of_production);
if (expiry_date) await ProductService.updateExpiryDate(groupId, localId, expiry_date);
} catch (e) {
switch (e.status) {
case statuses.invalid_syntax:
log.error(e.original);
return res.status(400).send(e.message);
}
}
return res.status(200).send("Successfull");
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
};

View File

@ -4,35 +4,31 @@ import bcrypt from 'bcrypt';
import genToken from '../utils/jwt.js';
import AbstractProductService from '../services/abstractproduct.js';
import ProductService from '../services/product.js';
import translate from '../utils/translate.js';
const TAG = "/controllers/userjs"
class UserController {
async register(req, res) {
try {
const { username, password } = req.body;
await UserService.create(username, password);
log.info(`New user with name ${username} has just registered`);
return res.status(200).send("Successfull register");
} catch (e) { res.status(500).send(log.unknownError(`${TAG}/register: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async login(req, res) {
try {
const { username, password } = req.body;
const user = await UserService.getByUsername(username);
if (!bcrypt.compareSync(password, user.password)) return res.status(401).send("Wrong password");
const token = genToken(user);
return res.status(200).send(token);
} catch (e) { res.status(500).send(log.unknownError(`${TAG}/login: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
async synchronize(req, res) {
try {
const { groupId } = req.params;
let result = {};
@ -40,8 +36,7 @@ class UserController {
result.products = await ProductService.getAll(groupId);
result.categories = await CategoryService.getAll(groupId);
return res.status(200).json(result);
} catch (e) { res.status(500).send(log.unknownError(`${TAG}/synchronize: ${e}`)); }
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
}
}

View File

@ -3,46 +3,41 @@ import jwt from 'jsonwebtoken';
import config from '../../config.json' with {type: "json"};
import GroupService from '../services/group.js';
import UserService from '../services/user.js';
import customError from '../response/customError.js';
import responseCodes from '../response/responseCodes.js';
const TAG = "/middlewares/auth.js";
const requireUsername = async (req, res, next) => {
if (req.method == "OPTIONS") next();
try {
const { username } = req.body;
if (!username) return res.status(400).send("Username is required");
if (!username) throw new customError(`requireUsername username is required`, responseCodes.responses.usernames.required)
next();
} catch (e) { return res.status(500).send(unknownError(`${TAG}/requireUsername: ${e}`)); }
};
const requirePassword = async (req, res, next) => {
if (req.method == "OPTIONS") next();
try {
const { password } = req.body;
if (!password) return res.status(400).send("Password is required");
if (!password) throw new customError(`requirePassword password is required`, responseCodes.responses.passwords.required);
next();
} catch (e) { return res.status(500).send(unknownError(`${TAG}/requirePassword: ${e}`)); }
};
const authenticate = async (req, res, next) => {
if (req.method == "OPTIONS") next();
try {
if (!req.headers.authorization) return res.status(403).send("No authorization header supplied");
if (!req.headers.authorization) throw new customError(`authenticate no authorization header`, responseCodes.responses.authentication.not_found);
const token = req.headers.authorization.split(' ')[1];
if (!token) return res.status(403).send("No authorization token supplied");
if (!jwt.verify(token, config.secret)) return res.status(403).send("Authorization token is incorrect");
if (!token) throw new customError(`authenticate no authorization token in header`, responseCodes.responses.authentication.not_found);
if (!jwt.verify(token, config.secret)) throw new customError(`authenticate token is invalid`, responseCodes.responses.authentication.invalid);
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/authenticate: ${e}`)); }
};
const authorizeGroupOwner = async (req, res, next) => {
if (req.method == "OPTIONS") next();
try {
const token = req.headers.authorization.split(' ')[1];
const { groupId } = req.params;
@ -50,24 +45,21 @@ const authorizeGroupOwner = async (req, res, next) => {
let user = jwt.decode(token, config.secret);
let adminId = await GroupService.getAdminId(groupId);
if (user.login.id != adminId) return res.status(403).send("Not your group");
if (user.login.id != adminId) throw new customError(`authorizeGroupOwner not an owner`, responseCodes.responses.groups.not_an_owner)
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/authorizeGroupOwner: ${e}`)); }
};
const checkGroupPassword = async (req, res, next) => {
if (req.method == "OPTIONS") next();
try {
const { groupId } = req.params;
const { password } = req.body;
const groupPassword = await GroupService.getPassword(groupId);
if (groupPassword != password) return res.status(403).send("Wrong password");
if (groupPassword != password) throw new customError(`checkGroupPassword password is invalid`, responseCodes.responses.passwords.invalid);
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/checkGroupPassword: ${e}`)); }
};
const userIsInGroup = async (req, res, next) => {
@ -77,7 +69,7 @@ const userIsInGroup = async (req, res, next) => {
const token = req.headers.authorization.split(' ')[1];
let user = jwt.decode(token, config.secret);
if (!await UserService.isInGroup(user.login.id, groupId)) return res.status(403).send("You are not a member of this group");
if (!await UserService.isInGroup(user.login.id, groupId)) throw new customError(`userIsInGroup not a member`, responseCodes.responses.groups.not_a_member)
next();
};

View File

@ -1,116 +0,0 @@
import UserService from '../services/user.js';
import GroupService from '../services/group.js';
import AbstractProductService from '../services/abstractproduct.js';
import ProductService from '../services/product.js';
import CategoryService from '../services/category.js';
import log from '../utils/log.js';
import statuses from '../utils/status.js';
const TAG = "/middlewares/existance.js";
const usernameExists = async (req, res, next) => {
try {
let { username } = req.body;
let user = await UserService.getByUsername(username);
if (!user || user == statuses.not_found) return res.status(404).send("User not found");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/usernameExists: ${e}`)); }
};
const usernameDoesntExist = async (req, res, next) => {
try {
let { username } = req.body;
let user = await UserService.getByUsername(username);
if (user != undefined && user != statuses.not_found) return res.status(400).send("Such username already taken");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/usernameDoesntExist: ${e}`)); }
};
const groupExists = async (req, res, next) => {
try {
let groupId = req.params.groupId || req.body.groupId;
let group = await GroupService.getById(groupId);
if (!group || group == statuses.not_found) return res.status(404).send("Group not found");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/groupExists: ${e}`)) }
};
const groupDoesntExist = async (req, res, next) => {
try {
let groupId = req.params.groupId || req.body.groupId;
let group = await GroupService.getById(groupId);
if (group || group != statuses.not_found) return res.status(400).send("Such group already exists");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/groupDoesntExist: ${e}`)) }
};
const groupNameDoesntExist = async (req, res, next) => {
try {
const { groupName } = req.params;
let group = await GroupService.getByName(groupName);
if (group) return res.status(400).send("Such group name already exists");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/groupNameDoesntExist: ${e}`)); }
};
const abstractProductExists = async (req, res, next) => {
try {
const { groupId, localId } = req.body;
let result = await AbstractProductService.exists(groupId, localId);
if (!result) return res.status(404).send("Abstract product not found");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/abstractProductExists: ${e}`)); }
};
const productExists = async (req, res, next) => {
try {
const { groupId, localId } = req.body;
let result = await ProductService.exists(groupId, localId);
if (!result) return res.status(404).send("Product not found");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/productExists: ${e}`)); }
};
const categoryNameDoesntExist = async (req, res, next) => {
try {
const { categoryName, localId, groupId } = req.body;
let result = await CategoryService.getByName(groupId, localId, categoryName);
if (result != statuses.not_found) return res.status(400).send("Such category name exists");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/categoryNameDoesntExist: ${e}`)); }
};
const categoryExists = async (req, res, next) => {
try {
const { localId, groupId } = req.body;
let result = await CategoryService.getById(groupId, localId);
if (!result || result == statuses.not_found) return res.status(404).send("No such category");
next();
} catch (e) { return res.status(500).send(log.unknownError(`${TAG}/categoryExists: ${e}`)); }
};
export default {
usernameExists,
usernameDoesntExist,
groupExists,
groupDoesntExist,
groupNameDoesntExist,
abstractProductExists,
productExists,
categoryNameDoesntExist,
categoryExists
};

View File

@ -0,0 +1,12 @@
class customError extends Error {
constructor(message, code) {
super(message)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, customError);
}
this.code = code;
}
}
export default customError;

View File

@ -0,0 +1,26 @@
import log from "../utils/log";
import customError from "./customError";
import responses from './responseCodes';
import translate from '../utils/translate.js';
const errorHandler = (err, req, res) => {
log.error(err);
let language = req.headers["accept-language"];
if (err instanceof customError) {
return res.status(responses.getHTTPCode(err.code)).send(translate(language, code));
}
}
const tryHandler = (func) => {
return async (req, res, next) => {
try {
await func(req, res, next);
} catch (err) {
errorHandler(err, req, res);
}
}
}
export default tryHandler;

View File

@ -0,0 +1,218 @@
import fs from 'fs';
const responses = {
authentication: {
not_found: "authentication not found",
invalid: "authentication invalid"
},
user: {
duplicate: "user duplicate",
invalid_syntax: "user invalid syntax",
already_in_group: "user already in group"
},
usernames: {
duplicate: "username taken",
not_found: "username not found",
required: "username required"
},
passwords: {
required: "password required",
invalid: "password invalid"
},
groups: {
duplicate: "group name taken",
name_not_found: "group name not found",
id_not_found: "group id not found",
not_an_owner: "group not an owner",
not_a_member: "group not a member"
},
abstractproducts: {
not_found: "abstract product not found",
hash_without_file: "hash without file",
file_without_hash: "file without hash",
invalid_syntax: "abstract product invalid syntax"
},
barcode: {
not_found: "barcode not found",
duplicate: "barcode duplicate",
too_long: "barcode too long",
invalid_syntax: "barcode invalid syntax"
},
abstractproductname: {
not_found: "abstract product name not found",
duplicate: "abstract product name duplicate",
too_long: "abstract product name too long",
invalid_syntax: "abstract product name invalid syntax"
},
netweight: {
too_long: "net weight too long",
invalid_syntax: "net weight invalid syntax"
},
imagehash: {
too_long: "image hash too long",
invalid_syntax: "image hash invalid syntax"
},
category: {
too_long: "category too long",
invalid_syntax: "category invalid syntax",
not_found: "category not found"
},
unit: {
too_long: "unit too long",
invalid_syntax: "unit invalid syntax"
},
products: {
not_found: "product not found",
invalid_syntax: "product invalid syntax"
},
abstractproductid: {
not_found: "abstract product id not found",
invalid_syntax: "abstract product id invalid syntax"
},
amount: {
too_long: "amount too long",
invalid_syntax: "amount invalid syntax"
},
dateofproduction: {
too_long: "date of production too long",
invalid_syntax: "date of production invalid syntax"
},
expirydate: {
too_long: "expiry date too long",
invalid_syntax: "expiry date invalid syntax"
},
categories: {
duplicate: "categories duplicate",
not_found: "categories not found"
},
general: {
ok: "ok",
invalid_syntax: "invalid syntax",
png_only: "png only",
too_long: "too long",
unknown: "unknown"
}
}
const getHTTPCode = (type) => {
switch (code) {
case responses.general.ok:
return 200
case responses.general.invalid_syntax:
return 400
case responses.general.unknown:
return 500
case responses.general.png_only:
return 400
case responses.general.too_long:
return 400
case responses.authentication.invalid:
return 403
case responses.authentication.not_found:
return 403
case responses.user.already_in_group:
return 409
case responses.user.duplicate:
return 409
case responses.user.invalid_syntax:
return 400
case responses.usernames.duplicate:
return 409
case responses.usernames.not_found:
return 404
case responses.usernames.required:
return 400
case responses.passwords.required:
return 400
case responses.passwords.invalid:
return 403
case responses.groups.id_not_found:
return 404
case responses.groups.name_not_found:
return 404
case responses.groups.duplicate:
return 409
case responses.groups.not_an_owner:
return 403
case responses.groups.not_a_member:
return 403
case responses.abstractproducts.not_found:
return 404
case responses.abstractproducts.file_without_hash:
return 400
case responses.abstractproducts.hash_without_file:
return 400
case responses.abstractproducts.invalid_syntax:
return 400
case responses.abstractproductid.invalid_syntax:
return 400
case responses.abstractproductid.not_found:
return 404
case responses.abstractproductname.duplicate:
return 409
case responses.abstractproductname.invalid_syntax:
return 400
case responses.abstractproductname.not_found:
return 404
case responses.abstractproductname.too_long:
return 400
case responses.abstractproducts.file_without_hash:
return 400
case responses.abstractproducts.hash_without_file:
return 400
case responses.abstractproducts.invalid_syntax:
return 400
case responses.abstractproducts.not_found:
return 404
case responses.amount.invalid_syntax:
return 400
case responses.amount.too_long:
return 409
case responses.barcode.duplicate:
return 409
case responses.barcode.invalid_syntax:
return 400
case responses.barcode.not_found:
return 404
case responses.barcode.too_long:
return 400
case responses.categories.duplicate:
return 409
case responses.categories.not_found:
return 404
case responses.category.invalid_syntax:
return 400
case responses.category.too_long:
return 400
case responses.category.not_found:
return 404
case responses.dateofproduction.invalid_syntax:
return 400
case responses.dateofproduction.too_long:
return 400
case responses.expirydate.invalid_syntax:
return 400
case responses.expirydate.too_long:
return 400
default:
return 500
}
}
export default { responses, getHTTPCode }

View File

@ -1,9 +1,9 @@
import { Router } from 'express';
import auth from '../middlewares/auth.js';
import AbstractProductController from '../controllers/abstractproduct.js';
import existance from '../middlewares/existance.js';
import multer from 'multer';
import path from 'path';
import tryHandler from '../response/errorHandler.js';
const upload = multer(({
dest: path.join(path.resolve(path.dirname('')), "/temp")
@ -11,7 +11,7 @@ const upload = multer(({
const AbstractProductRouter = new Router();
AbstractProductRouter.post('/create', upload.single("file"), auth.authenticate, existance.groupExists, auth.userIsInGroup, AbstractProductController.create);
AbstractProductRouter.post('/update', upload.single("file"), auth.authenticate, existance.groupExists, auth.userIsInGroup, existance.abstractProductExists, AbstractProductController.update);
AbstractProductRouter.post('/create', upload.single("file"), tryHandler(auth.authenticate), tryHandler(auth.userIsInGroup), tryHandler(AbstractProductController.create));
AbstractProductRouter.post('/update', upload.single("file"), tryHandler(auth.authenticate), tryHandler(auth.userIsInGroup), tryHandler(AbstractProductController.update));
export default AbstractProductRouter;

View File

@ -1,11 +1,11 @@
import { Router } from 'express';
import auth from '../middlewares/auth.js';
import existance from '../middlewares/existance.js';
import CategoryController from '../controllers/category.js';
import tryHandler from '../response/errorHandler.js';
const CategoryRouter = new Router();
CategoryRouter.post('/create', auth.authenticate, existance.groupExists, existance.categoryNameDoesntExist, CategoryController.create);
CategoryRouter.post('/update', auth.authenticate, existance.groupExists, existance.categoryExists, CategoryController.update);
CategoryRouter.post('/create', tryHandler(auth.authenticate), tryHandler(CategoryController.create));
CategoryRouter.post('/update', tryHandler(auth.authenticate), tryHandler(CategoryController.update));
export default CategoryRouter;

View File

@ -1,12 +1,12 @@
import { Router } from 'express';
import auth from '../middlewares/auth.js';
import GroupController from '../controllers/group.js';
import existance from '../middlewares/existance.js';
import tryHandler from '../response/errorHandler.js';
const GroupRouter = new Router();
GroupRouter.post('/create/:groupName', auth.authenticate, existance.groupNameDoesntExist, GroupController.create);
GroupRouter.post('/join/:groupId', auth.authenticate, existance.groupExists, auth.requirePassword, auth.checkGroupPassword, GroupController.join);
GroupRouter.post('/password/:groupId', auth.authenticate, existance.groupExists, auth.authorizeGroupOwner, auth.requirePassword, GroupController.updatePassword);
GroupRouter.post('/create/:groupName', tryHandler(auth.authenticate), tryHandler(GroupController.create));
GroupRouter.post('/join/:groupId', tryHandler(auth.authenticate), tryHandler(auth.requirePassword), tryHandler(auth.checkGroupPassword), tryHandler(GroupController.join));
GroupRouter.post('/password/:groupId', tryHandler(auth.authenticate), tryHandler(auth.authorizeGroupOwner), tryHandler(auth.requirePassword), tryHandler(GroupController.updatePassword));
export default GroupRouter;

View File

@ -1,11 +1,11 @@
import { Router } from 'express';
import auth from '../middlewares/auth.js';
import ProductController from '../controllers/product.js'
import existance from '../middlewares/existance.js';
import tryHandler from '../response/errorHandler.js';
const ProductRouter = new Router();
ProductRouter.post('/create', auth.authenticate, existance.groupExists, auth.userIsInGroup, ProductController.create);
ProductRouter.post('/update', auth.authenticate, existance.groupExists, auth.userIsInGroup, existance.productExists, ProductController.update);
ProductRouter.post('/create', tryHandler(auth.authenticate), tryHandler(auth.userIsInGroup), tryHandler(ProductController.create));
ProductRouter.post('/update', tryHandler(auth.authenticate), tryHandler(auth.userIsInGroup), tryHandler(ProductController.update));
export default ProductRouter;

View File

@ -1,12 +1,12 @@
import { Router } from 'express';
import auth from '../middlewares/auth.js';
import existance from '../middlewares/existance.js';
import UserController from '../controllers/user.js';
import tryHandler from '../response/errorHandler.js';
const UserRouter = new Router();
UserRouter.post('/register', auth.requireUsername, auth.requirePassword, existance.usernameDoesntExist, UserController.register);
UserRouter.post('/login', auth.requireUsername, auth.requirePassword, existance.usernameExists, UserController.login);
UserRouter.get('/synchronize/:groupId', auth.authenticate, existance.groupExists, auth.userIsInGroup, UserController.synchronize);
UserRouter.post('/register', tryHandler(auth.requireUsername), tryHandler(auth.requirePassword), tryHandler(UserController.register));
UserRouter.post('/login', tryHandler(auth.requireUsername), tryHandler(auth.requirePassword), tryHandler(UserController.login));
UserRouter.get('/synchronize/:groupId', tryHandler(auth.authenticate), tryHandler(auth.userIsInGroup), tryHandler(UserController.synchronize));
export default UserRouter;

View File

@ -1,12 +1,15 @@
import db from '../db.js';
import statuses from '../utils/status.js';
import errorHandler from '../utils/pgerrorhandler.js';
import tryHandler from '../response/errorHandler.js';
import responses from '../response/responseCodes.js';
import customError from '../response/customError.js';
class AbstractProductService {
async create(groupid, localid, barcode, name, net_weight, image_filename, category, unit) {
await db.query("INSERT INTO abstract_products (group_id, local_id, barcode, name, net_weight, image_filename, category, unit) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)", [groupid, localid, barcode, name, net_weight, image_filename, category, unit])
.catch((e) => {
errorHandler(e, "abstract product")
errorHandler(e, "abstractproduct")
});
}
@ -20,21 +23,21 @@ class AbstractProductService {
async updateName(groupId, localId, name) {
await db.query("UPDATE abstract_products SET name = $1 WHERE group_id = $2 AND local_id = $3", [name, groupId, localId])
.catch((e) => {
errorHandler(e, "name")
errorHandler(e, "abstractproductname")
});
}
async updateNetWeight(groupId, localId, net_weight) {
await db.query("UPDATE abstract_products SET net_weight = $1 WHERE group_id = $2 AND local_id = $3", [net_weight, groupId, localId]
.catch((e) => {
errorHandler(e, "net weight")
errorHandler(e, "netweight")
}));
}
async updateImageFilename(groupId, localId, image_filename) {
await db.query("UPDATE abstract_products SET image_filename = $1 WHERE group_id = $2 AND local_id = $3", [image_filename, groupId, localId])
.catch((e) => {
errorHandler(e, "image filename")
errorHandler(e, "imagehash")
});
}
@ -54,7 +57,7 @@ class AbstractProductService {
async getAll(groupId) {
let result = (await db.query("SELECT local_id, barcode, name, net_weight, image_filename, category, unit FROM abstract_products WHERE group_id = $1", [groupId])).rows;
if (!result) return statuses.not_found;
if (!result) throw new customError("getAll abstract products not found", responses.responses.abstractproducts.not_found)
return result;
}

View File

@ -1,4 +1,6 @@
import db from '../db.js';
import customError from '../response/customError.js';
import responseCodes from '../response/responseCodes.js';
import statuses from '../utils/status.js';
class CategoryService {
@ -11,14 +13,14 @@ class CategoryService {
}
async getById(groupId, localId) {
let result = (await db.query("SELECT * FROM categories WHERE group_id = $1 AND local_id = $2", [groupId, localId]))
if (result.rowCount == 0) return statuses.not_found;
let result = (await db.query("SELECT * FROM categories WHERE group_id = $1 AND local_id = $2", [groupId, localId]));
if (result.rowCount == 0) throw new customError(`getById categorirs not found`, responseCodes.responses.category.not_found)
return result.rows[0];
}
async getByName(groupId, localId, name) {
let result = (await db.query("SELECT * FROM categories WHERE group_id = $1 AND local_id = $2 AND name = $3", [groupId, localId, name]));
if (result.rowCount == 0) return statuses.not_found;
if (result.rowCount == 0) throw new customError(`getByName categories not found`, responseCodes.responses.category.not_found)
return result.rows[0];
}
}

View File

@ -1,17 +1,18 @@
import db from '../db.js';
import customError from '../response/customError.js';
import responseCodes from '../response/responseCodes.js';
import errorHandler from '../utils/pgerrorhandler.js';
import status from '../utils/status.js';
class GroupService {
async create(name, creatorId) {
let res = await db.query("INSERT INTO groups (name, admin_id) VALUES ($1, $2) RETURNING ID", [name, creatorId]).catch(errorHandler);
let res = await db.query("INSERT INTO groups (name, admin_id) VALUES ($1, $2) RETURNING ID", [name, creatorId]).catch((e) => errorHandler(e, "group"));
return res.rows[0];
}
async getById(id) {
let res = (await db.query("SELECT * FROM groups WHERE id = $1", [id]));
if (res.rowCount == 0) return status.not_found;
if (res.rowCount == 0) throw new customError(`getByUd group not found`, responseCodes.responses.groups.id_not_found);
return res.rows[0];
}
@ -28,7 +29,9 @@ class GroupService {
}
async getByName(name) {
return (await db.query("SELECT * FROM groups WHERE name = $1", [name])).rows[0];
let res = (await db.query("SELECT * FROM groups WHERE name = $1", [name]));
if (res.rowCount == 0) throw new customError(`getByName group not found`, responseCodes.responses.groups.name_not_found);
return res.rows[0];
}
};

View File

@ -1,19 +1,20 @@
import db from '../db.js';
import statuses from '../utils/status.js';
import errorHandler from '../utils/pgerrorhandler.js';
import customError from '../response/customError.js';
import responseCodes from '../response/responseCodes.js';
class ProductService {
async create(groupid, localid, abstract_product_id, amount, date_of_production, expiry_date) {
await db.query("INSERT INTO products (group_id, local_id, abstract_product_id, amount, date_of_production, expiry_date) VALUES ($1, $2, $3, $4, $5, $6)", [groupid, localid, abstract_product_id, amount, date_of_production, expiry_date])
.catch((e) => {
errorHandler(e, "Abstract Product")
errorHandler(e, "product")
});
}
async updateAbstractProductId(groupId, localId, abstract_product_id) {
await db.query("UPDATE products SET abstract_product_id = $1 WHERE group_id = $2 AND local_id = $3", [abstract_product_id, groupId, localId])
.catch((e) => {
errorHandler(e, "abstract product id")
errorHandler(e, "abstractproductid")
});
}
@ -28,20 +29,20 @@ class ProductService {
async updateDateOfProduction(groupId, localId, date_of_production) {
await db.query("UPDATE products SET date_of_production = $1 WHERE group_id = $2 AND local_id = $3", [date_of_production, groupId, localId])
.catch((e) => {
errorHandler(e, "date of production")
errorHandler(e, "dateofproduction")
});
}
async updateExpiryDate(groupId, localId, expiry_date) {
await db.query("UPDATE products SET expiry_date = $1 WHERE group_id = $2 AND local_id = $3", [expiry_date, groupId, localId])
.catch((e) => {
errorHandler(e, "expiry date")
errorHandler(e, "expirydate")
});
}
async getAll(groupId) {
let result = (await db.query("SELECT local_id, abstract_product_id, amount, date_of_production, expiry_date FROM products WHERE group_id = $1", [groupId])).rows;
if (!result) return statuses.not_found;
if (!result) throw new customError(`getAll product not found`, responseCodes.responses.products.not_found);
return result;
}

View File

@ -1,4 +1,6 @@
import db from '../db.js'
import customError from '../response/customError.js';
import responseCodes from '../response/responseCodes.js';
import statuses from '../utils/status.js';
import bcrypt from 'bcrypt';
@ -12,12 +14,14 @@ class UserService {
async getByUsername(username) {
let user = (await db.query("SELECT * FROM Users WHERE username = $1", [username])).rows;
if (user == undefined) return statuses.not_found;
if (user == undefined) throw new customError(`getByUsername user not found`, responseCodes.responses.usernames.not_found);
return (user[0]);
}
async getAll() {
return (await db.query("SELECT * FROM Users")).rows;
let res = await db.query("SELECT * FROM Users");
if (res.rowCount == 0) throw new customError(`getAll user not found`, responseCodes.responses.usernames.not_found);
return res.rows[0]
}
async isInGroup(userId, groupId) {
@ -25,7 +29,7 @@ class UserService {
}
async joinGroup(userId, groupId) {
if (await (this.isInGroup(userId, groupId))) return statuses.duplicate;
if (await (this.isInGroup(userId, groupId))) throw new customError(`joinGroup user already in group`, responseCodes.responses.user.already_in_group);
await db.query("UPDATE Users SET groups = array_append(groups, $1::integer) WHERE ID = $2", [groupId, userId]);
return statuses.ok;
}

View File

@ -2,23 +2,23 @@ import config from '../../config.json' with {type: "json"};
const debug = (text) => {
if (config.debug) console.debug(`[D] [${Date()}]: ${text}`);
}
};
const info = (text) => {
console.log(`[I] [${Date()}]: ${text}`);
}
};
const error = (text) => {
console.error(`[E] [${Date()}]: ${text}`);
}
};
const warn = (text) => {
console.warn(`[W] [${Date()}]: ${text}`);
}
};
const unknownError = (text) => {
error(text);
return "Unknown server error. Please, report to the developer";
}
};
export default { debug, info, error, warn, unknownError };

View File

@ -1,28 +1,16 @@
import statuses from "./status.js";
import customError from "../response/customError.js";
import responseCodes from "../response/responseCodes.js";
const errorHandler = (e, obj) => {
switch (e.code) {
case '23505':
throw {
status: statuses.duplicate,
message: `Such ${obj} already exists`
};
throw new customError(`Duplicate ${obj}`, responseCodes.responses[obs].duplicate)
case '22007':
throw {
status: statuses.invalid_syntax,
message: `Invalid syntax in ${obj}`
};
throw new customError(`Invalid syntax ${obj}`, responseCodes.responses.general.invalid_syntax)
case '22001':
throw {
status: statuses.invalid_syntax,
message: `Value too long (${obj})`
};
throw new customError(`Value too long ${obj}`, responseCodes.responses[obj].too_long)
default:
throw {
status: statuses.unknown,
message: `Unknown error. Please, report to the developer`,
original: e
};
throw new customError(`Unknown error ${obj}`, responseCodes.responses.general.unknown)
};
};

View File

@ -1,9 +0,0 @@
const statuses = {
ok: "ok",
duplicate: "duplicate",
not_found: "not found",
invalid_syntax: "invalid syntax",
unknown: "unknown"
};
export default statuses;

7
src/utils/translate.js Normal file
View File

@ -0,0 +1,7 @@
const translate = (language, code) => {
if (!language) language = "en-US"
if (!code) code = "unknown"
return JSON.parse(fs.readFileSync(`../../messages/${language}/msgs.json`).toString())[code]
}
export default translate