From 123481d7485ff7e050dd71c30f7e2b5771e8dcaf Mon Sep 17 00:00:00 2001
From: didier amyot
Date: Sat, 8 Aug 2026 09:17:05 -0400
Subject: [PATCH] mdldfs
---
.gitignore | 11 +-
README.md | 63 ++--
deno.json | 10 -
deno.lock | 224 --------------
deploy | 1 -
server.ts | 237 ---------------
server/game-service.ts | 340 ----------------------
server/login-service.ts | 116 --------
server/types.ts | 19 --
templates/calendrier.vto | 8 -
templates/contact.vto | 35 ---
templates/container.vto | 102 -------
templates/home.vto | 108 -------
templates/includes/game-editor.vto | 72 -----
templates/includes/home-news.vto | 10 -
templates/includes/team-selector.vto | 10 -
templates/includes/walter-stewart-map.vto | 15 -
templates/membre.vto | 28 --
templates/nouvelles.vto | 69 -----
templates/partials/games-editor.vto | 37 ---
templates/partials/new-game-error.vto | 7 -
templates/partials/new-games-editor.vto | 45 ---
templates/partials/single-game-editor.vto | 7 -
templates/reglement.vto | 42 ---
24 files changed, 29 insertions(+), 1587 deletions(-)
delete mode 100644 deno.json
delete mode 100644 deno.lock
delete mode 100755 deploy
delete mode 100644 server.ts
delete mode 100644 server/game-service.ts
delete mode 100644 server/login-service.ts
delete mode 100644 server/types.ts
delete mode 100644 templates/calendrier.vto
delete mode 100644 templates/contact.vto
delete mode 100644 templates/container.vto
delete mode 100644 templates/home.vto
delete mode 100644 templates/includes/game-editor.vto
delete mode 100644 templates/includes/home-news.vto
delete mode 100644 templates/includes/team-selector.vto
delete mode 100644 templates/includes/walter-stewart-map.vto
delete mode 100644 templates/membre.vto
delete mode 100644 templates/nouvelles.vto
delete mode 100644 templates/partials/games-editor.vto
delete mode 100644 templates/partials/new-game-error.vto
delete mode 100644 templates/partials/new-games-editor.vto
delete mode 100644 templates/partials/single-game-editor.vto
delete mode 100644 templates/reglement.vto
diff --git a/.gitignore b/.gitignore
index e63210d..b4140eb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,11 +1,4 @@
-# Deno
-node_modules/*
-lib/*
-css/*
-/api/resultats.json
-/index.html
-/main-built.js
-/api
+# Nix build result
result
# .NET
@@ -16,4 +9,4 @@ obj/
*.db
publish/
-.direnv/
\ No newline at end of file
+.direnv/
diff --git a/README.md b/README.md
index a2ea44e..863509e 100644
--- a/README.md
+++ b/README.md
@@ -1,48 +1,39 @@
# Site Web de [Balle Phénix](http://ballephenix.com)
-
+## Stack
-## introduction
+- **ASP.NET Core 9** — Razor Views (`Views/*.cshtml`), contrôleurs dans `Controllers/`
+- **SQLite** par défaut (`phenix.db`), Postgres au choix via `DatabaseProvider`
+- **Nix** — build et déploiement via `flake.nix` (service NixOS, domaine `ballephenix.com`)
+- Les assets statiques vivent dans `static/` et sont servis par `app.config.WebRootPath = "static"`
-Vous trouverez le code source du site web pour les Phénix ici. Le site web
-en lui-même est accessible au http://ballephenix.com ou au
-https://ballephenix.gitlab.io/website/.
-
-### Structure du site web.
-
-Premièrement, mille excuses pour mes choix hétéroclites. J'ai décidé d'explorer
-de nouvels technologies avec ce projet. En conséquence, le code est un peu
-difficile à comprendre à première vue mais il est __tellement__ plus cool!
-
-
-#### Choix
-
-* mithril.js comme framework dans le fureteur
-* require.js pour les dépendances
-* uikit avec sass comme framework css
-* gulp pour la compilation
-* gitlab pour le deployment
-
----
-
-# English Version
-
-All the source code is in english. The source code is for a static web
-side for The softball league 'Balle Phénix'.
-
-## How to build
-
-No build, it uses [deno](https://deno.land)
-
-# How to run it
+## Développement
```shell
-deno run -A --unstable-vk server.ts
+dotnet run
```
+Base de données SQLite par défaut (`phenix.db`). La config se règle dans `appsettings.json`
+(ou par variables d'environnement en prod, voir le module NixOS dans `flake.nix`).
-## How to deploy the website
+Pour peupler une instance locale depuis la prod:
```shell
-./deploy
+python dev/populate-db/populate.py --source https://ballephenix.com --target http://localhost:5000 --force
+```
+
+## Déploiement
+
+Le build et le service NixOS sont décrits dans `flake.nix` (`packages.website` et
+`nixosModules.x86_64-linux`). Le module déploie le binaire `Phenix` avec `static/`
+et une base de données dans `/var/lib/phenix`.
+
+## Outils d'administration
+
+- `debut_saison.ts` — script Deno qui crée le calendrier de la saison: se connecte
+ via `GET /login` puis POST chaque partie à `/membre/new-game`. Mettre à jour les
+ identifiants en haut du fichier et les dates avant de le lancer.
+
+```shell
+deno run -A debut_saison.ts
```
diff --git a/deno.json b/deno.json
deleted file mode 100644
index a26ec2b..0000000
--- a/deno.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "deploy": {
- "project": "7a93d03e-eabe-4db1-b78e-5f1bbcb460b0",
- "exclude": [
- "**/node_modules"
- ],
- "include": [],
- "entrypoint": "server.ts"
- }
-}
\ No newline at end of file
diff --git a/deno.lock b/deno.lock
deleted file mode 100644
index 91e2b11..0000000
--- a/deno.lock
+++ /dev/null
@@ -1,224 +0,0 @@
-{
- "version": "4",
- "specifiers": {
- "jsr:@oak/commons@1": "1.0.0",
- "jsr:@oak/oak@*": "17.1.4",
- "jsr:@std/assert@1": "1.0.13",
- "jsr:@std/bytes@1": "1.0.5",
- "jsr:@std/crypto@1": "1.0.4",
- "jsr:@std/encoding@1": "1.0.10",
- "jsr:@std/encoding@^1.0.10": "1.0.10",
- "jsr:@std/http@1": "1.0.15",
- "jsr:@std/media-types@1": "1.1.0",
- "jsr:@std/path@1": "1.0.9",
- "npm:path-to-regexp@^6.3.0": "6.3.0"
- },
- "jsr": {
- "@oak/commons@1.0.0": {
- "integrity": "49805b55603c3627a9d6235c0655aa2b6222d3036b3a13ff0380c16368f607ac",
- "dependencies": [
- "jsr:@std/assert",
- "jsr:@std/bytes",
- "jsr:@std/crypto",
- "jsr:@std/encoding@1",
- "jsr:@std/http",
- "jsr:@std/media-types"
- ]
- },
- "@oak/oak@17.1.4": {
- "integrity": "60530b582bf276ff741e39cc664026781aa08dd5f2bc5134d756cc427bf2c13e",
- "dependencies": [
- "jsr:@oak/commons",
- "jsr:@std/assert",
- "jsr:@std/bytes",
- "jsr:@std/http",
- "jsr:@std/media-types",
- "jsr:@std/path",
- "npm:path-to-regexp"
- ]
- },
- "@std/assert@1.0.13": {
- "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29"
- },
- "@std/bytes@1.0.5": {
- "integrity": "4465dd739d7963d964c809202ebea6d5c6b8e3829ef25c6a224290fbb8a1021e"
- },
- "@std/crypto@1.0.4": {
- "integrity": "cee245c453bd5366207f4d8aa25ea3e9c86cecad2be3fefcaa6cb17203d79340"
- },
- "@std/encoding@1.0.10": {
- "integrity": "8783c6384a2d13abd5e9e87a7ae0520a30e9f56aeeaa3bdf910a3eaaf5c811a1"
- },
- "@std/http@1.0.15": {
- "integrity": "435a4934b4e196e82a8233f724da525f7b7112f3566502f28815e94764c19159",
- "dependencies": [
- "jsr:@std/encoding@^1.0.10"
- ]
- },
- "@std/media-types@1.1.0": {
- "integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4"
- },
- "@std/path@1.0.9": {
- "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e"
- }
- },
- "npm": {
- "path-to-regexp@6.3.0": {
- "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
- }
- },
- "remote": {
- "https://deno.land/std@0.205.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee",
- "https://deno.land/std@0.205.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56",
- "https://deno.land/std@0.205.0/html/entities.ts": "43f208131bb847e6e222c9dd50322066491da93ed945a93d778923ef7e975398",
- "https://deno.land/std@0.205.0/html/mod.ts": "3f8c71781e32037ab63bd417759d15d31fb9606c6615c85dcabcc515986494ba",
- "https://deno.land/std@0.205.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946",
- "https://deno.land/std@0.205.0/path/_common/basename.ts": "0d978ff818f339cd3b1d09dc914881f4d15617432ae519c1b8fdc09ff8d3789a",
- "https://deno.land/std@0.205.0/path/_common/common.ts": "9e4233b2eeb50f8b2ae10ecc2108f58583aea6fd3e8907827020282dc2b76143",
- "https://deno.land/std@0.205.0/path/_common/constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0",
- "https://deno.land/std@0.205.0/path/_common/dirname.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397",
- "https://deno.land/std@0.205.0/path/_common/format.ts": "11aa62e316dfbf22c126917f5e03ea5fe2ee707386555a8f513d27ad5756cf96",
- "https://deno.land/std@0.205.0/path/_common/from_file_url.ts": "ef1bf3197d2efbf0297a2bdbf3a61d804b18f2bcce45548ae112313ec5be3c22",
- "https://deno.land/std@0.205.0/path/_common/glob_to_reg_exp.ts": "5c3c2b79fc2294ec803d102bd9855c451c150021f452046312819fbb6d4dc156",
- "https://deno.land/std@0.205.0/path/_common/is_glob.ts": "567dce5c6656bdedfc6b3ee6c0833e1e4db2b8dff6e62148e94a917f289c06ad",
- "https://deno.land/std@0.205.0/path/_common/normalize.ts": "2ba7fb4cc9fafb0f38028f434179579ce61d4d9e51296fad22b701c3d3cd7397",
- "https://deno.land/std@0.205.0/path/_common/normalize_string.ts": "88c472f28ae49525f9fe82de8c8816d93442d46a30d6bb5063b07ff8a89ff589",
- "https://deno.land/std@0.205.0/path/_common/relative.ts": "1af19d787a2a84b8c534cc487424fe101f614982ae4851382c978ab2216186b4",
- "https://deno.land/std@0.205.0/path/_common/strip_trailing_separators.ts": "7ffc7c287e97bdeeee31b155828686967f222cd73f9e5780bfe7dfb1b58c6c65",
- "https://deno.land/std@0.205.0/path/_common/to_file_url.ts": "a8cdd1633bc9175b7eebd3613266d7c0b6ae0fb0cff24120b6092ac31662f9ae",
- "https://deno.land/std@0.205.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b",
- "https://deno.land/std@0.205.0/path/_os.ts": "30b0c2875f360c9296dbe6b7f2d528f0f9c741cecad2e97f803f5219e91b40a2",
- "https://deno.land/std@0.205.0/path/basename.ts": "04bb5ef3e86bba8a35603b8f3b69537112cdd19ce64b77f2522006da2977a5f3",
- "https://deno.land/std@0.205.0/path/common.ts": "f4d061c7d0b95a65c2a1a52439edec393e906b40f1caf4604c389fae7caa80f5",
- "https://deno.land/std@0.205.0/path/dirname.ts": "88a0a71c21debafc4da7a4cd44fd32e899462df458fbca152390887d41c40361",
- "https://deno.land/std@0.205.0/path/extname.ts": "2da4e2490f3b48b7121d19fb4c91681a5e11bd6bd99df4f6f47d7a71bb6ecdf2",
- "https://deno.land/std@0.205.0/path/format.ts": "3457530cc85d1b4bab175f9ae73998b34fd456c830d01883169af0681b8894fb",
- "https://deno.land/std@0.205.0/path/from_file_url.ts": "e7fa233ea1dff9641e8d566153a24d95010110185a6f418dd2e32320926043f8",
- "https://deno.land/std@0.205.0/path/glob.ts": "9c77cf47db1d786e2ebf66670824d03fd84ecc7c807cac24441eb9d5cb6a2986",
- "https://deno.land/std@0.205.0/path/is_absolute.ts": "67232b41b860571c5b7537f4954c88d86ae2ba45e883ee37d3dec27b74909d13",
- "https://deno.land/std@0.205.0/path/join.ts": "98d3d76c819af4a11a81d5ba2dbb319f1ce9d63fc2b615597d4bcfddd4a89a09",
- "https://deno.land/std@0.205.0/path/mod.ts": "2d62a0a8b78a60e8e6f485d881bac6b61d58573b11cf585fb7c8fc50d9b20d80",
- "https://deno.land/std@0.205.0/path/normalize.ts": "aa95be9a92c7bd4f9dc0ba51e942a1973e2b93d266cd74f5ca751c136d520b66",
- "https://deno.land/std@0.205.0/path/parse.ts": "d87ff0deef3fb495bc0d862278ff96da5a06acf0625ca27769fc52ac0d3d6ece",
- "https://deno.land/std@0.205.0/path/posix/_util.ts": "ecf49560fedd7dd376c6156cc5565cad97c1abe9824f4417adebc7acc36c93e5",
- "https://deno.land/std@0.205.0/path/posix/basename.ts": "a630aeb8fd8e27356b1823b9dedd505e30085015407caa3396332752f6b8406a",
- "https://deno.land/std@0.205.0/path/posix/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b",
- "https://deno.land/std@0.205.0/path/posix/dirname.ts": "f48c9c42cc670803b505478b7ef162c7cfa9d8e751b59d278b2ec59470531472",
- "https://deno.land/std@0.205.0/path/posix/extname.ts": "ee7f6571a9c0a37f9218fbf510c440d1685a7c13082c348d701396cc795e0be0",
- "https://deno.land/std@0.205.0/path/posix/format.ts": "b94876f77e61bfe1f147d5ccb46a920636cd3cef8be43df330f0052b03875968",
- "https://deno.land/std@0.205.0/path/posix/from_file_url.ts": "b97287a83e6407ac27bdf3ab621db3fccbf1c27df0a1b1f20e1e1b5acf38a379",
- "https://deno.land/std@0.205.0/path/posix/glob.ts": "86c3f06d1c98303613c74650961c3e24bdb871cde2a97c3ae7f0f6d4abbef445",
- "https://deno.land/std@0.205.0/path/posix/is_absolute.ts": "159900a3422d11069d48395568217eb7fc105ceda2683d03d9b7c0f0769e01b8",
- "https://deno.land/std@0.205.0/path/posix/join.ts": "0c0d84bdc344876930126640011ec1b888e6facf74153ffad9ef26813aa2a076",
- "https://deno.land/std@0.205.0/path/posix/mod.ts": "6bfa8a42d85345b12dbe8571028ca2c62d460b6ef968125e498602b43b6cf6b6",
- "https://deno.land/std@0.205.0/path/posix/normalize.ts": "11de90a94ab7148cc46e5a288f7d732aade1d616bc8c862f5560fa18ff987b4b",
- "https://deno.land/std@0.205.0/path/posix/parse.ts": "199208f373dd93a792e9c585352bfc73a6293411bed6da6d3bc4f4ef90b04c8e",
- "https://deno.land/std@0.205.0/path/posix/relative.ts": "e2f230608b0f083e6deaa06e063943e5accb3320c28aef8d87528fbb7fe6504c",
- "https://deno.land/std@0.205.0/path/posix/resolve.ts": "51579d83159d5c719518c9ae50812a63959bbcb7561d79acbdb2c3682236e285",
- "https://deno.land/std@0.205.0/path/posix/separator.ts": "0b6573b5f3269a3164d8edc9cefc33a02dd51003731c561008c8bb60220ebac1",
- "https://deno.land/std@0.205.0/path/posix/to_file_url.ts": "08d43ea839ee75e9b8b1538376cfe95911070a655cd312bc9a00f88ef14967b6",
- "https://deno.land/std@0.205.0/path/posix/to_namespaced_path.ts": "c9228a0e74fd37e76622cd7b142b8416663a9b87db643302fa0926b5a5c83bdc",
- "https://deno.land/std@0.205.0/path/relative.ts": "23d45ede8b7ac464a8299663a43488aad6b561414e7cbbe4790775590db6349c",
- "https://deno.land/std@0.205.0/path/resolve.ts": "5b184efc87155a0af9fa305ff68a109e28de9aee81fc3e77cd01380f19daf867",
- "https://deno.land/std@0.205.0/path/separator.ts": "40a3e9a4ad10bef23bc2cd6c610291b6c502a06237c2c4cd034a15ca78dedc1f",
- "https://deno.land/std@0.205.0/path/to_file_url.ts": "edaafa089e0bce386e1b2d47afe7c72e379ff93b28a5829a5885e4b6c626d864",
- "https://deno.land/std@0.205.0/path/to_namespaced_path.ts": "cf8734848aac3c7527d1689d2adf82132b1618eff3cc523a775068847416b22a",
- "https://deno.land/std@0.205.0/path/windows/_util.ts": "f32b9444554c8863b9b4814025c700492a2b57ff2369d015360970a1b1099d54",
- "https://deno.land/std@0.205.0/path/windows/basename.ts": "8a9dbf7353d50afbc5b221af36c02a72c2d1b2b5b9f7c65bf6a5a2a0baf88ad3",
- "https://deno.land/std@0.205.0/path/windows/common.ts": "e781d395dc76f6282e3f7dd8de13194abb8b04a82d109593141abc6e95755c8b",
- "https://deno.land/std@0.205.0/path/windows/dirname.ts": "5c2aa541384bf0bd9aca821275d2a8690e8238fa846198ef5c7515ce31a01a94",
- "https://deno.land/std@0.205.0/path/windows/extname.ts": "07f4fa1b40d06a827446b3e3bcc8d619c5546b079b8ed0c77040bbef716c7614",
- "https://deno.land/std@0.205.0/path/windows/format.ts": "343019130d78f172a5c49fdc7e64686a7faf41553268961e7b6c92a6d6548edf",
- "https://deno.land/std@0.205.0/path/windows/from_file_url.ts": "d53335c12b0725893d768be3ac6bf0112cc5b639d2deb0171b35988493b46199",
- "https://deno.land/std@0.205.0/path/windows/glob.ts": "0286fb89ecd21db5cbf3b6c79e2b87c889b03f1311e66fb769e6b905d4142332",
- "https://deno.land/std@0.205.0/path/windows/is_absolute.ts": "245b56b5f355ede8664bd7f080c910a97e2169972d23075554ae14d73722c53c",
- "https://deno.land/std@0.205.0/path/windows/join.ts": "e6600bf88edeeef4e2276e155b8de1d5dec0435fd526ba2dc4d37986b2882f16",
- "https://deno.land/std@0.205.0/path/windows/mod.ts": "c3d1a36fbf9f6db1320bcb4fbda8de011d25461be3497105e15cbea1e3726198",
- "https://deno.land/std@0.205.0/path/windows/normalize.ts": "9deebbf40c81ef540b7b945d4ccd7a6a2c5a5992f791e6d3377043031e164e69",
- "https://deno.land/std@0.205.0/path/windows/parse.ts": "120faf778fe1f22056f33ded069b68e12447668fcfa19540c0129561428d3ae5",
- "https://deno.land/std@0.205.0/path/windows/relative.ts": "026855cd2c36c8f28f1df3c6fbd8f2449a2aa21f48797a74700c5d872b86d649",
- "https://deno.land/std@0.205.0/path/windows/resolve.ts": "5ff441ab18a2346abadf778121128ee71bda4d0898513d4639a6ca04edca366b",
- "https://deno.land/std@0.205.0/path/windows/separator.ts": "ae21f27015f10510ed1ac4a0ba9c4c9c967cbdd9d9e776a3e4967553c397bd5d",
- "https://deno.land/std@0.205.0/path/windows/to_file_url.ts": "8e9ea9e1ff364aa06fa72999204229952d0a279dbb876b7b838b2b2fea55cce3",
- "https://deno.land/std@0.205.0/path/windows/to_namespaced_path.ts": "e0f4d4a5e77f28a5708c1a33ff24360f35637ba6d8f103d19661255ef7bfd50d",
- "https://deno.land/std@0.224.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975",
- "https://deno.land/std@0.224.0/assert/assert.ts": "09d30564c09de846855b7b071e62b5974b001bb72a4b797958fe0660e7849834",
- "https://deno.land/std@0.224.0/assert/assert_almost_equals.ts": "9e416114322012c9a21fa68e187637ce2d7df25bcbdbfd957cd639e65d3cf293",
- "https://deno.land/std@0.224.0/assert/assert_array_includes.ts": "14c5094471bc8e4a7895fc6aa5a184300d8a1879606574cb1cd715ef36a4a3c7",
- "https://deno.land/std@0.224.0/assert/assert_equals.ts": "3bbca947d85b9d374a108687b1a8ba3785a7850436b5a8930d81f34a32cb8c74",
- "https://deno.land/std@0.224.0/assert/assert_exists.ts": "43420cf7f956748ae6ed1230646567b3593cb7a36c5a5327269279c870c5ddfd",
- "https://deno.land/std@0.224.0/assert/assert_false.ts": "3e9be8e33275db00d952e9acb0cd29481a44fa0a4af6d37239ff58d79e8edeff",
- "https://deno.land/std@0.224.0/assert/assert_greater.ts": "5e57b201fd51b64ced36c828e3dfd773412c1a6120c1a5a99066c9b261974e46",
- "https://deno.land/std@0.224.0/assert/assert_greater_or_equal.ts": "9870030f997a08361b6f63400273c2fb1856f5db86c0c3852aab2a002e425c5b",
- "https://deno.land/std@0.224.0/assert/assert_instance_of.ts": "e22343c1fdcacfaea8f37784ad782683ec1cf599ae9b1b618954e9c22f376f2c",
- "https://deno.land/std@0.224.0/assert/assert_is_error.ts": "f856b3bc978a7aa6a601f3fec6603491ab6255118afa6baa84b04426dd3cc491",
- "https://deno.land/std@0.224.0/assert/assert_less.ts": "60b61e13a1982865a72726a5fa86c24fad7eb27c3c08b13883fb68882b307f68",
- "https://deno.land/std@0.224.0/assert/assert_less_or_equal.ts": "d2c84e17faba4afe085e6c9123a63395accf4f9e00150db899c46e67420e0ec3",
- "https://deno.land/std@0.224.0/assert/assert_match.ts": "ace1710dd3b2811c391946954234b5da910c5665aed817943d086d4d4871a8b7",
- "https://deno.land/std@0.224.0/assert/assert_not_equals.ts": "78d45dd46133d76ce624b2c6c09392f6110f0df9b73f911d20208a68dee2ef29",
- "https://deno.land/std@0.224.0/assert/assert_not_instance_of.ts": "3434a669b4d20cdcc5359779301a0588f941ffdc2ad68803c31eabdb4890cf7a",
- "https://deno.land/std@0.224.0/assert/assert_not_match.ts": "df30417240aa2d35b1ea44df7e541991348a063d9ee823430e0b58079a72242a",
- "https://deno.land/std@0.224.0/assert/assert_not_strict_equals.ts": "37f73880bd672709373d6dc2c5f148691119bed161f3020fff3548a0496f71b8",
- "https://deno.land/std@0.224.0/assert/assert_object_match.ts": "411450fd194fdaabc0089ae68f916b545a49d7b7e6d0026e84a54c9e7eed2693",
- "https://deno.land/std@0.224.0/assert/assert_rejects.ts": "4bee1d6d565a5b623146a14668da8f9eb1f026a4f338bbf92b37e43e0aa53c31",
- "https://deno.land/std@0.224.0/assert/assert_strict_equals.ts": "b4f45f0fd2e54d9029171876bd0b42dd9ed0efd8f853ab92a3f50127acfa54f5",
- "https://deno.land/std@0.224.0/assert/assert_string_includes.ts": "496b9ecad84deab72c8718735373feb6cdaa071eb91a98206f6f3cb4285e71b8",
- "https://deno.land/std@0.224.0/assert/assert_throws.ts": "c6508b2879d465898dab2798009299867e67c570d7d34c90a2d235e4553906eb",
- "https://deno.land/std@0.224.0/assert/assertion_error.ts": "ba8752bd27ebc51f723702fac2f54d3e94447598f54264a6653d6413738a8917",
- "https://deno.land/std@0.224.0/assert/equal.ts": "bddf07bb5fc718e10bb72d5dc2c36c1ce5a8bdd3b647069b6319e07af181ac47",
- "https://deno.land/std@0.224.0/assert/fail.ts": "0eba674ffb47dff083f02ced76d5130460bff1a9a68c6514ebe0cdea4abadb68",
- "https://deno.land/std@0.224.0/assert/mod.ts": "48b8cb8a619ea0b7958ad7ee9376500fe902284bb36f0e32c598c3dc34cbd6f3",
- "https://deno.land/std@0.224.0/assert/unimplemented.ts": "8c55a5793e9147b4f1ef68cd66496b7d5ba7a9e7ca30c6da070c1a58da723d73",
- "https://deno.land/std@0.224.0/assert/unreachable.ts": "5ae3dbf63ef988615b93eb08d395dda771c96546565f9e521ed86f6510c29e19",
- "https://deno.land/std@0.224.0/fmt/colors.ts": "508563c0659dd7198ba4bbf87e97f654af3c34eb56ba790260f252ad8012e1c5",
- "https://deno.land/std@0.224.0/internal/diff.ts": "6234a4b493ebe65dc67a18a0eb97ef683626a1166a1906232ce186ae9f65f4e6",
- "https://deno.land/std@0.224.0/internal/format.ts": "0a98ee226fd3d43450245b1844b47003419d34d210fa989900861c79820d21c2",
- "https://deno.land/std@0.224.0/internal/mod.ts": "534125398c8e7426183e12dc255bb635d94e06d0f93c60a297723abe69d3b22e",
- "https://deno.land/std@0.84.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58",
- "https://deno.land/std@0.84.0/_util/os.ts": "e282950a0eaa96760c0cf11e7463e66babd15ec9157d4c9ed49cc0925686f6a7",
- "https://deno.land/std@0.84.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853",
- "https://deno.land/std@0.84.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4",
- "https://deno.land/std@0.84.0/path/_util.ts": "f4fa69aa3cbbd8568763bfc43c7236875015ba343602d8bafd332b4b4243681b",
- "https://deno.land/std@0.84.0/path/common.ts": "eaf03d08b569e8a87e674e4e265e099f237472b6fd135b3cbeae5827035ea14a",
- "https://deno.land/std@0.84.0/path/glob.ts": "4a524c1c9da3e79a9fdabdc6e850cd9e41bdf31e442856ffa19c5b123268ca95",
- "https://deno.land/std@0.84.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12",
- "https://deno.land/std@0.84.0/path/posix.ts": "1408f8ba482a4dc5fc0a7cd7be28bbbff9608d2b3b5ffdcf288ae1228d959add",
- "https://deno.land/std@0.84.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c",
- "https://deno.land/std@0.84.0/path/win32.ts": "6ca052f54500f00cd7a5172fde62900626ab620dcd5bdcf4e6f5695d001ddef6",
- "https://deno.land/std@0.99.0/_util/assert.ts": "2f868145a042a11d5ad0a3c748dcf580add8a0dbc0e876eaa0026303a5488f58",
- "https://deno.land/std@0.99.0/_util/os.ts": "e282950a0eaa96760c0cf11e7463e66babd15ec9157d4c9ed49cc0925686f6a7",
- "https://deno.land/std@0.99.0/path/_constants.ts": "1247fee4a79b70c89f23499691ef169b41b6ccf01887a0abd131009c5581b853",
- "https://deno.land/std@0.99.0/path/_interface.ts": "1fa73b02aaa24867e481a48492b44f2598cd9dfa513c7b34001437007d3642e4",
- "https://deno.land/std@0.99.0/path/_util.ts": "2e06a3b9e79beaf62687196bd4b60a4c391d862cfa007a20fc3a39f778ba073b",
- "https://deno.land/std@0.99.0/path/common.ts": "eaf03d08b569e8a87e674e4e265e099f237472b6fd135b3cbeae5827035ea14a",
- "https://deno.land/std@0.99.0/path/glob.ts": "314ad9ff263b895795208cdd4d5e35a44618ca3c6dd155e226fb15d065008652",
- "https://deno.land/std@0.99.0/path/mod.ts": "4465dc494f271b02569edbb4a18d727063b5dbd6ed84283ff906260970a15d12",
- "https://deno.land/std@0.99.0/path/posix.ts": "f56c3c99feb47f30a40ce9d252ef6f00296fa7c0fcb6dd81211bdb3b8b99ca3b",
- "https://deno.land/std@0.99.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c",
- "https://deno.land/std@0.99.0/path/win32.ts": "77f7b3604e0de40f3a7c698e8a79e7f601dc187035a1c21cb1e596666ce112f8",
- "https://deno.land/x/media_types@v2.7.1/db.ts": "1d95aa3fc1fe076638550640609394f0e157b18b430800e419aa7ece5c151d9c",
- "https://deno.land/x/media_types@v2.7.1/deps.ts": "cd4c31e4b5ed8c4d8c61bd2fb38a82d68d3fd2dcf6d43f22511cbe6d9d310e51",
- "https://deno.land/x/media_types@v2.7.1/mod.ts": "d63583b978d32eff8b76e1ae5d83cba2fb27baa90cc1bcb0ad15a06122ea8c19",
- "https://deno.land/x/static_files@1.1.6/mod.ts": "8a9bb05599e53864c54eb22931fe98507818517e0d69f26e099a1d8f4ef2b638",
- "https://deno.land/x/static_files@1.1.6/src/deps.ts": "fb62be7a780339157bf692a619d6d02ea9662490deca275f488f9f9db917fc4a",
- "https://deno.land/x/static_files@1.1.6/src/types.ts": "ef201288626294e9e1b8ee85cdfe2cdfb282e4d78af445df1726050dfa0c0988",
- "https://deno.land/x/static_files@1.1.6/src/utils.ts": "9e6172dc97fed01e70a6b063c5afff40e20fe726b3bae0c5f0a962bad74b7107",
- "https://deno.land/x/vento@v0.9.1/deps.ts": "1fb4acd6b3b6261c308280b09e8feadac7b0fac1e01bd0e0f1e75527a2181a52",
- "https://deno.land/x/vento@v0.9.1/mod.ts": "ab690911075158ee3762bd7aefe209cdcb6ead7b492f14b0693d7025244db8e6",
- "https://deno.land/x/vento@v0.9.1/plugins/echo.ts": "f7c064fb6d34b29852f46f6e01583ed87656dcbbc5cae51c8f29198d6951d0cf",
- "https://deno.land/x/vento@v0.9.1/plugins/escape.ts": "8115ec84c84c13811f4a43263b8954e912df94df6565d6ff9ce7faea7daa50be",
- "https://deno.land/x/vento@v0.9.1/plugins/export.ts": "ef54811ed0205aaeef6ad09557c94b8ae98e1457234898da5a1c5461a7dcf424",
- "https://deno.land/x/vento@v0.9.1/plugins/for.ts": "6313e139a23ed17ca8b0852031f8d9e11aeb7520b228e68b9233418d25745414",
- "https://deno.land/x/vento@v0.9.1/plugins/function.ts": "cdf610a98493e4a093c53473abdad7d47cbcff40aa8362d280e39910620cb8d6",
- "https://deno.land/x/vento@v0.9.1/plugins/if.ts": "9de295f8675cacaec7866ad21068b6b089bfcadf72d3c62e1df50ca378c04279",
- "https://deno.land/x/vento@v0.9.1/plugins/import.ts": "406204ab9d785db206da5d5cbcffa9a111cef2a39a19574e630cdea89b0691c5",
- "https://deno.land/x/vento@v0.9.1/plugins/include.ts": "a9c65ce90354766220c0c9f7b21ea2db97bed99d9ffbe28f8a5ac035d488b163",
- "https://deno.land/x/vento@v0.9.1/plugins/js.ts": "2c50d60061e9c5b6280a145266e617181534b8767e91127d59d5cf5febdcfb03",
- "https://deno.land/x/vento@v0.9.1/plugins/layout.ts": "b9970b762ba73cf5605e63e585792803a48e326621c6cb2ec216502ba21a90cd",
- "https://deno.land/x/vento@v0.9.1/plugins/set.ts": "016235a906f99cbfab78d29dfdfe8ca0925db7a46458fd873adacd0d7c6ed82d",
- "https://deno.land/x/vento@v0.9.1/plugins/unescape.ts": "946512835a409815d6ad98ac4529440e9a368f42ca499791d0f25ee0ecc4c4d6",
- "https://deno.land/x/vento@v0.9.1/src/environment.ts": "9c28fbf05176297adb93fc688711125b295c69089554d4211cd38a5b04028ec5",
- "https://deno.land/x/vento@v0.9.1/src/loader.ts": "eb01b0dca7ea8bcdcdfd30b1f90f2fad28fb7f2cfd943900322a85bfaa86130c",
- "https://deno.land/x/vento@v0.9.1/src/tokenizer.ts": "e9918ac58f941e048fe08cea10e65fb6e19c00fe7ed31fb050663445f11c6e9d"
- }
-}
diff --git a/deploy b/deploy
deleted file mode 100755
index 14ae80c..0000000
--- a/deploy
+++ /dev/null
@@ -1 +0,0 @@
-exec deno run -A jsr:@deno/deployctl deploy --prod --project=phenix server.ts
diff --git a/server.ts b/server.ts
deleted file mode 100644
index 337a3b3..0000000
--- a/server.ts
+++ /dev/null
@@ -1,237 +0,0 @@
-import { Application } from "jsr:@oak/oak/application";
-import { Router } from "jsr:@oak/oak/router";
-import { GameService } from "./server/game-service.ts";
-import { Game } from "./server/types.ts";
-import staticFiles from "https://deno.land/x/static_files@1.1.6/mod.ts";
-import vento from "https://deno.land/x/vento@v0.9.1/mod.ts";
-import { LoginService } from "./server/login-service.ts";
-
-const env = vento();
-setInterval(() => env.cache.clear(), 1000);
-const gameService = new GameService(await Deno.openKv());
-const loginService = LoginService.officialLoginService();
-
-const router = new Router();
-
-router.get("/", async (ctx) => {
- const template = await env.load("templates/home.vto");
- const result = await template({ tab: "home" });
- ctx.response.body = result.content;
-});
-
-router.get("/calendrier", async (ctx) => {
- const template = await env.load("templates/calendrier.vto");
- const result = await template({
- tab: "calendrier",
- });
- ctx.response.body = result.content;
-});
-
-router.get("/nouvelles", async (ctx) => {
- const template = await env.load("templates/nouvelles.vto");
- const result = await template({ tab: "nouvelles" });
- ctx.response.body = result.content;
-});
-
-router.get("/contact", async (ctx) => {
- const template = await env.load("templates/contact.vto");
- const result = await template({ tab: "contact" });
- ctx.response.body = result.content;
-});
-
-router.get("/reglement", async (ctx) => {
- const template = await env.load("templates/reglement.vto");
- const result = await template({ tab: "reglement" });
- ctx.response.body = result.content;
-});
-
-router.get("/login", async (ctx) => {
- const username = ctx.request.url.searchParams.get("username") || "";
- const password = ctx.request.url.searchParams.get("password") || "";
-
- if (!(await loginService.validateCredentials(username, password))) {
- ctx.response.status = 403;
- return;
- }
- await loginService.login(ctx);
- ctx.response.redirect("/membre/games-editor/today");
-});
-
-const memberRouter = new Router();
-
-memberRouter.use(async (ctx, next) => {
- const isLoggedIn = await loginService.isLoggedIn(ctx);
- if (ctx.request.url.pathname !== "/membre" && !isLoggedIn) {
- ctx.response.redirect("/membre");
- return;
- }
- ctx.params.isLoggedIn = isLoggedIn;
- await next();
-});
-
-memberRouter.get("/", async (ctx) => {
- const template = await env.load("templates/membre.vto");
- const result = await template({
- tab: "membre",
- isLoggedIn: ctx.params.isLoggedIn,
- });
- ctx.response.body = result.content;
-});
-
-function today(): Date {
- const date = new Date().toLocaleDateString("fr-CA", {
- timeZone: "America/New_York",
- });
- return new Date(date);
-}
-
-memberRouter.get("/games-editor/today", async (ctx) => {
- const template = await env.load("templates/partials/games-editor.vto");
- const games = await gameService.getAllGames();
- const lastGameDay = games
- .map((g) => g.date)
- .filter((d) => new Date(d) <= today())
- .sort()
- .reverse()[0];
-
- const result = await template({
- tab: "membre",
- selectedYear: null,
- isToday: true,
- games: games.filter((g) => g.date === lastGameDay),
- years: [...new Set(games.map((x) => x.year))].sort().reverse(),
- });
- ctx.response.body = result.content;
-});
-
-memberRouter.get("/games-editor/:year", async (ctx) => {
- const template = await env.load("templates/partials/games-editor.vto");
- const games = await gameService.getAllGames();
- const selectedYear = parseInt(ctx.params.year);
- const result = await template({
- tab: "membre",
- selectedYear: selectedYear,
- games: games.filter((g) => g.year === selectedYear),
- years: [...new Set(games.map((x) => x.year))].sort().reverse(),
- });
- ctx.response.body = result.content;
-});
-
-memberRouter.get("/new-game-editor", async (ctx) => {
- const template = await env.load("templates/partials/new-games-editor.vto");
- const result = await template({
- tab: "membre",
- });
- ctx.response.body = result.content;
-});
-
-memberRouter.post("/new-game", async (ctx) => {
- const payload = await ctx.request.body.form();
- const preGame = {
- date: payload.get("game-date"),
- time: payload.get("game-time"),
- away: payload.get("away-team"),
- home: payload.get("home-team"),
- };
- const [game, error] = await gameService.createNewGame(preGame);
-
- if (error !== "") {
- const template = await env.load("templates/partials/new-game-error.vto");
- const result = await template({
- tab: "membre",
- error: error,
- });
- ctx.response.status = 500;
- ctx.response.body = result.content;
- return;
- }
-
- const template = await env.load("templates/partials/single-game-editor.vto");
- const result = await template({
- tab: "membre",
- game: game,
- });
- ctx.response.headers.set("game-id", game?.id ?? "");
- ctx.response.body = result.content;
-});
-
-memberRouter.delete("/games/:gameId", async (ctx) => {
- if (!(await loginService.isLoggedIn(ctx))) {
- ctx.response.redirect("/membre");
- return;
- }
- const success = await gameService.deleteGameById(ctx.params.gameId);
- ctx.response.body = `${success}`;
-});
-
-memberRouter.post("/games/:gameId", async (ctx) => {
- if (!(await loginService.isLoggedIn(ctx))) {
- ctx.response.redirect("/membre");
- return;
- }
- const payload = await ctx.request.body.form();
- let preGame = {
- awayScore: payload.get("away-score") ?? null,
- homeScore: payload.get("home-score") ?? null,
- rain: payload.get("game-type") === "rain",
- practice: payload.get("game-type") === "practice",
- };
-
- preGame = Object.fromEntries(
- Object.entries(preGame).filter(([_, v]) => v !== null),
- ) as Partial;
-
- const success = await gameService.updateGame(ctx.params.gameId, preGame);
- ctx.response.body = success
- ? ` `
- : ` `;
-});
-
-memberRouter.post("/games/:gameId/switch", async (ctx) => {
- if (!(await loginService.isLoggedIn(ctx))) {
- ctx.response.redirect("/membre");
- return;
- }
- const success = await gameService.switchVisitors(ctx.params.gameId);
- if (!success) {
- ctx.response.body = ` `;
- }
- const template = await env.load("templates/partials/single-game-editor.vto");
- const game = await gameService.getGameById(ctx.params.gameId);
- const result = await template({
- tab: "membre",
- game: game,
- });
- ctx.response.headers.set("game-id", game?.id ?? "");
- ctx.response.body = result.content;
-});
-
-const apiRouter = new Router();
-
-apiRouter.get("/results/:year.json", async (ctx) => {
- ctx.response.json = true;
- const games = await gameService.getAllGames();
- ctx.response.body = games
- .filter((g) => g.year == ctx.params.year)
- .map((g) => {
- g[g.home] = parseInt(g.homeScore);
- g[g.away] = parseInt(g.awayScore);
- return g;
- });
-});
-
-apiRouter.get("/available-years.json", async (ctx) => {
- ctx.response.json = true;
- const games = await gameService.getAllGames();
- ctx.response.body = [...new Set(games.map((g) => g.year))];
-});
-
-router.use("/membre", memberRouter.routes());
-router.use("/api", apiRouter.routes());
-
-const app = new Application();
-app.use(router.routes());
-
-app.use(staticFiles("static", { brotli: true, fetch: true }));
-
-await app.listen({ port: 8000 });
diff --git a/server/game-service.ts b/server/game-service.ts
deleted file mode 100644
index 4244c45..0000000
--- a/server/game-service.ts
+++ /dev/null
@@ -1,340 +0,0 @@
-import { Game, PreGame } from "./types.ts";
-import {
- assertEquals,
- assertNotEquals,
-} from "https://deno.land/std@0.224.0/assert/mod.ts";
-
-type GamePrimaryKey = ["phenix", "games", string];
-
-type date = [number, number, number];
-type time = [number, number];
-type DateIndex = ["phenix", "indexes", "game-date", ...date, ...time];
-
-export class GameService {
- readonly kv: Deno.Kv;
- private readonly DATE_VALIDATOR =
- /^(?\d{4})-(?\d{1,2})-(?\d{1,2})$/;
- private readonly TIME_VALIDATOR = /^(?\d{1,2})(:|h)(?\d{1,2})$/;
- private readonly VALID_TEAMS: string[] = [
- "jaune",
- "rouge",
- "bleu",
- "gris",
- "vert",
- "noir",
- "orange",
- "mauve",
- ];
-
- constructor(kv: Deno.Kv) {
- this.kv = kv;
- }
-
- private chronologicalGameOrder(game1: Game, game2: Game): number {
- if (game1.date < game2.date) {
- return -1;
- }
- if (game1.date > game2.date) {
- return 1;
- }
- if (game1.time < game2.time) {
- return -1;
- }
- if (game1.time > game2.time) {
- return 1;
- }
- return 0;
- }
-
- async getAllGames(): Promise {
- const ite = this.kv.list({ prefix: ["phenix", "games"] });
- return (await Array.fromAsync(ite))
- .map((e) => e.value)
- .sort(this.chronologicalGameOrder);
- }
-
- private gamePrimaryKey(id: string): GamePrimaryKey {
- return ["phenix", "games", id];
- }
-
- private dateIndex(date: string, time: string): DateIndex | null {
- let destructedDate = this.DATE_VALIDATOR.exec(date)?.groups;
- let destructedTime = this.TIME_VALIDATOR.exec(time)?.groups;
-
- if (!destructedDate || !destructedTime) {
- return null;
- }
-
- return [
- "phenix",
- "indexes",
- "game-date",
- parseInt(destructedDate.year),
- parseInt(destructedDate.month),
- parseInt(destructedDate.day),
- parseInt(destructedTime.hour),
- parseInt(destructedTime.minute),
- ];
- }
-
- private cleanTime(raw: string): string {
- const groups = this.TIME_VALIDATOR.exec(raw)!.groups!;
- return `${groups.hour.padStart(2, "0")}:${groups.minute.padStart(2, "0")}`;
- }
-
- private cleanDate(raw: string): string {
- const groups = this.DATE_VALIDATOR.exec(raw)!.groups!;
- return `${groups.year}-${groups.month.padStart(2, "0")}-${groups.day.padStart(2, "0")}`;
- }
-
- private extractYearFromDate(date: string): number {
- return parseInt(this.DATE_VALIDATOR.exec(date)!.groups!.year);
- }
-
- private createGame(preGame: PreGame): Game {
- const ret = {
- ...preGame,
- id: crypto.randomUUID(),
- practice: false,
- rain: false,
- year: this.extractYearFromDate(preGame.date),
- homeScore: null,
- awayScore: null,
- };
- ret.time = this.cleanTime(ret.time);
- ret.date = this.cleanDate(ret.date);
-
- return ret;
- }
-
- private validatePregate(preGame: PreGame): string {
- if (!this.DATE_VALIDATOR.test(preGame.date)) {
- return `Invalide date format ${preGame.date}`;
- }
- if (!this.TIME_VALIDATOR.test(preGame.time)) {
- return `Invalide time format ${preGame.time}`;
- }
- if (!this.VALID_TEAMS.includes(preGame.away)) {
- return `Invalide away format ${preGame.away}`;
- }
- if (!this.VALID_TEAMS.includes(preGame.home)) {
- return `Invalide home format ${preGame.home}`;
- }
- if (preGame.home === preGame.away) {
- return `Home and away teams must be different (received ${preGame.home} for both)`;
- }
- return "";
- }
-
- async createNewGame(preGame: PreGame): Promise<[Game | null, string]> {
- if (this.validatePregate(preGame) !== "") {
- return [null, this.validatePregate(preGame)];
- }
- const game = this.createGame(preGame);
- const dateIndex = this.dateIndex(game.date, game.time);
- if (!dateIndex) {
- return [null, "Cound not parse date or time"];
- }
- const precondition = await this.kv.get(dateIndex);
- if (precondition.value !== null) {
- return [null, "game already exists " + precondition.value];
- }
-
- const res = await this.kv
- .atomic()
- .check(precondition)
- .set(this.gamePrimaryKey(game.id), game)
- .set(dateIndex, game.id)
- .commit();
- if (!res.ok) {
- return [null, "Transaction failed"];
- }
-
- return [game, ""];
- }
-
- async getGameById(id: string): Promise {
- const res = await this.kv.get(this.gamePrimaryKey(id));
- return res.value;
- }
-
- async deleteGameById(id: string): Promise {
- const precond = await this.kv.get(this.gamePrimaryKey(id));
- if (precond.value === null) {
- return false;
- }
-
- const res = await this.kv
- .atomic()
- .check(precond)
- .delete(this.gamePrimaryKey(precond.value.id))
- .delete(this.dateIndex(precond.value.date, precond.value.time)!)
- .commit();
- return res.ok;
- }
-
- async switchVisitors(id: string): Promise {
- const game = await this.getGameById(id);
- if (game === null) {
- return false;
- }
- game.id = "";
- const [home, away] = [game.home, game.away];
- const [homeScore, awayScore] = [game.homeScore, game.awayScore];
- game.home = away;
- game.away = home;
- game.homeScore = awayScore;
- game.awayScore = homeScore;
- console.log(`game ${game}`);
-
- return this.updateGame(id, game);
- }
-
- async updateGame(id: string, partial: Partial): Promise {
- delete partial.id;
- const precond = await this.kv.get(this.gamePrimaryKey(id));
- if (precond.value === null) {
- return false;
- }
- const res = await this.kv
- .atomic()
- .check(precond)
- .delete(this.gamePrimaryKey(precond.value.id))
- .delete(this.dateIndex(precond.value.date, precond.value.time)!)
- .set(
- this.dateIndex(precond.value.date, precond.value.time)!,
- precond.value.id,
- )
- .set(this.gamePrimaryKey(precond.value.id), {
- ...precond.value,
- ...partial,
- })
- .commit();
- return res.ok;
- }
-}
-
-Deno.test("saving simple games", async (t) => {
- const kv = await Deno.openKv();
- const service = new GameService(kv);
-
- async function deleteAllKeys() {
- const keys = kv.list({ prefix: [] });
- for await (const entry of keys) {
- await kv.delete(entry.key);
- }
- }
-
- function validePreGame(seed: number): PreGame {
- let year = ((645 * seed + 162) % 10000) + 1;
- let month = ((335 * seed + 71) % 12) + 1;
- let day = ((72625 * seed + 176) % 28) + 1;
- return {
- date: `${(year + "").padStart(4, "0")}-${(month + "").padStart(2, "0")}-${(day + "").padStart(2, "0")}`,
- time: "18:45",
- away: "jaune",
- home: "rouge",
- };
- }
-
- await deleteAllKeys();
-
- await t.step("creating games", async () => {
- const preGame = validePreGame(7276);
- const [game, error] = await service.createNewGame(preGame);
- assertEquals(error, "");
- const ret = await service.getGameById(game!.id);
- assertEquals(game, ret);
- });
-
- await deleteAllKeys();
-
- await t.step("creating games with old date format", async () => {
- const preGame = validePreGame(7276);
- preGame.date = "2017-8-5";
- const [game, error] = await service.createNewGame(preGame);
- assertEquals(error, "");
- assertEquals(game?.date, "2017-08-05");
- });
-
- await deleteAllKeys();
-
- await t.step("creating games with old time format", async () => {
- const preGame = validePreGame(7276);
- preGame.time = "9:00";
- const [game, error] = await service.createNewGame(preGame);
- assertEquals(error, "");
- assertEquals(game?.time, "09:00");
- });
-
- await deleteAllKeys();
-
- await t.step(
- "saving two games in the same timeslot should fail",
- async () => {
- const preGame = validePreGame(7276);
- let [_, error] = await service.createNewGame(preGame);
- assertEquals(error, "");
- [_, error] = await service.createNewGame(preGame);
- assertNotEquals(error, "");
- },
- );
-
- await deleteAllKeys();
-
- await t.step("saving games with bad fields", async () => {
- let i = 0;
- for (const key of Object.keys(validePreGame(7276))) {
- let [_, error] = await service.createNewGame({
- ...validePreGame(7262 + i),
- [key]: `Broken ${key}`,
- });
- assertNotEquals(error, "");
- i++;
- }
- });
-
- await t.step("saving games with the same home and away teams", async () => {
- const preGame = validePreGame(7276);
- preGame.home = preGame.away;
- let [_, error] = await service.createNewGame(preGame);
- assertNotEquals(error, "");
- });
-
- await deleteAllKeys();
-
- await t.step("listing games", async () => {
- for (let i = 0; i < 10; i++) {
- await service.createNewGame(validePreGame(666 + i));
- }
- assertEquals((await service.getAllGames()).length, 10);
- });
-
- await deleteAllKeys();
-
- await t.step("deleting games", async () => {
- let [game, error] = await service.createNewGame(validePreGame(8992));
- await service.deleteGameById(game!.id);
- assertEquals((await service.getAllGames()).length, 0);
-
- [game, error] = await service.createNewGame(validePreGame(8992));
- assertEquals(error, "");
- });
-
- await deleteAllKeys();
-
- await t.step("updating game scores", async () => {
- let [game, _] = await service.createNewGame(validePreGame(8992));
- const ret = await service.updateGame(game!.id, {
- homeScore: 10,
- awayScore: 32,
- });
- assertEquals(ret, true);
- game = await service.getGameById(game!.id);
- assertEquals(game!.homeScore, 10);
- assertEquals(game!.awayScore, 32);
- });
-
- await deleteAllKeys();
- await kv.close();
-});
diff --git a/server/login-service.ts b/server/login-service.ts
deleted file mode 100644
index 203f74f..0000000
--- a/server/login-service.ts
+++ /dev/null
@@ -1,116 +0,0 @@
-import {
- assert,
- assertFalse,
-} from "https://deno.land/std@0.224.0/assert/mod.ts";
-
-type User = { username: string; passwordHashWithSalt: string };
-
-const officialUsers: User[] = [
- {
- username: "marqueur",
- passwordHashWithSalt:
- "34373780cc542a1eddb6a08488ec149323b94d66025421acd98ffc20eb5055a0:6f2fa05777d45a2da9db79b7fd11e3bc69eb1807642ccb53d41a0b9eb71a3311",
- },
- {
- username: "comite",
- passwordHashWithSalt:
- "8649feff48a50f53448e59ce480db97b5549eef1d92c886c49b5a14ee22648e5:a0017b879c8834d2f34938e7a4fa3f4c7be8f70545b9bb22a28cf56ab2eb26d9",
- },
-];
-
-export class LoginService {
- private readonly users: User[];
- private readonly sessionKey: string;
-
- constructor(users: User[], sessionKey: string) {
- this.users = users;
- this.sessionKey = sessionKey;
- }
-
- public static officialLoginService(): LoginService {
- return new LoginService(
- officialUsers,
- Deno.env.get("SESSION_KEY") || "dev-only",
- );
- }
-
- private async hashMessage(message: string): Promise {
- const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array
- const hashBuffer = await crypto.subtle.digest("SHA-256", msgUint8); // hash the message
- const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array
- const hashHex = hashArray
- .map((b) => b.toString(16).padStart(2, "0"))
- .join(""); // convert bytes to hex string
- return hashHex;
- }
-
- private async shittyHmac(message: string, salt: string): Promise {
- const h1 = await this.hashMessage(message + salt);
- const h2 = await this.hashMessage(salt + message);
- return await this.hashMessage(h1 + h2);
- }
-
- async hashPassword(password: string): Promise {
- const salt = await this.hashMessage(`${Math.random()}`);
- const hash = await this.shittyHmac(password, salt);
- return `${salt}:${hash}`;
- }
-
- async verifyPassword(
- password: string,
- passwordHashWithSalt: string,
- ): Promise {
- const [passwordSalt, passwordHash] = passwordHashWithSalt.split(":");
- return passwordHash === (await this.shittyHmac(password, passwordSalt));
- }
-
- async validateCredentials(
- username: string,
- password: string,
- ): Promise {
- for (const user of this.users) {
- if (user.username === username) {
- return this.verifyPassword(password, user.passwordHashWithSalt);
- }
- }
- return false;
- }
-
- async login(ctx: any): Promise {
- const nDays = 90;
- const maxAgesInSecond = nDays * 24 * 3600;
- const maxUnixEpoch = Math.floor(Date.now() / 1000) + maxAgesInSecond;
-
- await ctx.cookies.set("phenix-session", `${maxUnixEpoch}`, {
- maxAge: maxAgesInSecond,
- });
- await ctx.cookies.set(
- "phenix-session-sign",
- await this.shittyHmac(`${maxUnixEpoch}`, this.sessionKey),
- {
- maxAge: maxAgesInSecond,
- },
- );
- }
-
- async isLoggedIn(ctx: any): Promise {
- const expiration = await ctx.cookies.get("phenix-session");
- const signature = await ctx.cookies.get("phenix-session-sign");
- if (signature !== (await this.shittyHmac(expiration, this.sessionKey))) {
- return false;
- }
- if (!expiration || !/^\d+$/.test(expiration)) {
- return false;
- }
- return Date.now() < parseInt(expiration) * 1000;
- }
-}
-
-Deno.test("login service", async (t) => {
- await t.step("hashing password", async () => {
- const service = new LoginService([], "ss");
- const passwordHashWithSalt = await service.hashPassword("qwerty");
- assert(await service.verifyPassword("qwerty", passwordHashWithSalt));
- assertFalse(await service.verifyPassword("ytrewq", passwordHashWithSalt));
- });
-});
diff --git a/server/types.ts b/server/types.ts
deleted file mode 100644
index 3a34157..0000000
--- a/server/types.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export type Game = {
- id: string;
- date: string;
- time: string;
- home: string;
- away: string;
- year: number;
- homeScore: number | null;
- awayScore: number | null;
- practice: boolean;
- rain: boolean;
-};
-
-export type PreGame = {
- date: string;
- time: string;
- home: string;
- away: string;
-};
diff --git a/templates/calendrier.vto b/templates/calendrier.vto
deleted file mode 100644
index fa38fa9..0000000
--- a/templates/calendrier.vto
+++ /dev/null
@@ -1,8 +0,0 @@
-{{ layout "templates/container.vto" }}
-
-
-
-
-
-
-{{ /layout }}
diff --git a/templates/contact.vto b/templates/contact.vto
deleted file mode 100644
index 2e6133a..0000000
--- a/templates/contact.vto
+++ /dev/null
@@ -1,35 +0,0 @@
-{{ layout "templates/container.vto" }}
-
-
-
-
-
-
-
- sportsphenixmtl@gmail.com
-
-
-
- (514) 838-8950
-
-
-
-
- 10454 Sylvain-Garneau Montréal, Québec H1C 0A2
-
-
-
-
-
- Le site web est ouvert et accessible sur gitlab.
-
-
-
-
-
-
-{{ /layout }}
diff --git a/templates/container.vto b/templates/container.vto
deleted file mode 100644
index 1b68ee6..0000000
--- a/templates/container.vto
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
-
- Balle Phenix
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ content }}
-
-
-
-
-
diff --git a/templates/home.vto b/templates/home.vto
deleted file mode 100644
index 28359ae..0000000
--- a/templates/home.vto
+++ /dev/null
@@ -1,108 +0,0 @@
-
-{{ layout "templates/container.vto" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ include "templates/includes/home-news.vto" }}
-
-
-
-
-
-
-
-
Parc Walter-Stewart
- {{ include "templates/includes/walter-stewart-map.vto" }}
-
-
-
-
-
-
-
-
-
-
-
- {{ include "templates/includes/home-news.vto" }}
-
-
-
-
-
-
-
-
-
-
Parc Walter-Stewart
- {{ include "templates/includes/walter-stewart-map.vto" }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ include "templates/includes/home-news.vto" }}
-
-
-
-
-
-
-
-
-
-
Parc Walter-Stewart
- {{ include "templates/includes/walter-stewart-map.vto" }}
-
-
-
-
-
-
-
-{{ /layout }}
diff --git a/templates/includes/game-editor.vto b/templates/includes/game-editor.vto
deleted file mode 100644
index 598de98..0000000
--- a/templates/includes/game-editor.vto
+++ /dev/null
@@ -1,72 +0,0 @@
-
-
- {{set prettyGameDate = new Date(game.date).toLocaleString("fr-CA", { month: 'long', year: 'numeric', day: 'numeric', timeZone: 'UTC'}) }}
-
-
-
-
{{ game.away }} vs {{ game.home }} | {{ prettyGameDate }} | {{ game.time }}
-
-
-
- Inverser visiteur/receveur
- Supprimer
-
-
diff --git a/templates/includes/home-news.vto b/templates/includes/home-news.vto
deleted file mode 100644
index b7cb42c..0000000
--- a/templates/includes/home-news.vto
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
Pré-inscription pour la balle-molle Phénix, ça ne coûte rien et c'est sans prix! https://forms.gle/Mv2wCVdbP83uiMdC7
- lire la suite ...
-
diff --git a/templates/includes/team-selector.vto b/templates/includes/team-selector.vto
deleted file mode 100644
index 4c66228..0000000
--- a/templates/includes/team-selector.vto
+++ /dev/null
@@ -1,10 +0,0 @@
-{{ set selectedTeam = selectedTeam || "" }}
-{{set isDisabled = isDisabled || false }}
-{{set teams = ['jaune', 'rouge', 'bleu', 'gris', 'vert', 'noir', 'orange', 'mauve'] }}
-
-
-
-{{ for team of teams }}
- {{ team }}
-{{ /for }}
-
diff --git a/templates/includes/walter-stewart-map.vto b/templates/includes/walter-stewart-map.vto
deleted file mode 100644
index bb0ddcf..0000000
--- a/templates/includes/walter-stewart-map.vto
+++ /dev/null
@@ -1,15 +0,0 @@
-
diff --git a/templates/membre.vto b/templates/membre.vto
deleted file mode 100644
index d56030c..0000000
--- a/templates/membre.vto
+++ /dev/null
@@ -1,28 +0,0 @@
-{{ layout "templates/container.vto" }}
-
-
-{{ /layout }}
diff --git a/templates/nouvelles.vto b/templates/nouvelles.vto
deleted file mode 100644
index 3ce1fe1..0000000
--- a/templates/nouvelles.vto
+++ /dev/null
@@ -1,69 +0,0 @@
-{{ layout "templates/container.vto" }}
-
-
-
-
-
-
- Pré-inscription
-
-
-
Samedi 8 Août 2026
-
-
- La pré-inscription pour la balle-molle Phénix est maintenant ouverte. Ça ne coûte rien et c'est sans prix!
-
-
- https://forms.gle/Mv2wCVdbP83uiMdC7
-
-
-
-
-
-
-
-
-
- Saison 2026
-
-
-
Lundi 9 Mars 2026
-
-
-
-
- La saison de la balle annonce à grand pas et les inscriptions débuteront lundi prochain (16 mars 2026). Le coût de la saison sera le même que l'an passé: 155$ pour la saison + 20$ de dépôt remboursable pour le prêt du chandail.
-
-
- Comme à l'habitude, nous jouerons au parc walter-stewart les jeudis soir. La ligue comptera quatre équipes pour un grand total de 44 joueurs.
-
- Les inscriptions en présentiel auront lieu le vendredi 20 mars au bar fullum entre 18h00 et 21h00. Pour ceux qui veulle venir prendre une petite bière avec nous ou payer en argent compten.
-
- On vous tiens au courrant!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Saison 2025
-
-
-
Vendredi 25 Avril 2025
-
- Bonne saison à tous et toutes!
- N'oubliez pas de consulter la page facebook: https://www.facebook.com/SportsPhenixMtl/ pour toutes mises à jour, y compris les annulations due à la météo.
- Votre Comité 2023
-
-
-
-
-{{ /layout }}
diff --git a/templates/partials/games-editor.vto b/templates/partials/games-editor.vto
deleted file mode 100644
index 4e3d092..0000000
--- a/templates/partials/games-editor.vto
+++ /dev/null
@@ -1,37 +0,0 @@
-{{set isToday = !!isToday }}
-
-
-
-
-
-
- {{ for game of games }}
-
- {{ include "templates/includes/game-editor.vto" {game} }}
-
- {{ /for }}
-
-
-
- Nouvelle Partie
-
-
diff --git a/templates/partials/new-game-error.vto b/templates/partials/new-game-error.vto
deleted file mode 100644
index 7db45f0..0000000
--- a/templates/partials/new-game-error.vto
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/templates/partials/new-games-editor.vto b/templates/partials/new-games-editor.vto
deleted file mode 100644
index f176dd3..0000000
--- a/templates/partials/new-games-editor.vto
+++ /dev/null
@@ -1,45 +0,0 @@
-
diff --git a/templates/partials/single-game-editor.vto b/templates/partials/single-game-editor.vto
deleted file mode 100644
index 907d6ae..0000000
--- a/templates/partials/single-game-editor.vto
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- {{ include "templates/includes/game-editor.vto" {game} }}
-
-
-
diff --git a/templates/reglement.vto b/templates/reglement.vto
deleted file mode 100644
index a81d3b3..0000000
--- a/templates/reglement.vto
+++ /dev/null
@@ -1,42 +0,0 @@
-{{ layout "templates/container.vto" }}
-
-
-
-
-
-
-
Mission
-
La ligue de balle Les Phénix a été fondée en 2004 afin d'offrir aux membres de la communauté gaie et lesbienne et à leurs amis hétéros l'opportunité de s'amuser et de pratiquer un sport dans une ambiance amicale et décontractée. L'ouverture d'esprit, la camaraderie et le plaisir de pratiquer un sport à l'extérieur caractérisent cette ligue.
-
-
-
-{{ /layout }}