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) -![Image Alt](https://gitlab.com/ballephenix/website/raw/master/images/phenix_logo.png) +## 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 }} - -
-
-
Ligue de balle les Phénix... pour le plaisir de jouer! -

Ligue de balle les Phénix

-
- -

-
-
- - - 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" }} -
-
-
-
-
-
-

Calendrier

-
-
-
-
-
-
-

Parc Walter-Stewart

- {{ include "templates/includes/walter-stewart-map.vto" }} -
-
-
- - -
-
-
-
-
-
- {{ include "templates/includes/home-news.vto" }} -
-
-
-
-
-
-

Calendrier

-
-
-
-
-
-
-
-
-

Parc Walter-Stewart

- {{ include "templates/includes/walter-stewart-map.vto" }} -
-
-
-
- - - - - -
-
-
-
-
-
- {{ include "templates/includes/home-news.vto" }} -
-
-
-
-
-
-
-
-

Calendrier

-
-
-
-
-
-
-
-
-
-

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 }}

-
- -
- -
- -
- -
- -
- - - -
- -
-
- -
- -
- - -
-
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

-
-

- -

-

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'] }} - - - 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 @@ -
- - -
- - Voir la carte - -
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 }} - -
- -
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 @@ -
- -
-
{{ error }}
-
- -
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 @@ -
- -
- -
-
-
- - {{ include "templates/includes/team-selector.vto" {name: "away-team"} }} - - {{ include "templates/includes/team-selector.vto" {name: "home-team"}}} - -
- -
- -
- -
- -
- -
- -
- -
- - - - -
- - -
- -
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 }}