начал работу над функциональностью Message, мелкие правки

This commit is contained in:
dyakonovr 2024-03-26 21:03:55 +04:00
parent ed3f2cb63e
commit 5476b11fb5
18 changed files with 362 additions and 25 deletions

View File

@ -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={<ThreadCreate />}
// edit={<SectionEdit />}
/>
<Resource name="messages" list={<MessagesList />} create={<MessageCreate />} />
</Admin>
);
}

View File

@ -0,0 +1,26 @@
import {
Create,
ReferenceInput,
SelectInput,
SimpleForm,
TextInput,
required
} from "react-admin";
function MessageCreate() {
return (
<Create>
<SimpleForm>
<TextInput source="text" fullWidth multiline />
<ReferenceInput source="thread_id" reference="threads">
<SelectInput optionText="name" fullWidth validate={required()} />
</ReferenceInput>
<ReferenceInput source="user_id" reference="users">
<SelectInput optionText="nickname" fullWidth validate={required()} />
</ReferenceInput>
</SimpleForm>
</Create>
);
}
export default MessageCreate;

View File

@ -0,0 +1,27 @@
import {
Edit,
ReferenceInput,
SelectInput,
SimpleForm,
TextInput,
required,
} from "react-admin";
import Title from "../Title";
function SectionEdit() {
return (
<Edit title={<Title prefixText="Сообщение" />} actions={false}>
<SimpleForm>
<TextInput source="text" fullWidth multiline />
<ReferenceInput source="thread_id" reference="threads">
<SelectInput optionText="name" fullWidth validate={required()} />
</ReferenceInput>
<ReferenceInput source="user_id" reference="users">
<SelectInput optionText="nickname" fullWidth validate={required()} />
</ReferenceInput>
</SimpleForm>
</Edit>
);
}
export default SectionEdit;

View File

@ -0,0 +1,17 @@
import { List, Datagrid, TextField, EditButton } from "react-admin";
function MessagesList() {
return (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="text" />
<TextField source="user_id" />
<TextField source="thread_id" />
<EditButton />
</Datagrid>
</List>
);
};
export default MessagesList;

View File

@ -12,7 +12,11 @@ function ThreadCreate() {
<Create>
<SimpleForm>
<TextInput source="name" fullWidth />
<ReferenceInput source="section_id" reference="sections">
<ReferenceInput
source="section_id"
reference="sections"
filter={{ onlyEndSections: true }}
>
<SelectInput optionText="name" fullWidth validate={required()} />
</ReferenceInput>
<ReferenceInput source="creator_id" reference="users">

View File

@ -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<object, object, IMessageDto>,
res: Response<Message>,
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<Message>,
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<Message>,
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<Message>,
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();

View File

@ -0,0 +1,5 @@
export interface IMessageDto {
text: string;
user_id: number;
thread_id: number;
}

View File

@ -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));

View File

@ -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<object, object, IUserDto>,

View File

@ -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]
});

View File

@ -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;
}

View File

@ -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[];
}

View File

@ -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[];
}

View File

@ -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[];
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 */