This commit is contained in:
2024-06-05 19:14:56 +05:00
parent acae2e5a4c
commit e4331fb31f
22 changed files with 799 additions and 293 deletions
+1 -1
View File
@@ -1,7 +1,7 @@
module.exports = {
apps: [
{
name: "crm.stream.graff.tech-server",
name: "crm.stream.graff.tech-server:3001",
exec_mode: "cluster",
script: "yarn",
args: "start",
+4 -4
View File
@@ -19,17 +19,17 @@ const port = process.env.PORT || 3000;
connectDB();
app.use(json());
app.use(cors());
app.use(cors({ origin: "*" }));
app.use("/app", authMiddleware, appRouter);
app.use("/companies", authMiddleware, companiesRouter);
app.use("/users", authMiddleware, usersRouter);
app.use("/login", loginRouter);
app.use("/registration", registrationRouter);
app.use("/actions", actionsRouter);
app.use("/builds", buildsRouter);
app.use("/scheduled_sessions", scheduledSessionsRouter);
app.use("/schedules", schedulesRouter);
app.use("/app", authMiddleware, appRouter);
app.use("/companies", authMiddleware, companiesRouter);
app.use("/users", authMiddleware, usersRouter);
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
+4 -5
View File
@@ -16,10 +16,6 @@ const scheduleSchema = new Schema(
type: Date,
required: true,
},
endDate: {
type: Date,
required: true,
},
startTime: {
type: String,
required: true,
@@ -28,6 +24,9 @@ const scheduleSchema = new Schema(
type: String,
required: true,
},
weekends: {
type: [String],
},
sessionDuration: {
type: Number,
required: true,
@@ -36,7 +35,7 @@ const scheduleSchema = new Schema(
type: Number,
required: true,
},
sessionCount: {
sessionsPerDay: {
type: Number,
required: true,
},
+100 -78
View File
@@ -6,15 +6,15 @@ import Schedule from "../models/Schedule";
import BuildUser from "../models/BuildUser";
import User from "../models/User";
const companiesRouter = Router();
const router = Router();
// companiesRouter.get("/", async (_req, res) => {
// router.get("/", async (_req, res) => {
// const companies = await Company.find();
// res.json(companies);
// });
companiesRouter.get("/:id", async (req, res) => {
router.get("/:id", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
@@ -25,7 +25,7 @@ companiesRouter.get("/:id", async (req, res) => {
res.json(company);
});
companiesRouter.get("/:id/builds", async (req, res) => {
router.get("/:id/builds", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
@@ -37,7 +37,7 @@ companiesRouter.get("/:id/builds", async (req, res) => {
res.json(builds);
});
companiesRouter.get("/:id/users", async (req, res) => {
router.get("/:id/users", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
@@ -49,7 +49,7 @@ companiesRouter.get("/:id/users", async (req, res) => {
res.json(users);
});
companiesRouter.get("/:id/builds/:buildId/users", async (req, res) => {
router.get("/:id/builds/:buildId/users", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
@@ -69,44 +69,41 @@ companiesRouter.get("/:id/builds/:buildId/users", async (req, res) => {
res.json(users);
});
companiesRouter.get(
"/:id/builds/:buildId/scheduled_sessions",
async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
}
router.get("/:id/builds/:buildId/scheduled_sessions", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
}
if (!req.query.date) {
res.json({ error: "Query parameter `date` is required" });
return;
}
if (!req.query.date) {
res.json({ error: "Query parameter `date` is required" });
return;
}
const date = parseISO(req.query.date as string);
const date = parseISO(req.query.date as string);
const company: any = await Company.findById(req.params.id).populate({
path: "builds",
const company: any = await Company.findById(req.params.id).populate({
path: "builds",
match: {
_id: req.params.buildId,
},
populate: {
path: "scheduledSessions",
match: {
_id: req.params.buildId,
},
populate: {
path: "scheduledSessions",
match: {
startAt: {
$gte: startOfDay(date),
$lte: endOfDay(date),
},
startAt: {
$gte: startOfDay(date),
$lte: endOfDay(date),
},
},
});
},
});
const { scheduledSessions } = company.builds[0];
const { scheduledSessions } = company.builds[0];
res.json(scheduledSessions);
}
);
res.json(scheduledSessions);
});
// companiesRouter.post(
// router.post(
// "/:id/builds/:buildId/scheduled_sessions",
// async (req, res) => {
// if (req.params.id != res.locals.user.companyId) {
@@ -129,48 +126,45 @@ companiesRouter.get(
// }
// );
companiesRouter.put(
"/:id/scheduled_sessions/:scheduledSessionId",
async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
router.put("/:id/scheduled_sessions/:scheduledSessionId", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
}
try {
const scheduledSession = await ScheduledSession.findById(
req.params.scheduledSessionId
);
const scheduledSessionAtSameTime = await ScheduledSession.findOne({
startAt: scheduledSession?.startAt,
userId: req.body.userId,
});
if (scheduledSessionAtSameTime) {
res.json({ error: "Scheduled session at same time" });
return;
}
try {
const scheduledSession = await ScheduledSession.findById(
req.params.scheduledSessionId
);
const scheduledSessionAtSameTime = await ScheduledSession.findOne({
startAt: scheduledSession?.startAt,
userId: req.body.userId,
});
if (scheduledSessionAtSameTime) {
res.json({ error: "Scheduled session at same time" });
return;
const updatedScheduledSession = await ScheduledSession.findByIdAndUpdate(
req.params.scheduledSessionId,
req.body,
{
new: true,
upsert: true,
}
);
const updatedScheduledSession = await ScheduledSession.findByIdAndUpdate(
req.params.scheduledSessionId,
req.body,
{
new: true,
upsert: true,
}
);
res.json(updatedScheduledSession);
} catch (error) {
if (error instanceof Error) {
res.json({ error });
}
res.json(updatedScheduledSession);
} catch (error) {
if (error instanceof Error) {
res.json({ error });
}
}
);
});
companiesRouter.get(
router.get(
"/:id/builds/:buildId/scheduled_sessions/:scheduledSessionId/availableManagers",
async (req, res) => {
if (!req.query.startAt) {
@@ -225,7 +219,7 @@ companiesRouter.get(
}
);
companiesRouter.get("/:id/builds/:buildId/schedules", async (req, res) => {
router.get("/:id/builds/:buildId/schedules", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
@@ -239,19 +233,47 @@ companiesRouter.get("/:id/builds/:buildId/schedules", async (req, res) => {
res.json(schedules);
});
companiesRouter.post("/:id/builds/:buildId/schedules", async (req, res) => {
router.post("/:id/builds/:buildId/schedules", async (req, res) => {
if (req.params.id != res.locals.user.companyId) {
res.json({ error: "Access denied" });
return;
}
const schedule = await Schedule.create({
companyId: req.params.id,
buildId: req.params.buildId,
...req.body,
});
res.json(schedule);
try {
const schedule = await Schedule.create({
companyId: req.params.id,
buildId: req.params.buildId,
...req.body,
});
res.json(schedule);
} catch (error) {
if (error instanceof Error) {
res.json({ error: error.message });
}
}
});
router.get(
"/:companyId/builds/:buildId/last_scheduled_session",
async (req, res) => {
const { companyId, buildId } = req.params;
console.log("companyId", companyId);
console.log("buildId", buildId);
try {
const lastScheduledSession = await ScheduledSession.findOne({
companyId,
buildId,
}).sort({ startAt: -1 });
res.json(lastScheduledSession);
} catch (error) {
res.json({ error: (error as Error).message });
}
}
);
const companiesRouter = router;
export default companiesRouter;
+177 -17
View File
@@ -5,11 +5,13 @@ import Schedule from "../models/Schedule";
import {
addMinutes,
areIntervalsOverlapping,
differenceInMinutes,
endOfDay,
isValid,
parseISO,
startOfDay,
} from "date-fns";
import { isValidObjectId } from "mongoose";
const scheduledSessionsRouter = Router();
@@ -23,6 +25,15 @@ scheduledSessionsRouter.get("/", async (_req, res) => {
});
scheduledSessionsRouter.get("/:id", async (req, res) => {
const scheduledSessionId = req.params.id;
if (!isValidObjectId(scheduledSessionId)) {
return res.json({
status: "error",
message: "Invalid session ID value",
});
}
const scheduledSession = await ScheduledSession.findById(req.params.id);
res.json(scheduledSession);
@@ -41,6 +52,14 @@ scheduledSessionsRouter.get("/builds/:buildId", async (req, res) => {
const buildId = req.params.buildId;
const date = req.query.date as string;
if (!isValidObjectId(buildId)) {
return res.json({
status: "error",
message: "Invalid build ID value",
});
}
const scheduledSessions = await ScheduledSession.find({
buildId,
startAt: {
@@ -77,13 +96,19 @@ scheduledSessionsRouter.get("/:buildId", async (req, res) => {
});
scheduledSessionsRouter.post("/", async (req, res) => {
const { buildId, startAt, client } = req.body;
const { buildId, startAt, client, duration } = req.body;
if (!isValidObjectId(buildId)) {
return res.json({
status: "error",
message: "Invalid build ID value",
});
}
if (!buildId || !startAt) {
return res.json({
status: "error",
message:
"Parameters `buildId`, `startAt` are required!", // Параметры `compamyId`, `buildId`, `startAt`, `client` обязательны!
message: "Parameters `buildId`, `startAt` are required!", // Параметры `compamyId`, `buildId`, `startAt`, `client` обязательны!
});
}
@@ -96,6 +121,65 @@ scheduledSessionsRouter.post("/", async (req, res) => {
});
}
const build = await Build.findById(buildId);
if (!build) {
return res.json({
status: "error",
message: "An assembly with such a `buildId` was not found", // Сборка с таким `buildId` не найдена
});
}
if (duration) {
const scheduledSessions = await ScheduledSession.find({
buildId,
startAt: {
$gte: startOfDay(startAtISO),
$lte: endOfDay(startAtISO),
},
});
const endAtISO = addMinutes(startAtISO, duration);
if (scheduledSessions.length) {
const overlappingSessions = [];
for (const session of scheduledSessions) {
if (
areIntervalsOverlapping(
{
start: session.startAt,
end: addMinutes(session.endAt, duration),
},
{ start: startAtISO, end: endAtISO }
)
) {
overlappingSessions.push(session);
}
}
if (overlappingSessions.length >= build.sessionLimit) {
return res.json({
status: "error",
message:
"It is not possible to create a session because it overlaps with the time of another session", // Невозможно создать сеанс, поскольку он перекрывается со временем другого сеанса.
});
}
}
const scheduledSession = await ScheduledSession.create({
buildId,
startAt: startAtISO,
endAt: endAtISO,
});
return res.json({
status: "success",
scheduledSessionId: scheduledSession.id,
url: `https://stream.graff.tech/scheduled/${scheduledSession.id}`,
});
}
const schedule = await Schedule.findOne({
buildId,
startDate: { $lte: startAtISO },
@@ -109,15 +193,6 @@ scheduledSessionsRouter.post("/", async (req, res) => {
});
}
const build = await Build.findById(buildId);
if (!build) {
return res.json({
status: "error",
message: "An assembly with such a `buildId` was not found", // Сборка с таким `buildId` не найдена
});
}
const scheduledSessions = await ScheduledSession.find({
buildId,
startAt: {
@@ -163,18 +238,103 @@ scheduledSessionsRouter.post("/", async (req, res) => {
res.json({
status: "success",
scheduledSessionId: scheduledSession.id,
url: `https://stream.graff.tech/scheduled/${scheduledSession.id}`,
});
});
scheduledSessionsRouter.put("/:id", async (req, res) => {
const scheduledSession = await ScheduledSession.findByIdAndUpdate(
req.params.id,
req.body,
{ new: true, upsert: true }
const scheduledSessionId = req.params.id;
if (!isValidObjectId(scheduledSessionId)) {
return res.json({
status: "error",
message: "Invalid session ID value",
});
}
let { startAt, duration }: { startAt: string; duration: number } = req.body;
if (!startAt && !duration) {
return res.json({
status: "error",
message: "Parameter `startAt` or `duration` is required, or both",
});
}
if (startAt && !isValid(parseISO(startAt))) {
return res.json({
status: "error",
message: "Invalid value of the `startAt` parameter",
});
}
function isInteger(num: number) {
return (num ^ 0) === num;
}
if (duration && !isInteger(duration)) {
return res.json({
status: "error",
message: "Parameter `duration` is not an integer",
});
}
const scheduledSession = await ScheduledSession.findById(scheduledSessionId);
if (!scheduledSession) {
return res.json({
status: "error",
message: "Session with this ID not found",
});
}
if (!duration) {
duration = differenceInMinutes(
scheduledSession.endAt,
scheduledSession.startAt
);
}
const endAt = addMinutes(
(startAt && parseISO(startAt.toString())) || scheduledSession.startAt,
duration
);
res.json(scheduledSession);
try {
const scheduledSession = await ScheduledSession.findByIdAndUpdate(
scheduledSessionId,
{ startAt, endAt },
{ new: true }
);
res.json({ status: "success", scheduledSession });
} catch (error) {
if (error instanceof Error) {
res.json({ status: "error", message: error.message });
}
}
});
scheduledSessionsRouter.delete("/:id", async (req, res) => {
const scheduledSessionId = req.params.id;
if (!isValidObjectId(scheduledSessionId)) {
return res.json({
status: "error",
message: "Invalid session ID value",
});
}
try {
await ScheduledSession.findByIdAndDelete(scheduledSessionId);
res.json({ status: "success" });
} catch (error) {
if (error instanceof Error) {
res.json({ status: "error", message: error.message });
}
}
});
export default scheduledSessionsRouter;