diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bb83dc5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.mysql diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4099fa5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM oven/bun:1 AS base +WORKDIR /usr/src/app + +COPY package.json bun.lockb . +#RUN bun install --frozen-lockfile --production +RUN bun install --frozen-lockfile --development + +COPY . . + +#ENV NODE_ENV=production +ENV NODE_ENV=development + +USER bun +EXPOSE 8080/tcp +#ENTRYPOINT [ "bun", "run", "src/index.ts" ] +ENTRYPOINT [ "bun", "run", "dev" ] diff --git a/docker-compose.yml b/docker-compose.yml index 16c3776..aa72a3c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,16 @@ services: + app: + image: labyrint + build: + context: . + restart: on-failure:3 + ports: + - 8080:8080 + volumes: + - .:/usr/src/app + depends_on: + db: + condition: service_healthy adminer: image: adminer:latest restart: always @@ -11,8 +23,6 @@ services: restart: always environment: MYSQL_ROOT_PASSWORD: password - ports: - - 8081:3306 volumes: - ./.mysql:/var/lib/mysql healthcheck: diff --git a/drizzle.config.ts b/drizzle.config.ts index 2c477f4..8ed41bd 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -1,10 +1,10 @@ import { defineConfig } from "drizzle-kit"; export const dbCredentials = { - host: "127.0.0.1", - //host: "db", - port: 8081, - //port: 3306, + //host: "127.0.0.1", + host: "db", + //port: 8081, + port: 3306, user: "root", password: "password", database: "sous-podzim2024-app" diff --git a/src/database/schema.ts b/src/database/schema.ts index a62c322..783bc04 100644 --- a/src/database/schema.ts +++ b/src/database/schema.ts @@ -3,8 +3,8 @@ import { datetime, int, mysqlTable, varchar } from "drizzle-orm/mysql-core"; export const personTable = mysqlTable('person', { personId: int('personId').primaryKey().autoincrement(), - name: varchar('name', { length: 255 }), - secret: varchar('secret', { length: 255 }), + name: varchar('name', { length: 255 }).unique().notNull(), + secret: varchar('secret', { length: 255 }).unique().notNull(), gambleTime: datetime('gampleTime') }); diff --git a/src/index.ts b/src/index.ts index 2bd051b..25e0753 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,13 +30,17 @@ app.get("/", async (req, res) => { }); }); +function getNextGambleTime(time: Date): Date { + return new Date(time.getTime() + 3 * 60 * 60 * 1000); +} + function isGambleAvailable(time: Date | null): boolean { if (time == null) { return true; } // 3 hour delay before showing - if (new Date(time.getTime() + 3 * 60 * 60 * 1000) < new Date()) { + if (getNextGambleTime(time) < new Date()) { return true; } @@ -49,13 +53,23 @@ function isDetailAvailable(time: Date | null): boolean { } // 2 minute delay before hiding - if (new Date(time.getTime() + 1 * 60 * 1000) > new Date()) { + if (new Date(time.getTime() + 2 * 60 * 1000) > new Date()) { return true; } return false; } +function sendError(res: express.Response, code: number, error: string): void { + ejs.renderFile('src/templates/error.ejs', { error: error }, function (err, str) { + if (err) { + res.status(500).send(err); + } + + res.status(code).send(str); + }); +} + app.get("/gamble/:id", async (req, res) => { let id = parseInt(req.params.id); if (id == undefined) { @@ -77,13 +91,14 @@ app.get("/gamble/:id", async (req, res) => { } if (!isGambleAvailable(person.gambleTime)) { - ejs.renderFile('src/templates/error.ejs', { error: "Gamble is currently not available" }, function (err, str) { - if (err) { - res.status(500).send(err); - } - - res.send(str); - }); + if (person.gambleTime == null) { + sendError(res, 423, "Gamble není dostupný"); + } else { + sendError(res, 423, "Gamble bude dostupný až ve " + getNextGambleTime(person.gambleTime).toLocaleString('cs', { + hour: "2-digit", + minute: "2-digit", + })); + } return; } @@ -115,17 +130,17 @@ app.post("/gamble/:id", upload.none(), async (req, res) => { .groupBy(personTable.personId))[0]; if (!person) { - res.status(404).send("Invalid person id"); + sendError(res, 404, "Osoba nenalezena"); return; } if (!isGambleAvailable(person.gambleTime)) { - res.status(423).send("Gamble currently locked"); + sendError(res, 423, "Nelze zadat další gamble"); return; } if (person.secret != req.body['secret']) { - res.sendStatus(403); + sendError(res, 423, "Nesprávé heslo"); return; } @@ -150,7 +165,7 @@ app.post("/gamble/:id", upload.none(), async (req, res) => { app.get("/person/:id", async (req, res) => { let id = parseInt(req.params.id); if (id == undefined) { - res.status(404).send("Invalid person id"); + sendError(res, 404, "Osoba nenalezena"); return; } @@ -165,18 +180,12 @@ app.get("/person/:id", async (req, res) => { .groupBy(personTable.personId))[0]; if (!person) { - res.status(404).send("Invalid person id"); + sendError(res, 404, "Osoba nenalezena"); return; } if (!isDetailAvailable(person.gambleTime)) { - ejs.renderFile('src/templates/error.ejs', { error: "Detail not available" }, function (err, str) { - if (err) { - res.status(500).send(err); - } - - res.send(str); - }); + sendError(res, 404, "Detail bude dostupný až po dalším gamblu"); } let points = await db.query.pointsTable.findMany({ diff --git a/src/templates/error.ejs b/src/templates/error.ejs index 4b965e7..a72b5a3 100644 --- a/src/templates/error.ejs +++ b/src/templates/error.ejs @@ -6,11 +6,23 @@ -