Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "",
Expand Down
82 changes: 82 additions & 0 deletions src/module-3/controllers/groups.ts
Original file line number Diff line number Diff line change
@@ -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("Something wrong");
}
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;
37 changes: 37 additions & 0 deletions src/module-3/controllers/user-groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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();

/* Get user-groups list */

router.get("/", async (req, res) => {
try {
const userGroups = await UserGroupsService.findAll();
res.status(200).send(userGroups);
} catch (e) {
res.status(500).send(e.message);
}
});

/* Add user to any group by id*/

router.post(
"/",
validator.body(userGroupValidationSchema),
async (req, res) => {
try {
const body: AddUsersToGroupModel = req.body;
await UserGroupsService.addUsersToGroup(body.groupId, body.userIds);
res.redirect("/api/user-groups");
} catch (e) {
res.status(500).send(e.message);
}
}
);

export default router;
2 changes: 1 addition & 1 deletion src/module-3/controllers/users.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import express from "express";
import { createValidator } from "express-joi-validation";
import { UserModel } from "../types";
import * as UsersService from "../services/users";
import { UserModel } from "../types";
import { isNull } from "./utils";
import userValidationSchema from "./validation/users";

Expand Down
6 changes: 6 additions & 0 deletions src/module-3/controllers/validation/groups.ts
Original file line number Diff line number Diff line change
@@ -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()
});
6 changes: 6 additions & 0 deletions src/module-3/controllers/validation/user-groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import joi from "joi";

export default joi.object().keys({
userIds: joi.array().required(),
groupId: joi.string().required()
});
4 changes: 1 addition & 3 deletions src/module-3/controllers/validation/users.ts
Original file line number Diff line number Diff line change
@@ -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;
8 changes: 7 additions & 1 deletion src/module-3/data-access/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
});
8 changes: 7 additions & 1 deletion src/module-3/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +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";

Expand All @@ -13,6 +15,10 @@ 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);
app.use("/api/user-groups", userGroupsRouter);
})
.catch((err) => console.error(err))
);
20 changes: 20 additions & 0 deletions src/module-3/models/group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { DataTypes, Model, ModelCtor } from "sequelize";
import db from "../data-access";
import { GroupModel } from "../types";

const Group: ModelCtor<Model<GroupModel>> = db.define(
"groups",
{
name: {
type: DataTypes.STRING
},
permissions: {
type: DataTypes.ARRAY(DataTypes.CHAR)
}
},
{
timestamps: false
}
);

export default Group;
20 changes: 20 additions & 0 deletions src/module-3/models/user-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { DataTypes, Model, ModelCtor } from "sequelize";
import db from "../data-access";
import { UserGroupModel } from "../types";

const UserGroup: ModelCtor<Model<UserGroupModel>> = db.define(
"user-groups",
{
groupId: {
type: DataTypes.STRING
},
userId: {
type: DataTypes.STRING
}
},
{
timestamps: false
}
);

export default UserGroup;
85 changes: 85 additions & 0 deletions src/module-3/services/groups.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
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) =>
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 transaction = await sequelize.transaction();

try {
const group = await find(id);

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<GroupModel, GroupModel> | 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
});
};
10 changes: 10 additions & 0 deletions src/module-3/services/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { BaseUser, GroupModel, UserGroupModel } from "../types";

export type AddUsersToGroupModel = Omit<UserGroupModel, "userId"> & {
userIds: Array<UserGroupModel["userId"]>;
};

export interface RemoveUserGroupParams {
userId?: BaseUser["id"];
groupId?: GroupModel["id"];
}
Loading