From 5476b11fb586456bc77269cd93a700aa903af186 Mon Sep 17 00:00:00 2001 From: dyakonovr Date: Tue, 26 Mar 2024 21:03:55 +0400 Subject: [PATCH] =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B0=D0=BB=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D1=83=20=D0=BD=D0=B0=D0=B4=20=D1=84=D1=83?= =?UTF-8?q?=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D1=81=D1=82=D1=8C=D1=8E=20Message,=20=D0=BC=D0=B5=D0=BB?= =?UTF-8?q?=D0=BA=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/src/App.tsx | 3 + client/src/components/Message/Create.tsx | 26 ++++ client/src/components/Message/Edit.tsx | 27 ++++ client/src/components/Message/List.tsx | 17 +++ client/src/components/Thread/Create.tsx | 6 +- .../controllers/message/message.controller.ts | 144 ++++++++++++++++++ server/controllers/message/message.dto.ts | 5 + .../controllers/section/section.controller.ts | 22 ++- server/controllers/user/user.controller.ts | 23 +-- server/db.ts | 3 +- server/models/message.model.ts | 61 ++++++++ server/models/section.model.ts | 8 +- server/models/thread.model.ts | 11 +- server/models/user.model.ts | 12 +- server/routes/routes.ts | 2 + server/routes/routes/message.router.ts | 14 ++ server/routes/routes/user.router.ts | 1 + server/tsconfig.json | 2 +- 18 files changed, 362 insertions(+), 25 deletions(-) create mode 100644 client/src/components/Message/Create.tsx create mode 100644 client/src/components/Message/Edit.tsx create mode 100644 client/src/components/Message/List.tsx create mode 100644 server/controllers/message/message.controller.ts create mode 100644 server/controllers/message/message.dto.ts create mode 100644 server/models/message.model.ts create mode 100644 server/routes/routes/message.router.ts diff --git a/client/src/App.tsx b/client/src/App.tsx index c414e9b..10dd743 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -11,6 +11,8 @@ import SectionCreate from "./components/Section/Create"; import SectionEdit from "./components/Section/Edit"; import ThreadsList from "./components/Thread/List"; import ThreadCreate from "./components/Thread/Create"; +import MessagesList from "./components/Message/List"; +import MessageCreate from "./components/Message/Create"; function App() { return ( @@ -39,6 +41,7 @@ function App() { create={} // edit={} /> + } create={} /> ); } diff --git a/client/src/components/Message/Create.tsx b/client/src/components/Message/Create.tsx new file mode 100644 index 0000000..dd4754b --- /dev/null +++ b/client/src/components/Message/Create.tsx @@ -0,0 +1,26 @@ +import { + Create, + ReferenceInput, + SelectInput, + SimpleForm, + TextInput, + required +} from "react-admin"; + +function MessageCreate() { + return ( + + + + + + + + + + + + ); +} + +export default MessageCreate; diff --git a/client/src/components/Message/Edit.tsx b/client/src/components/Message/Edit.tsx new file mode 100644 index 0000000..7f51eb3 --- /dev/null +++ b/client/src/components/Message/Edit.tsx @@ -0,0 +1,27 @@ +import { + Edit, + ReferenceInput, + SelectInput, + SimpleForm, + TextInput, + required, +} from "react-admin"; +import Title from "../Title"; + +function SectionEdit() { + return ( + } actions={false}> + + + + + + + + + + + ); +} + +export default SectionEdit; diff --git a/client/src/components/Message/List.tsx b/client/src/components/Message/List.tsx new file mode 100644 index 0000000..9c4bd5d --- /dev/null +++ b/client/src/components/Message/List.tsx @@ -0,0 +1,17 @@ +import { List, Datagrid, TextField, EditButton } from "react-admin"; + +function MessagesList() { + return ( + + + + + + + + + + ); +}; + +export default MessagesList; \ No newline at end of file diff --git a/client/src/components/Thread/Create.tsx b/client/src/components/Thread/Create.tsx index e00d780..5a218f3 100644 --- a/client/src/components/Thread/Create.tsx +++ b/client/src/components/Thread/Create.tsx @@ -12,7 +12,11 @@ function ThreadCreate() { - + diff --git a/server/controllers/message/message.controller.ts b/server/controllers/message/message.controller.ts new file mode 100644 index 0000000..9705491 --- /dev/null +++ b/server/controllers/message/message.controller.ts @@ -0,0 +1,144 @@ +import { ApiErrorHandler } from "../../error/api-error.handler"; +import Message from "../../models/message.model"; +import type { IMessageDto } from "./message.dto"; +import type { Order } from "sequelize"; +import type { NextFunction, Request, Response } from "express"; +import type { + FilterQueryParamType, + RangeQueryParamType, + SortQueryParamType +} from "../query-param.types"; + +class MessageController { + getAll = async (req: Request, res: Response, next: NextFunction) => { + try { + const range: RangeQueryParamType = req.query.range + ? JSON.parse(req.query.range.toString()) + : [0, 10]; + const sort: SortQueryParamType = req.query.sort + ? JSON.parse(req.query.sort.toString()) + : ["id", "ASC"]; + + const Messages = await Message.findAndCountAll({ + offset: range[0], + limit: range[1] - range[0] + 1, + order: [sort] as Order + }); + + return res.json({ data: Messages.rows, total: Messages.count }); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; + + getMany = async ( + req: Request, + res: Response<{ data: Message[] }>, + next: NextFunction + ) => { + try { + const filter: FilterQueryParamType = req.query.filter + ? JSON.parse(req.query.filter.toString()) + : { ids: [] }; + + const messages = await Message.findAll({ + where: { id: filter.ids as number[] } + }); + return res.json({ data: messages }); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; + + create = async ( + req: Request, + res: Response, + next: NextFunction + ) => { + try { + const { text, user_id, thread_id } = req.body; + const message = await Message.create({ text, user_id, thread_id }); + return res.json(message); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; + + getById = async ( + req: Request<{ id: number }>, + res: Response, + next: NextFunction + ) => { + try { + const { id } = req.params; + const message = await Message.findByPk(id); + if (!message) return next(ApiErrorHandler.notFound("Такой роли не найдено")); + + return res.json(message); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; + + update = async ( + req: Request<{ id: number }, object, IMessageDto>, + res: Response, + next: NextFunction + ) => { + try { + const { id } = req.params; + const { text, user_id, thread_id } = req.body; + + const message = await Message.findByPk(id); + if (!message) return next(ApiErrorHandler.internal("Такой роли не найдено")); + + message.text = text; + message.user_id = user_id; + message.thread_id = thread_id; + await message.save(); + + return res.json(message); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; + + delete = async ( + req: Request<{ id: number }>, + res: Response, + next: NextFunction + ) => { + try { + const { id } = req.params; + const message = await Message.findByPk(id); + if (!message) return next(ApiErrorHandler.internal("Такой роли не найдено")); + + await message.destroy(); + + return res.json(message); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; + + deleteMany = async ( + req: Request, + res: Response<{ data: Message[] }>, + next: NextFunction + ) => { + try { + const filter: FilterQueryParamType = req.query.filter + ? JSON.parse(req.query.filter.toString()) + : {}; + const messages = await Message.findAll({ where: filter }); + + Message.destroy({ where: filter }); + + return res.json({ data: messages }); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; +} + +export default new MessageController(); diff --git a/server/controllers/message/message.dto.ts b/server/controllers/message/message.dto.ts new file mode 100644 index 0000000..8716f56 --- /dev/null +++ b/server/controllers/message/message.dto.ts @@ -0,0 +1,5 @@ +export interface IMessageDto { + text: string; + user_id: number; + thread_id: number; +} \ No newline at end of file diff --git a/server/controllers/section/section.controller.ts b/server/controllers/section/section.controller.ts index f33e154..f5cec5a 100644 --- a/server/controllers/section/section.controller.ts +++ b/server/controllers/section/section.controller.ts @@ -16,8 +16,8 @@ class SectionController { // чтобы не возвращать его в списке const filter: FilterQueryParamType = req.query.filter ? JSON.parse(req.query.filter.toString()) - : { id: -1 }; - + : {}; + const range: RangeQueryParamType = req.query.range ? JSON.parse(req.query.range.toString()) : [0, 10]; @@ -36,6 +36,24 @@ class SectionController { } }); + // if (filter.onlyEndSections) { + // console.log('!'); + // const endSections = sections.rows.filter(async (section) => { + // const innerSections = await Section.findAll({ + // where: { + // root_section_id: section.id + // } + // }); + + // console.log(section.dataValues.name, innerSections.length); + // return innerSections.length === 0; + // }); + + // console.log(endSections); + + // return res.json({ data: endSections, total: endSections.length }); + // } + return res.json({ data: sections.rows, total: sections.count }); } catch (error) { next(ApiErrorHandler.internal((error as Error).message)); diff --git a/server/controllers/user/user.controller.ts b/server/controllers/user/user.controller.ts index 47a3a1b..fcbcfd1 100644 --- a/server/controllers/user/user.controller.ts +++ b/server/controllers/user/user.controller.ts @@ -38,15 +38,20 @@ class UserController { } }; - // getMany = async (req, res, next) => { - // try { - // const filter = JSON.parse(req.query.filter); - // const users = await User.findAll({ attributes: { exclude: ["slug"] }, where: { id: filter.ids } }); - // return res.json({ data: users }); - // } catch (error) { - // next(ApiErrorHandler.internal(error.message)); - // } - // } + getMany = async (req: Request, res: Response<{ data: User[] }>, next: NextFunction) => { + try { + const filter: FilterQueryParamType = req.query.filter + ? JSON.parse(req.query.filter.toString()) + : { ids: [] }; + + const users = await User.findAll({ + where: { id: filter.ids as number[] } + }); + return res.json({ data: users }); + } catch (error) { + next(ApiErrorHandler.internal((error as Error).message)); + } + }; create = async ( req: Request, diff --git a/server/db.ts b/server/db.ts index 719c65a..a0004d0 100644 --- a/server/db.ts +++ b/server/db.ts @@ -4,6 +4,7 @@ import Role from "./models/role.model"; import User from "./models/user.model"; import Section from "./models/section.model"; import Thread from "./models/thread.model"; +import Message from "./models/message.model"; dotenv.config(); @@ -14,5 +15,5 @@ export const sequelize = new Sequelize({ password: process.env.DB_PASSWORD, host: process.env.DB_HOST, port: process.env.DB_PORT, - models: [Role, User, Section, Thread] + models: [Role, User, Section, Thread, Message] }); diff --git a/server/models/message.model.ts b/server/models/message.model.ts new file mode 100644 index 0000000..3713155 --- /dev/null +++ b/server/models/message.model.ts @@ -0,0 +1,61 @@ +import { + Table, + Column, + Model, + DataType, + Length, + UpdatedAt, + CreatedAt, + ForeignKey, + BelongsTo +} from "sequelize-typescript"; +import User from "./user.model"; +import Thread from "./thread.model"; + +@Table({ + timestamps: true, + tableName: "messages", + modelName: "Message" +}) +export default class Message extends Model { + @Column({ + primaryKey: true, + autoIncrement: true, + type: DataType.INTEGER + }) + declare id: number; + + @Length({ min: 1 }) + @Column({ + allowNull: false, + defaultValue: "Unknown", + type: DataType.STRING + }) + declare text: string; + + @CreatedAt + declare created_at: Date; + + @UpdatedAt + declare updated_at: Date; + + @ForeignKey(() => User) + @Column({ + allowNull: false, + type: DataType.INTEGER + }) + declare user_id: number; + + @BelongsTo(() => User) + declare user: User; + + @ForeignKey(() => Thread) + @Column({ + allowNull: false, + type: DataType.INTEGER + }) + declare thread_id: number; + + @BelongsTo(() => Thread) + declare thread: Thread; +} diff --git a/server/models/section.model.ts b/server/models/section.model.ts index f8ad71f..a4a737b 100644 --- a/server/models/section.model.ts +++ b/server/models/section.model.ts @@ -44,12 +44,12 @@ export default class Section extends Model { }) declare root_section_id: number | null; - @BelongsTo(() => Section, "root_section_id") + @BelongsTo(() => Section) declare root_section: Section; - @HasMany(() => Section, "root_section_id") + @HasMany(() => Section) declare inner_sections: Section[]; - // @HasMany(() => Thread, "section_id") - // declare threads: Thread[]; + @HasMany(() => Thread) + declare threads: Thread[]; } diff --git a/server/models/thread.model.ts b/server/models/thread.model.ts index 6f50f57..649f7fb 100644 --- a/server/models/thread.model.ts +++ b/server/models/thread.model.ts @@ -7,10 +7,12 @@ import { UpdatedAt, CreatedAt, ForeignKey, - BelongsTo + BelongsTo, + HasMany } from "sequelize-typescript"; import Section from "./section.model"; import User from "./user.model"; +import Message from "./message.model"; @Table({ tableName: "threads", @@ -45,7 +47,7 @@ export default class Thread extends Model { }) declare section_id: number; - @BelongsTo(() => Section, "section_id") + @BelongsTo(() => Section) declare section: Section; @ForeignKey(() => User) @@ -55,6 +57,9 @@ export default class Thread extends Model { }) declare creator_id: number | null; - @BelongsTo(() => User, "creator_id") + @BelongsTo(() => User) declare creator: User; + + @HasMany(() => Message) + declare messages: Message[]; } diff --git a/server/models/user.model.ts b/server/models/user.model.ts index d6e50ca..e26f568 100644 --- a/server/models/user.model.ts +++ b/server/models/user.model.ts @@ -8,10 +8,11 @@ import { UpdatedAt, ForeignKey, BelongsTo, - HasMany + HasMany, } from "sequelize-typescript"; import Role from "./role.model"; import Thread from "./thread.model"; +import Message from "./message.model"; @Table({ timestamps: true, @@ -69,9 +70,12 @@ export default class User extends Model { }) declare role_id: number; - @BelongsTo(() => Role, "role_id") + @BelongsTo(() => Role) declare role: Role; - // @HasMany(() => Thread, "thread_id") - // declare threads: Thread[]; + @HasMany(() => Thread) + declare threads: Thread[]; + + @HasMany(() => Message) + declare messages: Message[]; } diff --git a/server/routes/routes.ts b/server/routes/routes.ts index 5e4b37b..73cc318 100644 --- a/server/routes/routes.ts +++ b/server/routes/routes.ts @@ -3,6 +3,7 @@ import roleRouter from "./routes/role.router"; import userRouter from "./routes/user.router"; import sectionRouter from "./routes/section.router"; import threadRouter from "./routes/thread.router"; +import messageRouter from "./routes/message.router"; export const router = Router(); @@ -10,3 +11,4 @@ router.use("/roles", roleRouter); router.use("/users", userRouter); router.use("/sections", sectionRouter); router.use("/threads", threadRouter); +router.use("/messages", messageRouter); diff --git a/server/routes/routes/message.router.ts b/server/routes/routes/message.router.ts new file mode 100644 index 0000000..3c50181 --- /dev/null +++ b/server/routes/routes/message.router.ts @@ -0,0 +1,14 @@ +import { Router } from "express"; +import MessageController from "../../controllers/message/message.controller"; + +const messageRouter = Router(); + +messageRouter.post("/", MessageController.create); +messageRouter.get("/", MessageController.getAll); +messageRouter.get("/get-many", MessageController.getMany); +messageRouter.get("/:id", MessageController.getById); +messageRouter.put("/:id", MessageController.update); +messageRouter.delete("/delete-many", MessageController.deleteMany); +messageRouter.delete("/:id", MessageController.delete); + +export default messageRouter; diff --git a/server/routes/routes/user.router.ts b/server/routes/routes/user.router.ts index a434155..6a8813a 100644 --- a/server/routes/routes/user.router.ts +++ b/server/routes/routes/user.router.ts @@ -5,6 +5,7 @@ const userRouter = Router(); userRouter.post("/", UserController.create); userRouter.get("/", UserController.getAll); +userRouter.get("/get-many", UserController.getMany); userRouter.get("/:id", UserController.getById); userRouter.put("/:id", UserController.update); userRouter.delete("/delete-many", UserController.deleteMany); diff --git a/server/tsconfig.json b/server/tsconfig.json index 4fd9e9b..89777fd 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -21,7 +21,7 @@ // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + "useDefineForClassFields": false, /* Emit ECMAScript-standard-compliant class fields. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */