summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--controllers/games/gameId.js17
-rw-r--r--controllers/games/root.js13
-rw-r--r--controllers/play.js9
-rw-r--r--database/001_games.sql12
-rw-r--r--database/db.js1
-rw-r--r--database/games.js29
-rw-r--r--main.js4
-rw-r--r--middlewares/sessions.js2
-rw-r--r--routes/games.js15
-rw-r--r--routes/play.js35
-rw-r--r--static/index.css62
-rw-r--r--views/game.ejs (renamed from views/play.ejs)18
-rw-r--r--views/games.ejs17
13 files changed, 157 insertions, 77 deletions
diff --git a/controllers/games/gameId.js b/controllers/games/gameId.js
new file mode 100644
index 0000000..c87a857
--- /dev/null
+++ b/controllers/games/gameId.js
@@ -0,0 +1,17 @@
+import { getGame } from "../../database/games.js";
+
+function makePageData(user, cwdata) {
+ return {
+ title: "Jouer",
+ user: user,
+ CWDATA: cwdata,
+ };
+}
+
+export function gameId_get(req, res) {
+ const game = getGame(req.params.gameId);
+ // TODO redirect if null
+ let cwdata = game; // TODO reformat this object
+ console.log(cwdata);
+ return res.render("game", makePageData(req.session.user, cwdata));
+}
diff --git a/controllers/games/root.js b/controllers/games/root.js
new file mode 100644
index 0000000..ece7b74
--- /dev/null
+++ b/controllers/games/root.js
@@ -0,0 +1,13 @@
+import { listGames } from "../../database/games.js";
+
+export function root_get(req, res) {
+ const data = {
+ title: "Liste des parties",
+ user: req.session.user,
+ games: listGames(req.session.user.id),
+ };
+ for (let i=0; i<data.games.length; i++) {
+ data.games[i].data = JSON.parse(data.games[i].data);
+ }
+ return res.render("games", data);
+}
diff --git a/controllers/play.js b/controllers/play.js
deleted file mode 100644
index c00d15d..0000000
--- a/controllers/play.js
+++ /dev/null
@@ -1,9 +0,0 @@
-function makeController(req, cwdata) {
- return {
- title: "Jouer",
- user: req.session.user,
- CWDATA: cwdata,
- };
-}
-
-export default makeController;
diff --git a/database/001_games.sql b/database/001_games.sql
new file mode 100644
index 0000000..be45084
--- /dev/null
+++ b/database/001_games.sql
@@ -0,0 +1,12 @@
+CREATE TABLE games (
+ id INTEGER PRIMARY KEY,
+ player1 INTEGER NOT NULL,
+ player2 INTEGER NOT NULL,
+ data TEXT NOT NULL,
+ created_at DATE DEFAULT (datetime('now')),
+ last_move_at DATE DEFAULT NULL,
+ FOREIGN KEY (player1) REFERENCES users(id) ON DELETE CASCADE,
+ FOREIGN KEY (player2) REFERENCES users(id) ON DELETE CASCADE
+);
+CREATE INDEX idx_games_player1 ON games(player1);
+CREATE INDEX idx_games_player2 ON games(player2);
diff --git a/database/db.js b/database/db.js
index 259ab58..a360e9b 100644
--- a/database/db.js
+++ b/database/db.js
@@ -3,6 +3,7 @@ import Database from "better-sqlite3";
const allMigrations = [
"database/000_init.sql",
+ "database/001_games.sql",
];
const db = new Database("jdm.db");
diff --git a/database/games.js b/database/games.js
new file mode 100644
index 0000000..b378eb2
--- /dev/null
+++ b/database/games.js
@@ -0,0 +1,29 @@
+import db from "./db.js";
+
+const createGameStatement = db.prepare("INSERT INTO games (player1, player2, data) VALUES (?, ?, ?);");
+const getGameStatement = db.prepare("SELECT * from games where id = ?;");
+const listGamesStatement = db.prepare("SELECT * from games where player1 = ?1 OR player2 = ?1 ORDER BY last_move_at;");
+
+export function createGame(player1, player2, data) {
+ try {
+ return createGameStatement.run(player1, player2, data).lastInsertRowId;
+ } catch {
+ return null;
+ }
+}
+
+export function getGame(id) {
+ try {
+ return getGameStatement.get(id);
+ } catch {
+ return null;
+ }
+}
+
+export function listGames(userId) {
+ try {
+ return listGamesStatement.all({ 1: userId });
+ } catch {
+ return [];
+ }
+}
diff --git a/main.js b/main.js
index b4c68b2..c3ab576 100644
--- a/main.js
+++ b/main.js
@@ -1,7 +1,7 @@
import express from "express";
import helmet from "./middlewares/helmet.js";
-import playRouter from "./routes/play.js";
+import gamesRouter from "./routes/games.js";
import rootRouter from "./routes/root.js";
const app = express();
@@ -11,7 +11,7 @@ app.use(helmet);
app.set("views", "./views");
app.set("view engine", "ejs");
-app.use("/play", playRouter);
+app.use("/games", gamesRouter);
app.use("/static", express.static("static"));
app.use("/", rootRouter);
diff --git a/middlewares/sessions.js b/middlewares/sessions.js
index 6112a8c..8697ae0 100644
--- a/middlewares/sessions.js
+++ b/middlewares/sessions.js
@@ -3,7 +3,7 @@ import sqlite from "better-sqlite3";
import sqliteStore from "better-sqlite3-session-store";
const SqliteStore = sqliteStore(expressSession);
-const db = new sqlite("sessions.db", { verbose: console.log });
+const db = new sqlite("sessions.db", process.env.NODE_ENV === "production" ? null : { verbose: console.log });
const secret = process.env.SESSION_SECRET || "secret";
const session = expressSession({
cookie: {
diff --git a/routes/games.js b/routes/games.js
new file mode 100644
index 0000000..67d105d
--- /dev/null
+++ b/routes/games.js
@@ -0,0 +1,15 @@
+import express from "express";
+
+import { gameId_get } from "../controllers/games/gameId.js";
+import { root_get } from "../controllers/games/root.js";
+import requireAuth from "../middlewares/requireAuth.js";
+import session from "../middlewares/sessions.js";
+
+const router = express.Router();
+router.use(session);
+router.use(requireAuth);
+
+router.get("/", root_get);
+router.get("/:gameId(\\d+)", gameId_get);
+
+export default router;
diff --git a/routes/play.js b/routes/play.js
deleted file mode 100644
index 4db9acd..0000000
--- a/routes/play.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import express from "express";
-
-import makePlayController from "../controllers/play.js";
-import requireAuth from "../middlewares/requireAuth.js";
-import session from "../middlewares/sessions.js";
-
-const router = express.Router();
-router.use(session);
-router.use(requireAuth);
-
-router.get("/", (req, res) => {
- const cwdata = {
- board: [
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ],
- [ "", "", "", "", "","", "", "", "", "", "", "", "", "", "" ]
- ],
- letters: [ "A", "B", "C", "D", "E", "F", "JOKER" ]
- };
- return res.render("play", makePlayController(req, cwdata));
-});
-
-export default router;
diff --git a/static/index.css b/static/index.css
index f5ef0b9..afb1c33 100644
--- a/static/index.css
+++ b/static/index.css
@@ -8,7 +8,7 @@ aside {
}
body {
- background: #126623;
+ background: #358a46;
display: grid;
grid-template-rows: auto 1fr auto;
font-family: -apple-system, BlinkMacSystemFont,
@@ -50,11 +50,12 @@ header nav ul li {
text-decoration: none;
}
header nav ul li a {
- color: #b58900;
+ color: black;
display: block;
text-decoration: none;
}
header nav ul li.nav-menu-title {
+ background: #126623;
float: left;
text-transform: uppercase;
font-weight: 700;
@@ -68,50 +69,69 @@ form input {
}
main {
- margin-left: auto;
- margin-right: auto;
+ background: #126623;
+ padding-left: 1em;
+ padding-right: 1em;
}
-td {
- background: #47b75e;
- border: 1px solid #d4fcdb;
- min-width: 27px;
- height: 27px;
- text-align: center;
+#games {
+ border-collapse: collapse;
+}
+#games tr:nth-child(even){background-color: #f2f2f2;}
+#games tr:hover {background-color: #ddd;}
+#games td, #games th {
+ border: 1px solid #ddd;
+ padding: 8px;
+}
+#games th {
+ padding-top: 12px;
+ padding-bottom: 12px;
+ text-align: left;
+ background-color: #04AA6D;
+ color: white;
}
-#board {
- border-collapse: collapse;
- font-weight: bold;
+#remaining_letters {
max-width: 405px;
}
+#rack-area {
+ max-width: 405px;
+}
#rack {
display:inline-block;
font-weight: bold;
}
-
-#remaining_letters {
+#board {
+ border-collapse: collapse;
+ font-weight: bold;
max-width: 405px;
}
+#board tr td, #rack tr td {
+ background: #47b75e;
+ border: 1px solid #d4fcdb;
+ min-width: 27px;
+ height: 27px;
+ text-align: center;
+}
-.tw {
+#board tr td.tw {
background:#E60000;
}
-.dw {
+#board tr td.dw {
background:#F86969;
}
-.tl {
+#board tr td.tl {
background:#3675FA;
}
-.dl {
+#board tr td.dl {
background:#22ACD8;
}
-.start {
+#board tr td.start {
background:#ff5500;
}
-.letter {
+#board tr td.letter, #rack tr td.letter {
background:#f3e797;
}
.placed {
diff --git a/views/play.ejs b/views/game.ejs
index bc98c94..e1fab41 100644
--- a/views/play.ejs
+++ b/views/game.ejs
@@ -17,20 +17,20 @@
<tr><td id="s13_0"><td id="s13_1" class="dw" title="double word"><td id="s13_2"><td id="s13_3"><td id="s13_4"><td id="s13_5" class="tl" title="triple letter"><td id="s13_6"><td id="s13_7"><td id="s13_8"><td id="s13_9" class="tl" title="triple letter"><td id="s13_10"><td id="s13_11"><td id="s13_12"><td id="s13_13" class="dw" title="double word"><td id="s13_14"></tr>
<tr><td id="s14_0" class="tw" title="triple word"><td id="s14_1"><td id="s14_2"><td id="s14_3" class="dl" title="double letter"><td id="s14_4"><td id="s14_5"><td id="s14_6"><td id="s14_7" class="tw" title="triple word"><td id="s14_8"><td id="s14_9"><td id="s14_10"><td id="s14_11" class="dl" title="double letter"><td id="s14_12"><td id="s14_13"><td id="s14_14" class="tw" title="triple word"></tr>
</table>
-<p>
-<table id="rack">
- <tr><td id="l0"><td id="l1"><td id="l2"><td id="l3"><td id="l4"><td id="l5"><td id="l6"></tr>
-</table>
-<aside>
- <button title="validate your move" onclick="onvalidatemoveclick()" id="validate" disabled>0 - Validate</button>
- <button onclick="onSelectSwapTilesClicked()" id="pass">Pass</button>
-</aside>
+<p id="rack-area">
+ <table id="rack">
+ <tr><td id="l0"><td id="l1"><td id="l2"><td id="l3"><td id="l4"><td id="l5"><td id="l6"></tr>
+ </table>
+ <aside>
+ <button title="validate your move" onclick="onvalidatemoveclick()" id="validate" disabled>0 - Validate</button>
+ <button onclick="onSelectSwapTilesClicked()" id="pass">Pass</button>
+ </aside>
</p>
<p>
<span id="player_1_name">player one name</span>: <span class="player_name" id="player_1_points">0</span><br>
<span id="player_2_name">player two name</span>: <span class="player_name" id="player_2_points">0</span>
</p>
<p id="remaining_letters"></p>
-<script>var CWDATA = <%- JSON.stringify(CWDATA) %></script>
+<script>var CWDATA = <%- CWDATA.data %></script>
<script type="module" src="/static/index.js"></script>
<%- include("footer") %>
diff --git a/views/games.ejs b/views/games.ejs
new file mode 100644
index 0000000..3189be8
--- /dev/null
+++ b/views/games.ejs
@@ -0,0 +1,17 @@
+<%- include("header") %>
+<% if (Object.keys(games).length === 0) { %>
+<h2>Aucune partie en cours</h2>
+<% } else { %>
+<h2>Liste des parties en cours</h2>
+<table id="games">
+ <tr><th>Partie</th><th>Joueur 1</th><th>Joueur 2</th></tr>
+ <% games.forEach((game) => { %>
+ <tr>
+ <td><a href="/games/<%= game.id %>"><%= game.data.title %></a></td>
+ <td><a href="/users/<%= game.player1 %>"><%= game.data.player1.name %></a></td>
+ <td><a href="/users/<%= game.player2 %>"><%= game.data.player2.name %></a></td>
+ </tr>
+ <% }) %>
+</table>
+<% } %>
+<%- include("footer") %>