Compare commits
11 Commits
2be40b6f34
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 010475bca2 | |||
| 63aaa30d92 | |||
| 947dc720a5 | |||
| 7d98ba89c5 | |||
| 9988cedbc4 | |||
| 4f5cd78eb0 | |||
| 0e4cc6507b | |||
| 1e6975fa13 | |||
| 05652f1cfb | |||
| 3c7e88d389 | |||
| eb0c8ac99d |
@@ -13,10 +13,8 @@ services:
|
||||
- ./data/uploads:/uploads
|
||||
database:
|
||||
image: 'postgres:15'
|
||||
|
||||
# ports:
|
||||
# - 5432:5432
|
||||
|
||||
volumes:
|
||||
- ./data/db:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: bsfe
|
||||
POSTGRES_PASSWORD: Ch@NgEME!
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"user invalid syntax": "Invalid syntax in one of user's parameters!",
|
||||
"user already in group": "User is already in group!",
|
||||
"user not found": "User does not exists!",
|
||||
"admin leave": "You are an admin of that group. You must transfer ownership of that group first!",
|
||||
"username taken": "Username is taken!",
|
||||
"username not found": "Such username not found!",
|
||||
"username required": "Username is required!",
|
||||
@@ -15,6 +16,8 @@
|
||||
"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!",
|
||||
"name not specified": "New name of a group is not specified!",
|
||||
"new owner not specified": "ID of a new group owner is not specified!",
|
||||
"abstract product not found": "Such abstract product is not found!",
|
||||
"abstract product invalid syntax": "Invalid syntax in one of user's parameters!",
|
||||
"barcode not found": "Such barcode not found!",
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"user invalid syntax": "Неправильный синткасис в одном из параметров пользователя!",
|
||||
"user already in group": "Пользователь уже в группе!",
|
||||
"user not found": "Пользователь не существует!",
|
||||
"admin leave": "Вы являетесь администратором группы. Перед выходом передайте владение группой!",
|
||||
"username taken": "Имя пользователя занято!",
|
||||
"username not found": "Такое имя пользователя не найдено!",
|
||||
"username required": "Требуется имя пользователя!",
|
||||
@@ -15,6 +16,8 @@
|
||||
"group id not found": "Группы с таким ID не существует!",
|
||||
"group not an owner": "Вы не владелец этой группы!",
|
||||
"group not a member": "Вы не участник этой группы!",
|
||||
"name not specified": "Не указано новое имя группы!",
|
||||
"new owner not specified": "Не указан ID нового владельца группы!",
|
||||
"abstract product not found": "Такой абстрактный продукт не найден!",
|
||||
"abstract product invalid syntax": "Неправильный синткасис в одном из параметров абстрактного продукта!",
|
||||
"barcode not found": "Такой штрихкод не найден!",
|
||||
|
||||
@@ -45,11 +45,18 @@ class AbstractProductController {
|
||||
|
||||
if (req.file) {
|
||||
tempPath = req.file.path;
|
||||
|
||||
let previousImageHash = (await AbstractProductService.getByLocalId(groupId, localId)).image_filename
|
||||
let previousImagePath = path.join(path.resolve(path.dirname('')), `/uploads/${previousImageHash}.png`);
|
||||
fs.unlinkSync(previousImagePath)
|
||||
|
||||
image_buffer = fs.readFileSync(tempPath);
|
||||
image_filename = createHash('md5').update(image_buffer).digest('hex');
|
||||
targetPath = path.join(path.resolve(path.dirname('')) + `/uploads/${image_filename}.png`);
|
||||
fs.copyFileSync(tempPath, targetPath);
|
||||
fs.rmSync(tempPath);
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (barcode) await AbstractProductService.updateBarcode(groupId, localId, barcode);
|
||||
@@ -93,6 +100,10 @@ class AbstractProductController {
|
||||
async delete(req, res) {
|
||||
let { localId, groupId } = req.params;
|
||||
|
||||
let imageFilename = (await AbstractProductService.getByLocalId(groupId, localId)).image_filename
|
||||
let imagePath = path.join(path.resolve(path.dirname('')), `/uploads/${imageFilename}.png`);
|
||||
fs.unlinkSync(imagePath)
|
||||
|
||||
await AbstractProductService.delete(groupId, localId)
|
||||
|
||||
notify(req.headers.authorization.split(' ')[1], groupId, 'delete', 'abstractproduct', { local_id: localId });
|
||||
|
||||
@@ -5,6 +5,7 @@ import config from '../../config.json' with {type: "json"};
|
||||
import log from '../utils/log.js';
|
||||
import translate from '../utils/translate.js';
|
||||
import responseCodes from '../response/responseCodes.js';
|
||||
import customError from '../response/customError.js';
|
||||
|
||||
const TAG = "/controllers/group.js";
|
||||
|
||||
@@ -15,10 +16,7 @@ class GroupController {
|
||||
let user = jwt.decode(req.headers.authorization.split(' ')[1], config.secret);
|
||||
let group = await GroupService.create(groupName, user.login.id);
|
||||
|
||||
log.info(`New group with name ${groupName} was just created by user ${user.login.username}`);
|
||||
|
||||
await UserService.joinGroup(user.login.id, group.id);
|
||||
// return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
|
||||
return res.status(200).send(group.id.toString())
|
||||
}
|
||||
async join(req, res) {
|
||||
@@ -27,7 +25,21 @@ class GroupController {
|
||||
let user = jwt.decode(req.headers.authorization.split(' ')[1], config.secret);
|
||||
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(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
|
||||
}
|
||||
|
||||
async leave(req, res) {
|
||||
let groupId = req.params.groupId;
|
||||
|
||||
let user = jwt.decode(req.headers.authorization.split(' ')[1], config.secret);
|
||||
|
||||
if (await GroupService.getAdminId(groupId) == user.login.id) {
|
||||
let code = responseCodes.responses.user.admin_leave
|
||||
return res.status(responseCodes.getHTTPCode(code)).send(translate(req.headers["accept-language"], code))
|
||||
}
|
||||
|
||||
await UserService.leaveGroup(user.login.id, groupId);
|
||||
|
||||
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
|
||||
}
|
||||
|
||||
@@ -75,6 +87,28 @@ class GroupController {
|
||||
|
||||
return res.status(200).send(result.toString())
|
||||
}
|
||||
|
||||
async rename(req, res) {
|
||||
const groupId = req.params.groupId;
|
||||
const name = req.body.name;
|
||||
|
||||
if (!name) throw new customError(`New group name is not specified`, responseCodes.responses.groups.name_not_specified);
|
||||
|
||||
await GroupService.rename(groupId, name);
|
||||
|
||||
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
|
||||
}
|
||||
|
||||
async transferOwnership(req, res) {
|
||||
const groupId = req.params.groupId;
|
||||
const userId = req.body.userId;
|
||||
|
||||
if (!userId) throw new customError(`New owner id is not specified`, responseCodes.responses.groups.new_owner_not_specified);
|
||||
|
||||
await GroupService.transferOwnership(groupId, userId);
|
||||
|
||||
return res.status(200).send(translate(req.headers["accept-language"], responseCodes.responses.general.ok));
|
||||
}
|
||||
}
|
||||
|
||||
export default new GroupController();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import ProductService from '../services/product.js';
|
||||
import translate from '../utils/translate.js';
|
||||
import responseCodes from '../response/responseCodes.js';
|
||||
|
||||
import notify from '../utils/notify.js';
|
||||
const TAG = "/controllers/product.js"
|
||||
|
||||
class AbstractProductController {
|
||||
|
||||
12
src/index.js
12
src/index.js
@@ -32,10 +32,12 @@ app.get('/status', (req, res) => {
|
||||
|
||||
wss.on('connection', (client) => {
|
||||
client.on('message', async (message) => {
|
||||
if (message == "keepalive") return;
|
||||
|
||||
let parsed = JSON.parse(message);
|
||||
let token = parsed.token;
|
||||
let currentGroup = parsed.currentGroup;
|
||||
|
||||
try {
|
||||
if (!jwt.verify(token, config.secret)) {
|
||||
client.send("Invalid token");
|
||||
return;
|
||||
@@ -45,6 +47,11 @@ wss.on('connection', (client) => {
|
||||
client.send("Not a member of specified group");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
log.error("Error during connection through websocket.")
|
||||
client.send("Error")
|
||||
return;
|
||||
}
|
||||
|
||||
clients.push({
|
||||
socket: client,
|
||||
@@ -56,6 +63,7 @@ wss.on('connection', (client) => {
|
||||
client.on('close', () => {
|
||||
for (let i = 0; i < clients.length; i++) {
|
||||
if (clients[i].socket == client) {
|
||||
log.debug(`Client with token ${clients[i].token} has disconnected`)
|
||||
clients.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
@@ -69,7 +77,7 @@ const server = app.listen(config.port, () => {
|
||||
|
||||
server.on('upgrade', (req, res, head) => {
|
||||
wss.handleUpgrade(req, res, head, socket => {
|
||||
wss.emit('connection', socket, request);
|
||||
wss.emit('connection', socket, req);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ const responses = {
|
||||
duplicate: "user duplicate",
|
||||
invalid_syntax: "user invalid syntax",
|
||||
already_in_group: "user already in group",
|
||||
not_found: "user not found"
|
||||
not_found: "user not found",
|
||||
admin_leave: "admin leave"
|
||||
},
|
||||
usernames: {
|
||||
duplicate: "username taken",
|
||||
@@ -23,7 +24,9 @@ const responses = {
|
||||
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"
|
||||
not_a_member: "group not a member",
|
||||
name_not_specified: "name not specified",
|
||||
new_owner_not_specified: "new owner not specified"
|
||||
},
|
||||
abstractproducts: {
|
||||
not_found: "abstract product not found",
|
||||
@@ -117,6 +120,8 @@ const getHTTPCode = (type) => {
|
||||
return 400
|
||||
case responses.user.not_found:
|
||||
return 404
|
||||
case responses.user.admin_leave:
|
||||
return 409
|
||||
|
||||
|
||||
case responses.usernames.duplicate:
|
||||
@@ -141,6 +146,10 @@ const getHTTPCode = (type) => {
|
||||
return 403
|
||||
case responses.groups.not_a_member:
|
||||
return 403
|
||||
case responses.groups.name_not_specified:
|
||||
return 400
|
||||
case responses.new_owner_not_specified:
|
||||
return 400
|
||||
|
||||
case responses.abstractproducts.not_found:
|
||||
return 404
|
||||
|
||||
@@ -8,10 +8,12 @@ const GroupRouter = new Router();
|
||||
|
||||
GroupRouter.post('/create/:groupName', tryHandler(auth.authenticate), tryHandler(GroupController.create));
|
||||
GroupRouter.post('/join/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.requirePassword), tryHandler(auth.checkGroupPassword), tryHandler(GroupController.join));
|
||||
GroupRouter.get('/leave/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.leave));
|
||||
GroupRouter.post('/password/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.authorizeGroupOwner), tryHandler(auth.requirePassword), tryHandler(GroupController.updatePassword));
|
||||
GroupRouter.get('/byName/:groupName', tryHandler(auth.authenticate), tryHandler(existance.groupNameExists), tryHandler(GroupController.getByName))
|
||||
GroupRouter.get('/byId/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.getById))
|
||||
GroupRouter.get('/getUsers/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.getUsersInGroup))
|
||||
GroupRouter.get('/adminId/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.getAdminId))
|
||||
|
||||
GroupRouter.get('/byName/:groupName', tryHandler(auth.authenticate), tryHandler(existance.groupNameExists), tryHandler(GroupController.getByName));
|
||||
GroupRouter.get('/byId/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.getById));
|
||||
GroupRouter.get('/getUsers/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.getUsersInGroup));
|
||||
GroupRouter.get('/adminId/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.userIsInGroup), tryHandler(GroupController.getAdminId));
|
||||
GroupRouter.post('/rename/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.authorizeGroupOwner), tryHandler(GroupController.rename));
|
||||
GroupRouter.post('/transferOwnership/:groupId', tryHandler(auth.authenticate), tryHandler(existance.groupExists), tryHandler(auth.authorizeGroupOwner), tryHandler(GroupController.transferOwnership));
|
||||
export default GroupRouter;
|
||||
@@ -37,6 +37,14 @@ class GroupService {
|
||||
async getUsersInGroup(groupId) {
|
||||
return (await db.query("SELECT id FROM users WHERE $1 = ANY(groups)", [groupId])).rows.map((group) => group.id)
|
||||
}
|
||||
|
||||
async rename(groupId, newName) {
|
||||
await db.query("UPDATE groups SET name = $1 WHERE id = $2", [newName, groupId]).catch((e) => errorHandler(e, "groups"));;
|
||||
}
|
||||
|
||||
async transferOwnership(groupId, userId) {
|
||||
await db.query("UPDATE groups SET admin_id = $1 WHERE id = $2", [userId, groupId])
|
||||
}
|
||||
};
|
||||
|
||||
export default new GroupService();
|
||||
@@ -31,7 +31,11 @@ class UserService {
|
||||
|
||||
async joinGroup(userId, groupId) {
|
||||
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]);
|
||||
await db.query("UPDATE users SET groups = array_append(groups, $1::integer) WHERE ID = $2", [groupId, userId]);
|
||||
}
|
||||
|
||||
async leaveGroup(userId, groupId) {
|
||||
await db.query("UPDATE users SET groups = array_remove(groups, $1::integer) WHERE ID = $2", [groupId, userId]);
|
||||
}
|
||||
|
||||
async changeUsername(userId, username) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import clients from '../index.js';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
import config from '../../config.json' with {type: "json"};
|
||||
import log from './log.js';
|
||||
|
||||
const notify = (token, groupId, action, item, data) => {
|
||||
let login = jwt.decode(token, config.secret).login
|
||||
@@ -18,7 +19,8 @@ const notify = (token, groupId, action, item, data) => {
|
||||
if (client.currentGroup == groupId) {
|
||||
let userIdFromToken = jwt.decode(client.token, config.secret).login.id
|
||||
if (userIdCurrent == userIdFromToken) return;
|
||||
client.socket.send(payload)
|
||||
log.debug(`Sending user with ID ${userIdCurrent} packet "${JSON.stringify(payload)}"`)
|
||||
client.socket.send(JSON.stringify(payload))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user