Skip to content

Commit e5341c2

Browse files
committed
i dont remember my changes
1 parent 005aef7 commit e5341c2

File tree

4 files changed

+163
-86
lines changed

4 files changed

+163
-86
lines changed

web/schema.prisma

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ model Borrow {
1515
id Int @id @default(autoincrement())
1616
userLogin String
1717
joyconsTaken Int
18-
borrowOpeningId Int @unique
19-
returnOpeningId Int @unique
18+
borrowOpeningId String @unique
19+
returnOpeningId String @unique
2020
createdAt DateTime @default(now())
2121
2222
user User @relation(fields: [userLogin], references: [login])
@@ -25,7 +25,7 @@ model Borrow {
2525
}
2626

2727
model Opening {
28-
id Int @id @default(autoincrement())
28+
id String @id @default(uuid())
2929
date DateTime?
3030
code String?
3131
codeGeneratedAt DateTime?

web/src/apiRouter.ts

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
CODE_LIFETIME,
66
generateCode,
77
generateNewCode,
8+
sendDiscordWebhook,
89
setLastTimeChestWasAlive,
910
} from "./utils";
1011

@@ -65,7 +66,8 @@ apiRouter.post("/sesame", async (request: Request, response: Response) => {
6566
});
6667

6768
apiRouter.get("/ping", async (request: Request, response: Response) => {
68-
setLastTimeChestWasAlive(Date.now());
69+
const interval: number = Number(request.body.interval) || undefined;
70+
setLastTimeChestWasAlive(Date.now(), interval);
6971
return response.status(200).send("Good news ! (Me too)");
7072
});
7173

@@ -83,34 +85,26 @@ apiRouter.get("/reports", async (request: Request, response: Response) => {
8385
if (borrows.length) {
8486
logger.info(`Generating reports for ${borrows.length} users !`);
8587
const count = borrows.reduce((acc, borrow) => acc + borrow.joyconsTaken, 0);
86-
fetch(process.env.DISCORD_WEBHOOK_URL, {
87-
method: "POST",
88-
headers: {'Content-Type': 'application/json'},
89-
body: JSON.stringify({
90-
content: null,
91-
embeds: [
92-
{
93-
title: "⚠️ Emprunts non rendus",
94-
description: `🚨 ${count} joycon${count > 1 ? "s" : ""} n'${
95-
count > 1 ? "ont" : "a"
96-
} pas été rendu${count > 1 ? "s" : ""} !`,
97-
color: 11468800,
98-
fields: borrows.map((borrow) => ({
99-
name: `${borrow.user.firstName} ${
100-
borrow.user.lastName
101-
}`,
102-
value: `${borrow.joyconsTaken} joycon${
103-
borrow.joyconsTaken > 1 ? "s" : ""
104-
} non rendu(s)\nContacte le : ${
105-
borrow.user.mail
106-
}`,
107-
})),
108-
timestamp: new Date().toISOString(),
109-
},
110-
],
111-
attachments: [],
112-
}),
113-
});
88+
sendDiscordWebhook([
89+
{
90+
title: "⚠️ Emprunts non rendus",
91+
description: `🚨 ${count} joycon${count > 1 ? "s" : ""} n'${
92+
count > 1 ? "ont" : "a"
93+
} pas été rendu${count > 1 ? "s" : ""} !`,
94+
color: 11468800,
95+
fields: borrows.map((borrow) => ({
96+
name: `${borrow.user.firstName} ${borrow.user.lastName}`,
97+
value: `${borrow.joyconsTaken} joycon${
98+
borrow.joyconsTaken > 1 ? "s" : ""
99+
} non rendu(s)\nContacte le : ${
100+
borrow.user.mail
101+
}\n[Génère un nouveau code de retour](https://turboswitch.assos.utt.fr/forceOpen?id=${
102+
borrow.returnOpeningId
103+
})`,
104+
})),
105+
timestamp: new Date(),
106+
},
107+
]);
114108
}
115109
return response.status(200).send("Generating reports");
116110
});

web/src/utils.ts

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,17 @@ import jwt from "jsonwebtoken";
33
import { prisma, prismaUtils } from "./prisma";
44
import { Prisma } from "@prisma/client";
55

6+
export type DiscordEmbed = {
7+
title: string;
8+
description: string;
9+
color: number;
10+
fields: {
11+
name: string;
12+
value: string;
13+
}[];
14+
timestamp: Date;
15+
};
16+
617
export function authenticate(request: Request) {
718
if (!request.cookies["token"]) {
819
return null;
@@ -144,15 +155,68 @@ export async function generateNewCode(borrowId: number) {
144155
return code;
145156
}
146157

158+
export function sendDiscordWebhook(embeds: DiscordEmbed[]) {
159+
return fetch(process.env.DISCORD_WEBHOOK_URL, {
160+
method: "POST",
161+
headers: { "Content-Type": "application/json" },
162+
body: JSON.stringify({
163+
content: null,
164+
embeds: embeds.map((embed) => ({
165+
...embed,
166+
timestamp: embed.timestamp.toISOString(),
167+
})),
168+
attachments: [],
169+
}),
170+
});
171+
}
172+
147173
let lastTimeChestWasAlive = 0;
148-
export function setLastTimeChestWasAlive(time: number) {
174+
let sendInterval = Number.parseInt(process.env.TIME_BEFORE_CHEST_DEATH) * 1000;
175+
let lastChestAlive = false;
176+
177+
function checkChestAlive() {
178+
if (chestAlive() !== lastChestAlive) {
179+
lastChestAlive = !lastChestAlive;
180+
if (lastChestAlive) {
181+
// Chest is up
182+
sendDiscordWebhook([
183+
{
184+
title: "✅ Le coffre est de nouveau en ligne",
185+
color: 2985934,
186+
description: "*Niceeeeuuuhh* 🎉🎉🎉",
187+
fields: [],
188+
timestamp: new Date(),
189+
},
190+
]);
191+
} else {
192+
// Chest is down
193+
sendDiscordWebhook([
194+
{
195+
title: "⚠️ Le coffre est hors ligne !",
196+
color: 16711680,
197+
description:
198+
"*<@&1209413150424825876> vérifiez l'état du coffre et des piles !*",
199+
fields: [],
200+
timestamp: new Date(),
201+
},
202+
]);
203+
}
204+
}
205+
}
206+
207+
export function setLastTimeChestWasAlive(time: number, sendInSecs?: number) {
149208
lastTimeChestWasAlive = time;
209+
sendInterval =
210+
((sendInSecs || Number.parseInt(process.env.TIME_BEFORE_CHEST_DEATH)) + 2) *
211+
1000;
212+
setTimeout(checkChestAlive, sendInterval);
150213
}
151-
export function getLastTimeChestWasAlive() {
152-
if (process.env.CHEST_ALWAYS_ALIVE === 'true') {
153-
return Date.now();
154-
}
155-
return lastTimeChestWasAlive;
214+
215+
export function chestAlive() {
216+
return (
217+
process.env.CHEST_ALWAYS_ALIVE === "true" ||
218+
Date.now() - lastTimeChestWasAlive < sendInterval
219+
);
156220
}
157221

158222
export const CODE_LIFETIME = Number(process.env.CODE_LIFETIME) * 1000;

web/src/webRouter.ts

Lines changed: 67 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
1-
import { NextFunction, Request, Response, Router } from "express";
1+
import { Request, Response, Router } from "express";
22
import path from "path";
33
import { XMLParser } from "fast-xml-parser";
44
import jwt from "jsonwebtoken";
55
import { prisma } from "./prisma";
66
import {
7-
authenticate, formatOpening,
7+
authenticate,
8+
chestAlive,
9+
formatOpening,
810
generateCode,
911
generateNewCode,
1012
getJoyconsLeft,
11-
getLastTimeChestWasAlive,
12-
getWaitingOpening, OPENING_INCLUDE_BEFORE_FORMATTING,
13+
getWaitingOpening,
14+
OPENING_INCLUDE_BEFORE_FORMATTING,
1315
} from "./utils";
1416

1517
const webRouter = Router();
1618

17-
function chestAlive() {
18-
return Date.now() - getLastTimeChestWasAlive() < Number.parseInt(process.env.TIME_BEFORE_CHEST_DEATH) * 1000;
19-
}
20-
2119
webRouter.get("/borrow", async (request: Request, response: Response) => {
22-
if (!chestAlive()) return response.redirect('/down');
20+
if (!chestAlive()) return response.redirect("/down");
2321
const login = authenticate(request);
24-
if (!authenticate(request)) return response.redirect('/login');
25-
if (await getWaitingOpening(login)) return response.redirect('/code');
22+
if (!authenticate(request)) return response.redirect("/login");
23+
if (await getWaitingOpening(login)) return response.redirect("/code");
2624
const joyconsLeft = await getJoyconsLeft();
27-
return response.render(path.join(__dirname, '../www/borrow.html'), { joyconsLeft });
25+
return response.render(path.join(__dirname, "../www/borrow.html"), {
26+
joyconsLeft,
27+
});
2828
});
2929

3030
webRouter.get("/code", async (request: Request, response: Response) => {
3131
const login = authenticate(request);
32-
if (!login) return response.redirect('/login');
33-
if (!chestAlive()) return response.redirect('/down');
34-
if (!await getWaitingOpening(login)) return response.redirect('/');
32+
if (!login) return response.redirect("/login");
33+
if (!chestAlive()) return response.redirect("/down");
34+
if (!(await getWaitingOpening(login))) return response.redirect("/");
3535
const opening = await getWaitingOpening(login);
3636
const newCode = await generateNewCode(opening.id);
37-
return response.render(path.join(__dirname, "../www/getCode.html"), { code: newCode, joycons: opening.borrow.joyconsTaken, type: opening.type });
37+
return response.render(path.join(__dirname, "../www/getCode.html"), {
38+
code: newCode,
39+
joycons: opening.borrow.joyconsTaken,
40+
type: opening.type,
41+
});
3842
});
3943

4044
webRouter.get("/login", async (request: Request, response: Response) => {
41-
if (!chestAlive()) return response.redirect('/down');
42-
if (authenticate(request)) return response.redirect('/');
45+
if (!chestAlive()) return response.redirect("/down");
46+
if (authenticate(request)) return response.redirect("/");
4347
if (!request.query["ticket"]) {
4448
return response.sendFile(path.join(__dirname, "../www/login.html"));
4549
}
@@ -100,16 +104,16 @@ webRouter.get("/login/cas", async (request: Request, response: Response) => {
100104
);
101105
});
102106

103-
webRouter.get('/logout', async (request: Request, response: Response) => {
104-
return response.clearCookie('token').redirect('/');
107+
webRouter.get("/logout", async (request: Request, response: Response) => {
108+
return response.clearCookie("token").redirect("/");
105109
});
106110

107111
webRouter.post("/borrow", async (request: Request, response: Response) => {
108112
const login = authenticate(request);
109-
if (!login) return response.redirect('/login');
110-
if (!chestAlive()) return response.redirect('/down');
111-
if (await getWaitingOpening(login)) return response.redirect('/code');
112-
if (!request.body.joycons) return response.redirect('/borrow');
113+
if (!login) return response.redirect("/login");
114+
if (!chestAlive()) return response.redirect("/down");
115+
if (await getWaitingOpening(login)) return response.redirect("/code");
116+
if (!request.body.joycons) return response.redirect("/borrow");
113117
const joycons = Number.parseInt(request.body.joycons);
114118
if (Number.isNaN(joycons)) {
115119
return response.redirect("/borrow");
@@ -132,49 +136,64 @@ webRouter.post("/borrow", async (request: Request, response: Response) => {
132136
user: { connect: { login } },
133137
},
134138
});
135-
return response.redirect('/code');
139+
return response.redirect("/code");
136140
});
137141

138-
webRouter.get('/forceOpen', async (request: Request, response: Response) => {
139-
if (!chestAlive()) return response.redirect('/down');
140-
if (!request.query['id']) return response.redirect('/');
141-
const opening = formatOpening(await prisma.opening.findUnique({
142-
where: { id: Number.parseInt(request.query.id as string), date: null, borrow: null },
143-
...OPENING_INCLUDE_BEFORE_FORMATTING
144-
}));
142+
webRouter.get("/forceOpen", async (request: Request, response: Response) => {
143+
if (!chestAlive()) return response.redirect("/down");
144+
if (!request.query["id"]) return response.redirect("/");
145+
const opening = formatOpening(
146+
await prisma.opening.findUnique({
147+
where: {
148+
id: Number.parseInt(request.query.id as string),
149+
date: null,
150+
borrow: null,
151+
},
152+
...OPENING_INCLUDE_BEFORE_FORMATTING,
153+
})
154+
);
145155
if (!opening) {
146-
return response.redirect('/');
156+
return response.redirect("/");
147157
}
148-
const newCode = await generateNewCode(Number.parseInt(request.query.id as string));
149-
response.render(path.join(__dirname, '../www/getCode.html'), { code: newCode, joycons: opening.borrow.joyconsTaken, type: opening.type });
158+
const newCode = await generateNewCode(
159+
Number.parseInt(request.query.id as string)
160+
);
161+
response.render(path.join(__dirname, "../www/getCode.html"), {
162+
code: newCode,
163+
joycons: opening.borrow.joyconsTaken,
164+
type: opening.type,
165+
});
150166
});
151167

152168
webRouter.get("/down", async (request: Request, response: Response) => {
153-
if (chestAlive()) return response.redirect('/');
169+
if (chestAlive()) return response.redirect("/");
154170
response.sendFile(path.join(__dirname, "../www/down.html"));
155171
});
156172

157-
webRouter.get('/legal', async (request: Request, response: Response) => {
173+
webRouter.get("/legal", async (request: Request, response: Response) => {
158174
return response.sendFile(path.join(__dirname, "../www/legal.html"));
159175
});
160176

161-
webRouter.get('/cancel', async (request: Request, response: Response) => {
162-
if (!chestAlive()) return response.redirect('/down');
177+
webRouter.get("/cancel", async (request: Request, response: Response) => {
178+
if (!chestAlive()) return response.redirect("/down");
163179
const login = authenticate(request);
164-
if (!login) return response.redirect('/login');
180+
if (!login) return response.redirect("/login");
165181
const opening = await getWaitingOpening(login);
166-
if (opening && opening.type === 'borrow') {
167-
await prisma.opening.update({ where: { id: opening.id }, data: { code: null, codeGeneratedAt: null } });
182+
if (opening && opening.type === "borrow") {
183+
await prisma.opening.update({
184+
where: { id: opening.id },
185+
data: { code: null, codeGeneratedAt: null },
186+
});
168187
}
169-
return response.redirect('/');
188+
return response.redirect("/");
170189
});
171190

172-
webRouter.get('/', async (request: Request, response: Response) => {
173-
if (!chestAlive()) return response.redirect('/down');
191+
webRouter.get("/", async (request: Request, response: Response) => {
192+
if (!chestAlive()) return response.redirect("/down");
174193
const login = authenticate(request);
175-
if (!login) return response.redirect('/login');
176-
if (await getWaitingOpening(login)) return response.redirect('/code');
177-
return response.redirect('/borrow');
194+
if (!login) return response.redirect("/login");
195+
if (await getWaitingOpening(login)) return response.redirect("/code");
196+
return response.redirect("/borrow");
178197
});
179198

180199
webRouter.use(async (request: Request, response: Response) => {

0 commit comments

Comments
 (0)