From a4dd3549034bf122108da8e23b191b31a7a4f192 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Sun, 14 Nov 2021 00:56:21 +0300 Subject: [PATCH 1/6] module 4: prepare base realization --- package.json | 2 +- src/module-3/controllers/groups.ts | 82 +++++++++++++++++++ src/module-3/controllers/validation/groups.ts | 6 ++ src/module-3/controllers/validation/users.ts | 4 +- src/module-3/index.ts | 6 +- src/module-3/models/group.ts | 20 +++++ src/module-3/models/user-group.ts | 20 +++++ src/module-3/services/groups.ts | 72 ++++++++++++++++ src/module-3/services/utils.ts | 11 +++ src/module-3/types.ts | 31 ++++++- 10 files changed, 246 insertions(+), 8 deletions(-) create mode 100644 src/module-3/controllers/groups.ts create mode 100644 src/module-3/controllers/validation/groups.ts create mode 100644 src/module-3/models/group.ts create mode 100644 src/module-3/models/user-group.ts create mode 100644 src/module-3/services/groups.ts create mode 100644 src/module-3/services/utils.ts diff --git a/package.json b/package.json index c8fdb30..b4660f5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "module-3": "nodemon --exec babel-node ./src/module-3/index.ts --extensions .ts", + "module-4": "nodemon --exec babel-node ./src/module-3/index.ts --extensions .ts", "lint": "eslint . --ext .ts" }, "author": "", diff --git a/src/module-3/controllers/groups.ts b/src/module-3/controllers/groups.ts new file mode 100644 index 0000000..e5e44d0 --- /dev/null +++ b/src/module-3/controllers/groups.ts @@ -0,0 +1,82 @@ +import express from "express"; +import { createValidator } from "express-joi-validation"; +import * as GroupsService from "../services/groups"; +import { Errors, GroupModel } from "../types"; +import { isNull } from "./utils"; +import groupValidationSchema from "./validation/groups"; + +const validator = createValidator(); +const router = express.Router(); + +/* Get all groups */ + +router.get("/", async (req, res) => { + try { + const groups = await GroupsService.findAll(); + res.status(200).send(groups); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Find group by id */ + +router.get("/:id", async (req, res) => { + try { + const id = req.params.id; + const group = await GroupsService.find(id); + if (group) { + return res.status(200).send(group); + } + res.status(404).send("Group not found"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Create new group */ + +router.post("/", validator.body(groupValidationSchema), async (req, res) => { + try { + const body: GroupModel = req.body; + const isSuccess = await GroupsService.create(body); + if (!isSuccess) { + return res.status(400).send("Group with this name is already exists"); + } + res.redirect("/api/groups"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Delete group */ + +router.delete("/:id", async (req, res) => { + try { + const id = req.params.id; + const isSuccess = await GroupsService.remove(id); + if (isNull(isSuccess)) { + return res.status(404).send("Group with this name is not found"); + } + res.redirect("/api/groups"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +/* Update group */ + +router.put("/:id", validator.body(groupValidationSchema), async (req, res) => { + try { + const id = req.params.id; + const status = await GroupsService.update(id, req.body); + if ((status as Errors).type === "error") { + return res.status(404).send((status as Errors).message); + } + res.redirect("/api/groups"); + } catch (e) { + res.status(500).send(e.message); + } +}); + +export default router; diff --git a/src/module-3/controllers/validation/groups.ts b/src/module-3/controllers/validation/groups.ts new file mode 100644 index 0000000..dc8136c --- /dev/null +++ b/src/module-3/controllers/validation/groups.ts @@ -0,0 +1,6 @@ +import joi from "joi"; + +export default joi.object().keys({ + name: joi.string().alphanum().min(3).max(10).required(), + permissions: joi.array().required() +}); diff --git a/src/module-3/controllers/validation/users.ts b/src/module-3/controllers/validation/users.ts index 51527c8..0917992 100644 --- a/src/module-3/controllers/validation/users.ts +++ b/src/module-3/controllers/validation/users.ts @@ -1,9 +1,7 @@ import joi from "joi"; -const userValidationSchema = joi.object().keys({ +export default joi.object().keys({ login: joi.string().alphanum().min(3).max(10).required(), password: joi.string().alphanum().required(), age: joi.number().min(4).max(130).required() }); - -export default userValidationSchema; diff --git a/src/module-3/index.ts b/src/module-3/index.ts index 75b727d..343ff3d 100644 --- a/src/module-3/index.ts +++ b/src/module-3/index.ts @@ -1,4 +1,5 @@ import express from "express"; +import groupsRouter from "./controllers/groups"; import usersRouter from "./controllers/users"; import db from "./data-access"; @@ -13,6 +14,9 @@ app.listen(3000, () => ) ) .then(() => app.use(express.json())) - .then(() => app.use("/api/users", usersRouter)) + .then(() => { + app.use("/api/groups", groupsRouter); + app.use("/api/users", usersRouter); + }) .catch((err) => console.error(err)) ); diff --git a/src/module-3/models/group.ts b/src/module-3/models/group.ts new file mode 100644 index 0000000..6a66a99 --- /dev/null +++ b/src/module-3/models/group.ts @@ -0,0 +1,20 @@ +import { DataTypes, Model, ModelCtor } from "sequelize"; +import db from "../data-access"; +import { GroupModel } from "../types"; + +const Group: ModelCtor> = db.define( + "groups", + { + name: { + type: DataTypes.STRING + }, + permissions: { + type: DataTypes.ARRAY(DataTypes.CHAR) + } + }, + { + timestamps: false + } +); + +export default Group; diff --git a/src/module-3/models/user-group.ts b/src/module-3/models/user-group.ts new file mode 100644 index 0000000..315bd39 --- /dev/null +++ b/src/module-3/models/user-group.ts @@ -0,0 +1,20 @@ +import { DataTypes, Model, ModelCtor } from "sequelize"; +import db from "../data-access"; +import { UserGroupModel } from "../types"; + +const UserGroup: ModelCtor> = db.define( + "user-groups", + { + id: { + type: DataTypes.NUMBER + }, + role: { + type: DataTypes.STRING + } + }, + { + timestamps: false + } +); + +export default UserGroup; diff --git a/src/module-3/services/groups.ts b/src/module-3/services/groups.ts new file mode 100644 index 0000000..8ba87f7 --- /dev/null +++ b/src/module-3/services/groups.ts @@ -0,0 +1,72 @@ +import { Model } from "sequelize/types"; +import Group from "../models/group"; +import { Errors, GroupModel } from "../types"; +import { isEqualsObjects } from "./utils"; + +export const find = async (id: string) => + Group.findOne({ + where: { + id + } + }); + +export const findAll = async () => + Group.findAll({ + raw: true + }); + +export const create = async (model: GroupModel) => { + const { name } = model; + const group = await Group.findOne({ + where: { + name + } + }); + + if (group) { + return null; + } + + return Group.create({ + ...model + }); +}; + +export const remove = async (id: string) => { + const group = await find(id); + + if (!group) { + return null; + } + + group.destroy(); +}; + +export const update = async ( + id: string, + model: GroupModel +): Promise< + Model | Errors +> => { + const group = await find(id); + const { name, permissions } = model; + + if (!group) { + return { + type: "error", + message: "Group with this id not found" + }; + } + + if (isEqualsObjects(group.get(), model)) { + return { + type: "error", + message: "Input data is equal with exist data. Forbidden" + }; + } + + return group.update({ + name, + permissions + }); +}; diff --git a/src/module-3/services/utils.ts b/src/module-3/services/utils.ts new file mode 100644 index 0000000..028c64b --- /dev/null +++ b/src/module-3/services/utils.ts @@ -0,0 +1,11 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export const isEqualsObjects = (obj1: any, obj2: any) => { + // Delete useless ids here + /* eslint-disable @typescript-eslint/no-unused-vars */ + console.log(obj1, obj2); + const { id: id1, ...anotherDataObj1 } = obj1; + const { id: id2, ...anotherDataObj2 } = obj2; + /* eslint-enable */ + + return JSON.stringify(anotherDataObj1) === JSON.stringify(anotherDataObj2); +}; diff --git a/src/module-3/types.ts b/src/module-3/types.ts index 8364b99..a189bef 100644 --- a/src/module-3/types.ts +++ b/src/module-3/types.ts @@ -1,10 +1,35 @@ +export interface BaseUser { + id?: string; + isDeleted?: boolean; +} + +export interface BaseGroup { + id?: string; +} export interface UserModel extends BaseUser { login: string; password: string; age: number; } -export interface BaseUser { - id?: string; - isDeleted?: boolean; +export type Permissions = + | "READ" + | "WRITE" + | "DELETE" + | "SHARE" + | "UPLOAD_FILES"; + +export interface GroupModel extends BaseGroup { + name: string; + permissions: Array; +} + +export interface Errors { + type: string; + message: string; +} + +export interface UserGroupModel { + id: BaseUser["id"]; + role: GroupModel["name"]; } From c1acb34e11b4497720e69fdac87887cfbdfa8f9c Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Sun, 14 Nov 2021 01:43:42 +0300 Subject: [PATCH 2/6] some modifications --- src/module-3/models/user-group.ts | 6 +++--- src/module-3/services/user-groups.ts | 29 ++++++++++++++++++++++++++++ src/module-3/types.ts | 4 ++-- 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/module-3/services/user-groups.ts diff --git a/src/module-3/models/user-group.ts b/src/module-3/models/user-group.ts index 315bd39..d39f5ec 100644 --- a/src/module-3/models/user-group.ts +++ b/src/module-3/models/user-group.ts @@ -5,11 +5,11 @@ import { UserGroupModel } from "../types"; const UserGroup: ModelCtor> = db.define( "user-groups", { - id: { + groupId: { type: DataTypes.NUMBER }, - role: { - type: DataTypes.STRING + userId: { + type: DataTypes.NUMBER } }, { diff --git a/src/module-3/services/user-groups.ts b/src/module-3/services/user-groups.ts new file mode 100644 index 0000000..da22c85 --- /dev/null +++ b/src/module-3/services/user-groups.ts @@ -0,0 +1,29 @@ +import sequelize from "../data-access"; +import UserGroup from "../models/user-group"; +import { UserGroupModel } from "../types"; + +export const getUserGroup = async (userId: string) => + UserGroup.findOne({ + where: { + userId + } + }); + +export const addUsersToGroup = async ( + groupId: UserGroupModel["groupId"], + userIds: Array +) => { + const transaction = await sequelize.transaction(); + + // TODO: continue here... +}; + +// export const remove = async (id: string) => { +// const group = await find(id); + +// if (!group) { +// return null; +// } + +// group.destroy(); +// }; diff --git a/src/module-3/types.ts b/src/module-3/types.ts index a189bef..188aed8 100644 --- a/src/module-3/types.ts +++ b/src/module-3/types.ts @@ -30,6 +30,6 @@ export interface Errors { } export interface UserGroupModel { - id: BaseUser["id"]; - role: GroupModel["name"]; + userId: BaseUser["id"]; + groupId: GroupModel["id"]; } From 89dff2146ad7be2b84b63c55f520fbe51ac40caa Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Tue, 16 Nov 2021 16:56:36 +0300 Subject: [PATCH 3/6] minor updating of the functionality --- src/module-3/controllers/users.ts | 19 +++++++++++- .../controllers/validation/user-groups.ts | 6 ++++ src/module-3/services/types.ts | 5 ++++ src/module-3/services/user-groups.ts | 29 ++++++++++++++++++- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 src/module-3/controllers/validation/user-groups.ts create mode 100644 src/module-3/services/types.ts diff --git a/src/module-3/controllers/users.ts b/src/module-3/controllers/users.ts index a64a098..d299e5e 100644 --- a/src/module-3/controllers/users.ts +++ b/src/module-3/controllers/users.ts @@ -1,8 +1,11 @@ import express from "express"; import { createValidator } from "express-joi-validation"; -import { UserModel } from "../types"; +import { AddUsersToGroupModel } from "../services/types"; +import * as UsersGroupsService from "../services/user-groups"; import * as UsersService from "../services/users"; +import { UserModel } from "../types"; import { isNull } from "./utils"; +import userGroupValidationSchema from "./validation/user-groups"; import userValidationSchema from "./validation/users"; const validator = createValidator(); @@ -82,4 +85,18 @@ router.put("/:id", validator.body(userValidationSchema), async (req, res) => { } }); +router.post( + "/add", + validator.body(userGroupValidationSchema), + async (req, res) => { + try { + const body: AddUsersToGroupModel = req.body; + await UsersGroupsService.addUsersToGroup(body.groupId, body.userIds); + // res.redirect("/api/users"); + } catch (e) { + res.status(500).send(e.message); + } + } +); + export default router; diff --git a/src/module-3/controllers/validation/user-groups.ts b/src/module-3/controllers/validation/user-groups.ts new file mode 100644 index 0000000..b8cbfc4 --- /dev/null +++ b/src/module-3/controllers/validation/user-groups.ts @@ -0,0 +1,6 @@ +import joi from "joi"; + +export default joi.object().keys({ + userIds: joi.array().required(), + groupId: joi.string().required() +}); diff --git a/src/module-3/services/types.ts b/src/module-3/services/types.ts new file mode 100644 index 0000000..d876597 --- /dev/null +++ b/src/module-3/services/types.ts @@ -0,0 +1,5 @@ +import { UserGroupModel } from "../types"; + +export type AddUsersToGroupModel = Omit & { + userIds: Array; +}; diff --git a/src/module-3/services/user-groups.ts b/src/module-3/services/user-groups.ts index da22c85..9d4e55f 100644 --- a/src/module-3/services/user-groups.ts +++ b/src/module-3/services/user-groups.ts @@ -1,6 +1,8 @@ import sequelize from "../data-access"; import UserGroup from "../models/user-group"; import { UserGroupModel } from "../types"; +import { find as findGroupById } from "./groups"; +import { find as findUserById } from "./users"; export const getUserGroup = async (userId: string) => UserGroup.findOne({ @@ -14,8 +16,33 @@ export const addUsersToGroup = async ( userIds: Array ) => { const transaction = await sequelize.transaction(); + const group = findGroupById(groupId); - // TODO: continue here... + try { + userIds?.forEach(async (id) => { + const user = findUserById(id); + + if (!user || !group) { + return undefined; + } + + UserGroup.create( + { + userId: id, + groupId + }, + { transaction } + ); + + console.log("success"); + }); + transaction.afterCommit(() => { + // return Promise.resolve(); + }); + } catch (error) { + console.log("error"); + await transaction.rollback(); + } }; // export const remove = async (id: string) => { From 36edec7d97196faf0883dbb2bca0b9d05c3735c8 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Wed, 17 Nov 2021 00:23:41 +0300 Subject: [PATCH 4/6] implement adding a user to user group --- src/module-3/controllers/user-groups.ts | 50 ++++++++++++++++++++++ src/module-3/controllers/users.ts | 17 -------- src/module-3/index.ts | 2 + src/module-3/services/user-groups.ts | 55 ++++++++++++++----------- src/module-3/services/users.ts | 2 +- 5 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 src/module-3/controllers/user-groups.ts diff --git a/src/module-3/controllers/user-groups.ts b/src/module-3/controllers/user-groups.ts new file mode 100644 index 0000000..1aa66e3 --- /dev/null +++ b/src/module-3/controllers/user-groups.ts @@ -0,0 +1,50 @@ +import express from "express"; +import { createValidator } from "express-joi-validation"; +import { AddUsersToGroupModel } from "../services/types"; +import * as UserGroupsService from "../services/user-groups"; +import userGroupValidationSchema from "./validation/user-groups"; + +const validator = createValidator(); +const router = express.Router(); + +router.get("/", async (req, res) => { + try { + const userGroups = await UserGroupsService.findAll(); + res.status(200).send(userGroups); + } catch (e) { + res.status(500).send(e.message); + } +}); + +router.post( + "/", + validator.body(userGroupValidationSchema), + async (req, res) => { + try { + const body: AddUsersToGroupModel = req.body; + await UserGroupsService.addUsersToGroup(body.groupId, body.userIds); + // const isSuccess = await GroupsService.create(body); + // if (!isSuccess) { + // return res.status(400).send("Group with this name is already exists"); + // } + res.redirect("/api/user-groups"); + } catch (e) { + res.status(500).send(e.message); + } + } +); + +router.delete("/:id", async (req, res) => { + // try { + // const id = req.params.id; + // const isSuccess = await GroupsService.remove(id); + // if (isNull(isSuccess)) { + // return res.status(404).send("Group with this name is not found"); + // } + // res.redirect("/api/groups"); + // } catch (e) { + // res.status(500).send(e.message); + // } +}); + +export default router; diff --git a/src/module-3/controllers/users.ts b/src/module-3/controllers/users.ts index d299e5e..f9b8b9c 100644 --- a/src/module-3/controllers/users.ts +++ b/src/module-3/controllers/users.ts @@ -1,11 +1,8 @@ import express from "express"; import { createValidator } from "express-joi-validation"; -import { AddUsersToGroupModel } from "../services/types"; -import * as UsersGroupsService from "../services/user-groups"; import * as UsersService from "../services/users"; import { UserModel } from "../types"; import { isNull } from "./utils"; -import userGroupValidationSchema from "./validation/user-groups"; import userValidationSchema from "./validation/users"; const validator = createValidator(); @@ -85,18 +82,4 @@ router.put("/:id", validator.body(userValidationSchema), async (req, res) => { } }); -router.post( - "/add", - validator.body(userGroupValidationSchema), - async (req, res) => { - try { - const body: AddUsersToGroupModel = req.body; - await UsersGroupsService.addUsersToGroup(body.groupId, body.userIds); - // res.redirect("/api/users"); - } catch (e) { - res.status(500).send(e.message); - } - } -); - export default router; diff --git a/src/module-3/index.ts b/src/module-3/index.ts index 343ff3d..c79e912 100644 --- a/src/module-3/index.ts +++ b/src/module-3/index.ts @@ -1,5 +1,6 @@ import express from "express"; import groupsRouter from "./controllers/groups"; +import userGroupsRouter from "./controllers/user-groups"; import usersRouter from "./controllers/users"; import db from "./data-access"; @@ -17,6 +18,7 @@ app.listen(3000, () => .then(() => { app.use("/api/groups", groupsRouter); app.use("/api/users", usersRouter); + app.use("/api/user-groups", userGroupsRouter); }) .catch((err) => console.error(err)) ); diff --git a/src/module-3/services/user-groups.ts b/src/module-3/services/user-groups.ts index 9d4e55f..1278695 100644 --- a/src/module-3/services/user-groups.ts +++ b/src/module-3/services/user-groups.ts @@ -4,7 +4,9 @@ import { UserGroupModel } from "../types"; import { find as findGroupById } from "./groups"; import { find as findUserById } from "./users"; -export const getUserGroup = async (userId: string) => +export const findAll = async () => UserGroup.findAll(); + +export const findUserGroup = async (userId: string) => UserGroup.findOne({ where: { userId @@ -15,32 +17,39 @@ export const addUsersToGroup = async ( groupId: UserGroupModel["groupId"], userIds: Array ) => { - const transaction = await sequelize.transaction(); const group = findGroupById(groupId); + const transaction = await sequelize.transaction(); try { - userIds?.forEach(async (id) => { - const user = findUserById(id); - - if (!user || !group) { - return undefined; - } - - UserGroup.create( - { - userId: id, - groupId - }, - { transaction } - ); - - console.log("success"); - }); - transaction.afterCommit(() => { - // return Promise.resolve(); - }); + return sequelize + .transaction(async (t) => { + for (const userId of userIds) { + const user = await findUserById(userId); + const isUserGroupExisted = await UserGroup.findOne({ + where: { + groupId, + userId + } + }); + + if (!user || !group || isUserGroupExisted) { + return; + } + + await UserGroup.create( + { + userId, + groupId + }, + { transaction: t } + ); + } + }) + .then(() => { + return Promise.resolve(); + }); } catch (error) { - console.log("error"); + console.error(error); await transaction.rollback(); } }; diff --git a/src/module-3/services/users.ts b/src/module-3/services/users.ts index 6637d8f..0af5301 100644 --- a/src/module-3/services/users.ts +++ b/src/module-3/services/users.ts @@ -1,5 +1,5 @@ -import { UserModel } from "../types"; import User from "../models/user"; +import { UserModel } from "../types"; export const getUsersList = async () => User.findAll({ From 787542e934375b207b7b5f8c02c89fa11fd0d34f Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Wed, 17 Nov 2021 02:15:14 +0300 Subject: [PATCH 5/6] implement multiple delete from users and users-groups table's data using transactions --- src/module-3/controllers/user-groups.ts | 21 +++------------- src/module-3/data-access/index.ts | 8 +++++- src/module-3/models/user-group.ts | 4 +-- src/module-3/services/types.ts | 7 +++++- src/module-3/services/user-groups.ts | 33 +++++++++++++++++++------ src/module-3/services/users.ts | 29 ++++++++++++++++------ src/module-3/types.ts | 4 +-- 7 files changed, 69 insertions(+), 37 deletions(-) diff --git a/src/module-3/controllers/user-groups.ts b/src/module-3/controllers/user-groups.ts index 1aa66e3..e83b280 100644 --- a/src/module-3/controllers/user-groups.ts +++ b/src/module-3/controllers/user-groups.ts @@ -7,6 +7,8 @@ import userGroupValidationSchema from "./validation/user-groups"; const validator = createValidator(); const router = express.Router(); +/* Get user-groups list */ + router.get("/", async (req, res) => { try { const userGroups = await UserGroupsService.findAll(); @@ -16,6 +18,8 @@ router.get("/", async (req, res) => { } }); +/* Add user to any group by id*/ + router.post( "/", validator.body(userGroupValidationSchema), @@ -23,10 +27,6 @@ router.post( try { const body: AddUsersToGroupModel = req.body; await UserGroupsService.addUsersToGroup(body.groupId, body.userIds); - // const isSuccess = await GroupsService.create(body); - // if (!isSuccess) { - // return res.status(400).send("Group with this name is already exists"); - // } res.redirect("/api/user-groups"); } catch (e) { res.status(500).send(e.message); @@ -34,17 +34,4 @@ router.post( } ); -router.delete("/:id", async (req, res) => { - // try { - // const id = req.params.id; - // const isSuccess = await GroupsService.remove(id); - // if (isNull(isSuccess)) { - // return res.status(404).send("Group with this name is not found"); - // } - // res.redirect("/api/groups"); - // } catch (e) { - // res.status(500).send(e.message); - // } -}); - export default router; diff --git a/src/module-3/data-access/index.ts b/src/module-3/data-access/index.ts index daaef92..0271528 100644 --- a/src/module-3/data-access/index.ts +++ b/src/module-3/data-access/index.ts @@ -9,4 +9,10 @@ if (!process.env.DB_URL) { const DB_URL = process.env.DB_URL; -export default new Sequelize(DB_URL); +export default new Sequelize(DB_URL, { + pool: { + max: 5, + min: 0, + idle: 10000 + } +}); diff --git a/src/module-3/models/user-group.ts b/src/module-3/models/user-group.ts index d39f5ec..aa73e5f 100644 --- a/src/module-3/models/user-group.ts +++ b/src/module-3/models/user-group.ts @@ -6,10 +6,10 @@ const UserGroup: ModelCtor> = db.define( "user-groups", { groupId: { - type: DataTypes.NUMBER + type: DataTypes.STRING }, userId: { - type: DataTypes.NUMBER + type: DataTypes.STRING } }, { diff --git a/src/module-3/services/types.ts b/src/module-3/services/types.ts index d876597..3179ba9 100644 --- a/src/module-3/services/types.ts +++ b/src/module-3/services/types.ts @@ -1,5 +1,10 @@ -import { UserGroupModel } from "../types"; +import { BaseUser, GroupModel, UserGroupModel } from "../types"; export type AddUsersToGroupModel = Omit & { userIds: Array; }; + +export interface RemoveUserGroupParams { + userId?: BaseUser["id"]; + groupId?: GroupModel["id"]; +} diff --git a/src/module-3/services/user-groups.ts b/src/module-3/services/user-groups.ts index 1278695..bcd8dcf 100644 --- a/src/module-3/services/user-groups.ts +++ b/src/module-3/services/user-groups.ts @@ -1,7 +1,9 @@ +import { Transaction } from "sequelize/types"; import sequelize from "../data-access"; import UserGroup from "../models/user-group"; import { UserGroupModel } from "../types"; import { find as findGroupById } from "./groups"; +import { RemoveUserGroupParams } from "./types"; import { find as findUserById } from "./users"; export const findAll = async () => UserGroup.findAll(); @@ -54,12 +56,29 @@ export const addUsersToGroup = async ( } }; -// export const remove = async (id: string) => { -// const group = await find(id); +export const remove = async ( + transaction: Transaction, + params: RemoveUserGroupParams +) => { + const { userId, groupId } = params ?? {}; + const id = userId ?? groupId; + + if (!id) { + return; + } + + const userGroups = await UserGroup.findAll({ + where: { + ...(userId ? { userId: id } : undefined), + ...(groupId ? { groupId: id } : undefined) + } + }); -// if (!group) { -// return null; -// } + if (!userGroups.length) { + return; + } -// group.destroy(); -// }; + for (const userGroup of userGroups) { + await userGroup.destroy({ transaction }); + } +}; diff --git a/src/module-3/services/users.ts b/src/module-3/services/users.ts index 0af5301..2787b49 100644 --- a/src/module-3/services/users.ts +++ b/src/module-3/services/users.ts @@ -1,5 +1,7 @@ +import sequelize from "../data-access"; import User from "../models/user"; import { UserModel } from "../types"; +import * as UserGroupsService from "./user-groups"; export const getUsersList = async () => User.findAll({ @@ -50,15 +52,28 @@ export const create = async (model: UserModel) => { }; export const remove = async (id: string) => { - const user = await find(id); + const transaction = await sequelize.transaction(); - if (!user) { - return null; - } + try { + const user = await find(id); + if (!user) { + transaction.rollback(); + return null; + } - return user.update({ - isDeleted: true - }); + await UserGroupsService.remove(transaction, { + userId: id + }); + + await transaction.commit(); + + return user.update({ + isDeleted: true + }); + } catch (error) { + console.error(error); + transaction.rollback(); + } }; export const update = async (id: string, model: UserModel) => { diff --git a/src/module-3/types.ts b/src/module-3/types.ts index 188aed8..0a22483 100644 --- a/src/module-3/types.ts +++ b/src/module-3/types.ts @@ -30,6 +30,6 @@ export interface Errors { } export interface UserGroupModel { - userId: BaseUser["id"]; - groupId: GroupModel["id"]; + userId: string; + groupId: string; } From a24cfb41bfdc2ea321ecfc0e4a377f6b739d7cd8 Mon Sep 17 00:00:00 2001 From: Yuri Lysov Date: Wed, 17 Nov 2021 02:31:03 +0300 Subject: [PATCH 6/6] implement multiple delete from groups and users-groups table's data using transactions; minor fixes --- src/module-3/controllers/groups.ts | 2 +- src/module-3/services/groups.ts | 29 ++++++++++++++++++++-------- src/module-3/services/user-groups.ts | 6 ++++-- src/module-3/services/users.ts | 12 ++++++++---- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/src/module-3/controllers/groups.ts b/src/module-3/controllers/groups.ts index e5e44d0..29ce3e8 100644 --- a/src/module-3/controllers/groups.ts +++ b/src/module-3/controllers/groups.ts @@ -56,7 +56,7 @@ router.delete("/:id", async (req, res) => { const id = req.params.id; const isSuccess = await GroupsService.remove(id); if (isNull(isSuccess)) { - return res.status(404).send("Group with this name is not found"); + return res.status(404).send("Something wrong"); } res.redirect("/api/groups"); } catch (e) { diff --git a/src/module-3/services/groups.ts b/src/module-3/services/groups.ts index 8ba87f7..5dd1bdf 100644 --- a/src/module-3/services/groups.ts +++ b/src/module-3/services/groups.ts @@ -1,6 +1,8 @@ import { Model } from "sequelize/types"; +import sequelize from "../data-access"; import Group from "../models/group"; import { Errors, GroupModel } from "../types"; +import * as UserGroupsService from "./user-groups"; import { isEqualsObjects } from "./utils"; export const find = async (id: string) => @@ -33,21 +35,32 @@ export const create = async (model: GroupModel) => { }; export const remove = async (id: string) => { - const group = await find(id); + const transaction = await sequelize.transaction(); - if (!group) { - return null; - } + try { + const group = await find(id); - group.destroy(); + if (!group) { + transaction.rollback(); + return null; + } + + await UserGroupsService.remove(transaction, { + groupId: id + }); + + await group.destroy({ transaction }); + await transaction.commit(); + } catch (error) { + console.error(error); + transaction.rollback(); + } }; export const update = async ( id: string, model: GroupModel -): Promise< - Model | Errors -> => { +): Promise | Errors> => { const group = await find(id); const { name, permissions } = model; diff --git a/src/module-3/services/user-groups.ts b/src/module-3/services/user-groups.ts index bcd8dcf..3174849 100644 --- a/src/module-3/services/user-groups.ts +++ b/src/module-3/services/user-groups.ts @@ -64,7 +64,7 @@ export const remove = async ( const id = userId ?? groupId; if (!id) { - return; + return Promise.reject(); } const userGroups = await UserGroup.findAll({ @@ -75,10 +75,12 @@ export const remove = async ( }); if (!userGroups.length) { - return; + return Promise.reject(); } for (const userGroup of userGroups) { await userGroup.destroy({ transaction }); } + + return Promise.resolve(); }; diff --git a/src/module-3/services/users.ts b/src/module-3/services/users.ts index 2787b49..b89ff60 100644 --- a/src/module-3/services/users.ts +++ b/src/module-3/services/users.ts @@ -65,11 +65,15 @@ export const remove = async (id: string) => { userId: id }); + await user.update( + { + isDeleted: true + }, + { + transaction + } + ); await transaction.commit(); - - return user.update({ - isDeleted: true - }); } catch (error) { console.error(error); transaction.rollback();