From 311cb66cddba8d5a6ac8ba7ddd9f2faf4f0fc4db Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Wed, 21 Aug 2019 22:56:46 +0200 Subject: [PATCH 001/120] Initial commit --- .htaccess | 28 +++ .idea/.gitignore | 6 + .idea/TFJM.iml | 10 + .idea/codeStyles/codeStyleConfig.xml | 5 + .idea/dataSources.xml | 21 ++ .idea/deployment.xml | 15 ++ .idea/misc.xml | 6 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + 403.php | 14 ++ 404.php | 14 ++ index.html | 0 logo.svg | 114 +++++++++ server_files/ajouter_equipe.php | 127 ++++++++++ server_files/ajouter_organisateur.php | 124 ++++++++++ server_files/ajouter_tournoi.php | 217 +++++++++++++++++ server_files/config.php | 60 +++++ server_files/confirmer_mail.php | 26 +++ server_files/connexion.php | 76 ++++++ server_files/deconnexion.php | 14 ++ server_files/equipe.php | 64 +++++ server_files/footer.php | 5 + server_files/header.php | 143 ++++++++++++ server_files/index.php | 114 +++++++++ server_files/inscription.php | 278 ++++++++++++++++++++++ server_files/mon_compte.php | 323 ++++++++++++++++++++++++++ server_files/mon_equipe.php | 200 ++++++++++++++++ server_files/rejoindre_equipe.php | 93 ++++++++ server_files/solutions.php | 115 +++++++++ server_files/solutions_orga.php | 29 +++ server_files/syntheses.php | 109 +++++++++ server_files/syntheses_orga.php | 30 +++ server_files/tournoi.php | 107 +++++++++ server_files/tournois.php | 50 ++++ server_files/view_file.php | 67 ++++++ style.css | 80 +++++++ 36 files changed, 2698 insertions(+) create mode 100644 .htaccess create mode 100644 .idea/.gitignore create mode 100644 .idea/TFJM.iml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/dataSources.xml create mode 100644 .idea/deployment.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 403.php create mode 100644 404.php create mode 100644 index.html create mode 100644 logo.svg create mode 100644 server_files/ajouter_equipe.php create mode 100644 server_files/ajouter_organisateur.php create mode 100644 server_files/ajouter_tournoi.php create mode 100644 server_files/config.php create mode 100644 server_files/confirmer_mail.php create mode 100644 server_files/connexion.php create mode 100644 server_files/deconnexion.php create mode 100644 server_files/equipe.php create mode 100644 server_files/footer.php create mode 100644 server_files/header.php create mode 100644 server_files/index.php create mode 100644 server_files/inscription.php create mode 100644 server_files/mon_compte.php create mode 100644 server_files/mon_equipe.php create mode 100644 server_files/rejoindre_equipe.php create mode 100644 server_files/solutions.php create mode 100644 server_files/solutions_orga.php create mode 100644 server_files/syntheses.php create mode 100644 server_files/syntheses_orga.php create mode 100644 server_files/tournoi.php create mode 100644 server_files/tournois.php create mode 100644 server_files/view_file.php create mode 100644 style.css diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..7f2d8b2 --- /dev/null +++ b/.htaccess @@ -0,0 +1,28 @@ +ErrorDocument 403 /tfjm/403.php +ErrorDocument 404 /tfjm/404.php + +Options +FollowSymlinks +# Options -Indexes +RewriteEngine On +RewriteOptions Inherit +RewriteBase /tfjm +RewriteRule index.html accueil [L] +RewriteRule ^accueil$ server_files/index.php [L] +RewriteRule ^ajouter_equipe$ server_files/ajouter_equipe.php [L] +RewriteRule ^ajouter_organisateur$ server_files/ajouter_organisateur.php [L] +RewriteRule ^ajouter_tournoi$ server_files/ajouter_tournoi.php [L] +RewriteRule ^confirmer_mail/(.*?)$ server_files/confirmer_mail.php?token=$1 [L] +RewriteRule ^connexion$ server_files/connexion.php [L] +RewriteRule ^deconnexion$ server_files/deconnexion.php [L] +RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] +RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] +RewriteRule ^inscription$ server_files/inscription.php [L] +RewriteRule ^mon_compte$ server_files/mon_compte.php [L] +RewriteRule ^mon_equipe$ server_files/mon_equipe.php [L] +RewriteRule ^rejoindre_equipe$ server_files/rejoindre_equipe.php [L] +RewriteRule ^solutions$ server_files/solutions.php [L] +RewriteRule ^solutions_orga$ server_files/solutions_orga.php [L] +RewriteRule ^syntheses$ server_files/syntheses.php [L] +RewriteRule ^syntheses_orga$ server_files/syntheses_orga.php [L] +RewriteRule ^tournoi/(.*?)$ server_files/tournoi.php?nom=$1 [L] +RewriteRule ^tournois$ server_files/tournois.php [L] diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..0ed6303 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,6 @@ +# Default ignored files +/workspace.xml + +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml \ No newline at end of file diff --git a/.idea/TFJM.iml b/.idea/TFJM.iml new file mode 100644 index 0000000..940f6f9 --- /dev/null +++ b/.idea/TFJM.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..9653190 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,21 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://galaxyoyo.com:3306/tfjm + + + + + + + + + + GMT+1 + + + \ No newline at end of file diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..69e8a41 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..28a804d --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..6fcadc0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/403.php b/403.php new file mode 100644 index 0000000..fab537f --- /dev/null +++ b/403.php @@ -0,0 +1,14 @@ + + +

Vous n'êtes pas autorisé à accéder à cette page.

+ + \ No newline at end of file diff --git a/404.php b/404.php new file mode 100644 index 0000000..54ac204 --- /dev/null +++ b/404.php @@ -0,0 +1,14 @@ + + +

Cette page n'existe pas.

+ + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..e69de29 diff --git a/logo.svg b/logo.svg new file mode 100644 index 0000000..699316b --- /dev/null +++ b/logo.svg @@ -0,0 +1,114 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/server_files/ajouter_equipe.php b/server_files/ajouter_equipe.php new file mode 100644 index 0000000..9dd42ae --- /dev/null +++ b/server_files/ajouter_equipe.php @@ -0,0 +1,127 @@ +query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); + +if (isset($_POST["submitted"])) { + $error_message = registerTournament(); +} + +function registerTournament() { + global $DB, $YEAR, $MAIL_ADDRESS, $access_code; + + if ($_SESSION["team_id"] != NULL) + return "Vous êtes déjà dans une équipe."; + + $name = htmlspecialchars($_POST["name"]); + + if (!isset($name) || $name == "") + return "Vous devez spécifier un nom d'équipe."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe existe déjà avec ce nom."; + + $trigram = htmlspecialchars($_POST["trigram"]); + + if (!preg_match("#[A-Z][A-Z][A-Z]#", $trigram)) + return "Le trigramme entré n'est pas valide."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe a déjà choisi ce trigramme."; + + $tournament_id = intval(htmlspecialchars($_POST["tournament"])); + + $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "Le tournoi spécifié n'existe pas."; + + $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; + $access_code = ""; + for ($i = 0; $i < 6; ++$i) + $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; + + $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?);"); + $result = $req->execute([$name, $trigram, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, + $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + $data_team = $result->fetch(); + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); + + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; + $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; + $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; + $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; + mail($_SESSION["email"], "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

Vous devez être participant ou encadrant pour pouvoir ajouter une équipe.

+ +

Vous êtes déjà dans une équipe.

+ + Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : + + +Erreur : " . $error_message . ""; ?> + +
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ +
+
+ + + + diff --git a/server_files/ajouter_organisateur.php b/server_files/ajouter_organisateur.php new file mode 100644 index 0000000..1146426 --- /dev/null +++ b/server_files/ajouter_organisateur.php @@ -0,0 +1,124 @@ +prepare("SELECT `id` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); + $req->execute([$email]); + if ($req->fetch() !== FALSE) + return "Cette adresse e-mail est déjà utilisée."; + + $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $password = ""; + for ($i = 0; $i < 16; ++$i) + $password .= $alphabet[rand(0, strlen($alphabet) - 1)]; + $hash = password_hash($password, PASSWORD_BCRYPT); + + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) + VALUES (?, ?, ?, ?, ?, ?);"); + $req->execute([$email, $hash, $surname, $first_name, $admin ? "ADMIN" : "ORGANIZER", $YEAR]); + + $msg = "Bonjour " . $first_name . " " . $surname . ",\r\n\r\n" + . "Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM². " + . "Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. " + . "Elles vous permettront de gérer les inscriptions des équipes de votre tournoi.\r\n\r\n" + . "Votre mot de passe est : $password\r\n\r\n" + . "Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer " + . "lors de votre prochaine connexion sur le site.\r\n\r\n" + . "Merci beaucoup pour votre aide !\r\n\r\n" + . "Les organisateurs du TFJM²"; + + mail($email, "Organisateur du TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

Vous n'êtes pas autorisé à accéder à cette page.

+ + + Erreur : " . $error_message . ""; + } else { + echo "

Organisateur ajouté avec succès ! Ses identifiants ont été transmis par mail.

"; + } + }?> + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ +
+
+ + + + diff --git a/server_files/ajouter_tournoi.php b/server_files/ajouter_tournoi.php new file mode 100644 index 0000000..434897f --- /dev/null +++ b/server_files/ajouter_tournoi.php @@ -0,0 +1,217 @@ +query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); + +if (isset($_POST["submitted"])) { + $error_message = registerTournament(); +} + +function registerTournament() { + global $DB, $YEAR, $MAIL_ADDRESS; + + $name = htmlspecialchars($_POST["name"]); + + $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Un tournoi existe déjà avec ce nom."; + + try { + $organizer_id = intval(htmlspecialchars($_POST["organizer"])); + } + catch (Exception $ex) { + return "Un problème a eu lieu concernant le choix de l'organisateur. Merci de ne pas formuler vous-même vos requêtes."; + } + + $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $organizer_id . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "L'organisateur spécifié n'existe pas."; + if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") + return "L'organisateur indiqué ne peut pas organiser de tournoi."; + $organize_mail = $data["email"]; + + try { + $size = intval(htmlspecialchars($_POST["size"])); + } + catch (Exception $ex) { + return "Le nombre d'équipes indiqué n'est pas un entier valide."; + } + + if ($size < 3 || $size > 12) + return "Un tournoi doit comporter entre 3 et 12 équipes."; + + $place = htmlspecialchars($_POST["place"]); + + try { + $price = intval(htmlspecialchars($_POST["price"])); + } + catch (Throwable $t) { + return "Le tarif pour les participants n'est pas un nombre valide."; + } + + if ($price < 0) + return "Le TFJM² ne va pas payer les élèves pour venir."; + + if ($price > 50) + return "Soyons raisonnable sur le prix."; + + $date_start = htmlspecialchars($_POST["date_start"]); + $date_start_parsed = date_parse_from_format("yyyy-mm-dd", $date_start); + + $date_end = htmlspecialchars($_POST["date_end"]); + $date_end_parsed = date_parse_from_format("yyyy-mm-dd", $date_end); + + $date_inscription = htmlspecialchars($_POST["date_inscription"]); + $time_inscription = htmlspecialchars($_POST["time_inscription"]); + $date_inscription_parsed = date_parse_from_format("yyyy-mm-dd", $date_inscription . ' ' . $time_inscription); + + $date_solutions = htmlspecialchars($_POST["date_solutions"]); + $time_solutions = htmlspecialchars($_POST["time_solutions"]); + $date_solutions_parsed = date_parse_from_format("yyyy-mm-dd", $date_solutions . ' ' . $time_solutions); + + $date_syntheses = htmlspecialchars($_POST["date_syntheses"]); + $time_syntheses = htmlspecialchars($_POST["time_syntheses"]); + $date_syntheses_parsed = date_parse_from_format("yyyy-mm-dd", $date_syntheses . ' ' . $time_syntheses); + + if (!$date_start_parsed || !$date_end_parsed || !$date_inscription_parsed || !$date_solutions_parsed || !$date_syntheses_parsed) + return "Une date est mal formée."; + + $description = htmlspecialchars($_POST["description"]); + + $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `organizer`, `size`, `place`, `description`, + `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + $result = $req->execute([$name, $organizer_id, $size, $place, $description, $date_start, $date_end, + "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $YEAR]); + + mail($organize_mail, "Organisateur TFJM² " . $name, "Vous venez d'être promu organisateur du tournoi " . $name . " pour le TFJM² $YEAR !", "From: $MAIL_ADDRESS"); + + return false; +} + +?> + + + + +

Vous n'êtes pas autorisé à accéder à cette page.

+ + +Erreur : " . $error_message . ""; + } else { + echo "

Tournoi de " . htmlspecialchars($_POST["name"]) . " ajouté avec succès !

"; + } + }?> + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + Du au +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ +
+
+ + + + diff --git a/server_files/config.php b/server_files/config.php new file mode 100644 index 0000000..1ecd6c0 --- /dev/null +++ b/server_files/config.php @@ -0,0 +1,60 @@ + PDO::ERRMODE_EXCEPTION)); +} +catch (Exception $ex) { + die("Erreur lors de la connexion à la base de données : " . $ex->getMessage()); +} + +session_start(); + +if (isset($_SESSION["user_id"])) { + $response = $DB->query("SELECT * FROM `users` WHERE `id` ='" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); + $data = $response->fetch(); + if ($data === FALSE) + unset($_SESSION["user_id"]); + else { + $_SESSION["email"] = $data["email"]; + $_SESSION["surname"] = $data["surname"]; + $_SESSION["first_name"] = $data["first_name"]; + $_SESSION["birth_date"] = $data["birth_date"]; + $_SESSION["role"] = $data["role"]; + $_SESSION["team_id"] = $data["team_id"]; + } + + if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"]) && $_SESSION["team_id"] != NULL) { + $response = $DB->query("SELECT `tournament`, `validation_status` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $data = $response->fetch(); + $_SESSION["tournament_id"] = $data["tournament"]; + $_SESSION["team_validation_status"] = $data["validation_status"]; + } +} + +setlocale(LC_ALL, "fr_FR.utf8"); + +function echo_date($date = NULL, $with_time = false) { + if ($date == NULL) + $date = date("yyyy-mm-dd"); + + return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); +} + +?> diff --git a/server_files/confirmer_mail.php b/server_files/confirmer_mail.php new file mode 100644 index 0000000..951d5b4 --- /dev/null +++ b/server_files/confirmer_mail.php @@ -0,0 +1,26 @@ +query("SELECT `email` FROM `users` WHERE `confirm_email` = '$token' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + $error_message = "Le jeton est invalide. Votre compte est peut-être déjà validé ?"; + else { + $DB->exec("UPDATE `users` SET `confirm_email` = NULL WHERE `confirm_email` = '$token';"); + $error_message = "Votre adresse mail a été validée ! Vous pouvez désormais vous connecter."; + } +} +else { + $error_message = "Il n'y a pas de compte à valider !"; +} + +?> + + + +

+ + \ No newline at end of file diff --git a/server_files/connexion.php b/server_files/connexion.php new file mode 100644 index 0000000..e6bcefc --- /dev/null +++ b/server_files/connexion.php @@ -0,0 +1,76 @@ +query("SELECT `id`, `pwd_hash`, `email`, `surname`, `first_name`, `role`, `team_id` FROM `users` WHERE `email` = '" . $email . "';"); + if (($data = $result->fetch()) === FALSE) + return "Le compte n'existe pas."; + + if (!password_verify($password, $data["pwd_hash"])) + return "Le mot de passe est incorrect."; + + $_SESSION["user_id"] = $data["id"]; + $_SESSION["email"] = $data["email"]; + $_SESSION["surname"] = $data["surname"]; + $_SESSION["first_name"] = $data["first_name"]; + $_SESSION["role"] = $data["role"]; + $_SESSION["team_id"] = $data["team_id"]; + + $response = $DB->query("SELECT `tournament`, `validation_status` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $data = $response->fetch(); + $_SESSION["tournament_id"] = $data["tournament"]; + $_SESSION["team_validation_status"] = $data["validation_status"]; + + return false; +} + +?> + + + +Erreur : " . $error_message . ""; ?> + + + Connexion réussie ! + + +

Vous êtes déjà connecté !

+ + + +
+ + + + + + + + + + + + + +
+
+ + + + diff --git a/server_files/deconnexion.php b/server_files/deconnexion.php new file mode 100644 index 0000000..31b50ac --- /dev/null +++ b/server_files/deconnexion.php @@ -0,0 +1,14 @@ + + + + +

Déconnexion réussie !

+ + diff --git a/server_files/equipe.php b/server_files/equipe.php new file mode 100644 index 0000000..4298a5f --- /dev/null +++ b/server_files/equipe.php @@ -0,0 +1,64 @@ +query("SELECT * FROM `teams` WHERE `trigram` = '$trigram';")->fetch(); + +$tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); + +$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `type` ORDER BY `user`, `type` ASC, `uploaded_at` DESC;"); +$documents_req->execute([$team_data["id"]]); + +?> + + + +

Informations sur l'équipe

+ +Nom de l'équipe :
+Trigramme :
+Tournoi :
+query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; +} +for ($i = 1; $i <= 6; ++$i) { + if ($team_data["participant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; +} +?> + +

Autorisations

+ +fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $user_id = $data["user"]; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); + $surname = $user_data["surname"]; + $first_name = $user_data["first_name"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name de $first_name $surname : Télécharger
"; +} +?> + + diff --git a/server_files/footer.php b/server_files/footer.php new file mode 100644 index 0000000..0289fab --- /dev/null +++ b/server_files/footer.php @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/server_files/header.php b/server_files/header.php new file mode 100644 index 0000000..48a0933 --- /dev/null +++ b/server_files/header.php @@ -0,0 +1,143 @@ +exec("UPDATE `users` SET `role` = 'ADMIN' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_SESSION["user_id"]) && isset($_GET["be-organizer"])) { + $DB->exec("UPDATE `users` SET `role` = 'ORGANIZER' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_SESSION["user_id"]) && isset($_GET["be-participant"])) { + $DB->exec("UPDATE `users` SET `role` = 'PARTICIPANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_SESSION["user_id"]) && isset($_GET["be-encadrant"])) { + $DB->exec("UPDATE `users` SET `role` = 'ENCADRANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +function quitTeam() { + global $DB, $URL_BASE; + + if ($_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") + return; + + for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); + for ($i = 1; $i <= 5; ++$i) { + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); + } + + $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + + if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { + $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); + + $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); + } + unset($_SESSION["team_id"]); + unset($_SESSION["team_validation_status"]); +} + +?> + + + + + + + Site d'inscription pour le TFJM² <?= $YEAR ?> + + + + + + + + + + + + + + + + + + +
+
+ +
\ No newline at end of file diff --git a/server_files/index.php b/server_files/index.php new file mode 100644 index 0000000..39fe89d --- /dev/null +++ b/server_files/index.php @@ -0,0 +1,114 @@ + + + + +
+ + + + + +
+ + +
+ + +

Vous souhaitez participer au tournoi ? Votre équipe est déjà formée ?

+

Créez un compte pour commencer la procédure d'inscription ou connectez-vous si votre équipe a déjà un compte.

+
+ +
+ +
+

Bienvenue sur le site d'inscription du TFJM2 !

+
+ +
+ Ce site a été conçu pour gérer les inscriptions au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens. +
+ Cliquez ici pour accéder au site de présentation du tournoi. +
+ +
+ + +

+ Attention aux échéances ! Chaque tournoi a une date limite pour les inscriptions et une date limite pour déposer vos solutions. Elles sont affichées avec les informations de chaque tournoi. Merci de vous y référer ! +
+ Une fois l'échéance passée, le site bloque tout accès aux inscriptions (et respectivement au dépôt des solutions).
+

+ +

+ Attention, modification du règlement par rapport aux années précédentes : article 4.3 +
+ "l’équipe doit envoyer par mail à contact@tfjm.org, une lettre (au format pdf), répondant aux questions suivantes : +
+ +

    +
  • Comment l’équipe s’est-elle formée ?
  • +
  • Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres avec l’encadrant•e) ?
  • +
+ + Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non l’inscription des équipes concernées par cette lettre." +
+ + Pour plus de détail, voir le règlement : https://tfjm.org/infos-tournois/ +

+ + +
+

Comment ça marche ?

+
+ +

+ Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer par la suite. +

+ +

+ Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : +

    +
  • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
  • +
  • enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière version enregistrée avant + la date limite sera prise en compte pour le tournoi).
  • +
+ + Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, votre inscription pourra être validée par les organisateurs locaux. +

+ + +

ATTENTION ! Votre équipe ne sera considérée comme admissible à participer au tournoi que lorsque cette première étape aura été franchie.

+ +

Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes seront placées en liste d'attente. +

+ +

+ Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers le site pour compléter votre inscription. +

+ + +

ATTENTION ! Les équipes qui ne respecteront pas les délais pour rendre ces documents risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente.

+ +

+ NB : Ce site est récent et il est encore possible que certaines pages ne fonctionnent pas correctement. Si vous remarquez des bugs, merci de les signaler à l'adresse contact@tfjm.org. +

+ + + + + + + + + +
+ + \ No newline at end of file diff --git a/server_files/inscription.php b/server_files/inscription.php new file mode 100644 index 0000000..a2e85b4 --- /dev/null +++ b/server_files/inscription.php @@ -0,0 +1,278 @@ +query("SELECT `email` FROM `users` WHERE `email` = '" . $email . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Un compte existe déjà avec cette adresse e-mail."; + + $password = htmlspecialchars($_POST["password"]); + if (strlen($password) < 8) + return "Le mot de passe doit comporter au moins 8 caractères."; + if ($password != $_POST["confirm_password"]) + return "Les deux mots de passe sont différents."; + + $password = password_hash($password, PASSWORD_BCRYPT); + + $surname = strtoupper(htmlspecialchars($_POST["surname"])); + if (!isset($surname) || $surname == "") + return "Le nom de famille est obligatoire."; + + $firstname = htmlspecialchars($_POST["firstname"]); + if (!isset($surname) || $surname == "") + return "Le prénom est obligatoire."; + + $birth_date = date_parse_from_format("yyyy-mm-dd", htmlspecialchars($_POST["birth_date"])); + + if ($birth_date === FALSE) + return "La date de naissance est invalide."; + + if (htmlspecialchars($_POST["birth_date"]) >= $YEAR . "-01-01") + return "Vous devez avoir un âge strictement positif. Date de naissance rentrée : " . htmlspecialchars($_POST["birth_date"]); + + $gender = htmlspecialchars($_POST["gender"]); + + if (!isset($gender) || ($gender != "M" && $gender != "F")) + return "Le sexe indiqué est invalide."; + + $address = htmlspecialchars($_POST["address"]); + + if (!isset($address)) + $address = ""; + + try { + $postal_code = intval($_POST["postal_code"]); + if ($postal_code < 1000 || $postal_code > 95999) + return "Le code postal est invalide."; + } + catch (Exception $ex) { + return "Le code postal n'est pas un nombre valide."; + } + + $city = htmlspecialchars($_POST["city"]); + + if (!isset($city)) + $city = ""; + + $country = htmlspecialchars($_POST["country"]); + + if (!isset($country)) + $country = "France"; + + $phone_number = htmlspecialchars($_POST["phone_number"]); + + if (!isset($phone_number) || $phone_number == "") + return "Vous devez renseigner un numéro de téléphone."; + + $role = htmlspecialchars($_POST["role"]); + + if (!isset($role) || ($role != "participant" && $role != "encadrant")) + return "Le rôle entré n'est pas valide."; + + $role = strtoupper($role); + + $school = htmlspecialchars($_POST["school"]); + $class = strtoupper(htmlspecialchars($_POST["class"])); + $responsible_name = htmlspecialchars($_POST["responsible_name"]); + $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); + $responsible_email = htmlspecialchars($_POST["responsible_email"]); + + if ($role == "ENCADRANT") { + $school = NULL; + $class = NULL; + $responsible_name = NULL; + $responsible_phone = NULL; + $responsible_email = NULL; + } + else { + if (!isset($class) && $class != "TERMINALE" && $class != "PREMIERE" && $class != "SECONDE") + return "La classe spécifiée est invalide. Merci de ne pas créer vos propres requêtes."; + + if ((!isset($responsible_name) || $responsible_name == "") && $birth_date > strval($YEAR - 18) . "-05-01") + return "Veuillez spécifier un nom de responsable légal."; + + if ((!isset($responsible_phone) || $responsible_phone == "") && (!isset($responsible_email) || !filter_var($responsible_email, FILTER_VALIDATE_EMAIL)) + && $birth_date > strval($YEAR - 18) . "-05-01") + return "Veuillez préciser au moins le numéro de téléphone ou l'addresse e-mail de votre responsable légal."; + } + + $description = $_POST["description"]; + + if ($role == "PARTICIPANT") + $description = NULL; + + $confirm_email_uid = uniqid(); + + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, + `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + $req->execute([$email, $password, $confirm_email_uid, $surname, $firstname, $_POST["birth_date"], $gender, $address, $postal_code, + $city, $country, $phone_number, $school, $class, $role, $description, $YEAR]); + + $msg = "Merci pour votre inscription au TFJM² $YEAR ! Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; + mail($email, "Inscription au TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + Erreur : " . $error_message . ""; ?> + + + Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. + + +

Vous êtes déjà connecté !

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
" />
+
" />
+
+ + + + + + diff --git a/server_files/mon_compte.php b/server_files/mon_compte.php new file mode 100644 index 0000000..d4dba41 --- /dev/null +++ b/server_files/mon_compte.php @@ -0,0 +1,323 @@ +query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "';"); + $user_data = $result->fetch(); +} + +function updateAccount() +{ + global $DB, $URL_BASE, $MAIL_ADDRESS; + + if (!isset($_SESSION["user_id"])) + return "Vous n'êtes pas connecté."; + + $ID = $_SESSION["user_id"]; + + $surname = htmlspecialchars($_POST["surname"]); + if (isset($surname) && $surname != "") + $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $ID]); + + $first_name = htmlspecialchars($_POST["firstname"]); + if (isset($first_name) && $first_name != "") + $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $ID]); + + $birth_date = htmlspecialchars($_POST["birth_date"]); + if (isset($birth_date) && $birth_date != "") + $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $ID]); + + if (isset($_POST["gender"])) { + $gender = htmlspecialchars($_POST["gender"]); + if (isset($gender) && ($gender == "M" || $gender == "F")) + $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $ID]); + } + + $address = htmlspecialchars($_POST["address"]); + if (isset($address) && $address != "") + $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $ID]); + + $postal_code = htmlspecialchars($_POST["postal_code"]); + if (isset($postal_code) && $postal_code != "") + $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $ID]); + + $city = htmlspecialchars($_POST["city"]); + if (isset($city) && $city != "") + $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $ID]); + + $country = htmlspecialchars($_POST["country"]); + if (isset($country) && $country != "") + $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $ID]); + + $phone_number = htmlspecialchars($_POST["phone_number"]); + if (isset($phone_number) && $phone_number != "") + $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $ID]); + + if (isset($_POST["school"])) { + $school = htmlspecialchars($_POST["school"]); + if (isset($school) && $school != "") + $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $ID]); + } + + if (isset($_POST["class"])) { + $class = htmlspecialchars($_POST["class"]); + if (isset($class) && ($class == "terminale" || $class == "premiere" || $class == "seconde")) + $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([strtoupper($class), $ID]); + } + + if (isset($_POST["responsible_name"])) { + $responsible_name = htmlspecialchars($_POST["responsible_name"]); + if (isset($responsible_name) && $responsible_name != "") + $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $ID]); + } + + if (isset($_POST["responsible_phone"])) { + $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); + if (isset($responsible_phone) && $responsible_phone != "") + $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $ID]); + } + + if (isset($_POST["responsible_email"])) { + $responsible_email = htmlspecialchars($_POST["responsible_email"]); + if (isset($responsible_email) && $responsible_email != "") + $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $ID]); + } + + if (isset($_POST["description"])) { + $description = htmlspecialchars($_POST["description"]); + if (isset($description) && $description != "") + $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$description, $ID]); + } + + $email = htmlspecialchars($_POST["email"]); + if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { + $confirm_email_uid = uniqid(); + $DB->prepare("UPDATE `users` SET `email` = ?, `confirm_email` = ? WHERE `id` = ?;")->execute([$email, $confirm_email_uid, $ID]); + + $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; + mail($email, "Changement d'adresse mail - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + } + + return false; +} + +function updatePassword() +{ + global $DB, $YEAR; + + $old = htmlspecialchars($_POST["old_password"]); + $new = htmlspecialchars($_POST["new_password"]); + $confirm = htmlspecialchars($_POST["confirm_password"]); + + $result = $DB->query("SELECT `pwd_hash` FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + return "Le compte n'existe pas."; + + if (!password_verify($old, $data["pwd_hash"])) + return "L'ancien mot de passe est incorrect."; + + if (strlen($new) < 8) + return "Le mot de passe doit comporter au moins 8 caractères."; + + if ($new != $confirm) + return "Les deux mots de passe sont différents."; + + $hash = password_hash($new, PASSWORD_BCRYPT); + + $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$hash, $_SESSION["user_id"]]); + + return false; +} + +?> + + + +Vous devez être connecté pour afficher cette page."; + include "footer.php"; + return; +} ?> + +Erreur : " . $error_message . ""; ?> + + +

Votre compte a bien été mis à jour !

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/> + />
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php new file mode 100644 index 0000000..c29fd22 --- /dev/null +++ b/server_files/mon_equipe.php @@ -0,0 +1,200 @@ +exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); + for ($i = 1; $i <= 5; ++$i) { + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); + } + + $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + + if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { + $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); + + $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); + } + unset($_SESSION["team_id"]); + unset($_SESSION["team_validation_status"]); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_POST["send_document"])) { + sendDocument(); +} + +if (isset($_POST["request_validation"])) { + $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); + $_SESSION["team_validation_status"] = "WAITING"; +} + +if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { + $result = $DB->query("SELECT * FROM `teams` WHERE `id` = '" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $team_data = $result->fetch(); + + $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); + + $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? GROUP BY `type` ORDER BY `type` ASC, `uploaded_at` DESC;"); + $documents_req->execute([$_SESSION["user_id"]]); +} + +function sendDocument() { + global $LOCAL_PATH, $DB; + + $type = strtoupper(htmlspecialchars($_POST["type"])); + if (!isset($type) || ($type != "PARENTAL_CONSENT" && $type != "PHOTO_CONSENT" && $type != "SANITARY_PLUG")) + return "Le type de document est invalide. Merci de ne pas formuler vos propres requêtes."; + + $file = $_FILES["document"]; + + if ($file["size"] > 5000000 || $file["error"]) + return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; + + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') + return "Le fichier doit être au format PDF."; + + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) + return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; + + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) + return "Une erreur est survenue lors de l'envoi du fichier."; + + $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `tournament`, `type`) + VALUES (?, ?, ?, ?, ?);"); + $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION["tournament_id"], $type]); + + return false; +} + +?> + + + +Vous devez être dans une équipe pour afficher cette page."; + include "footer.php"; + return; +} ?> + +Erreur : " . $error_message . ""; + } + else { + echo "

Le fichier a été correctement envoyé !

"; + } +}?> + +

Informations sur l'équipe

+ +Nom de l'équipe :
+Trigramme :
+Tournoi :
+query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; +} +for ($i = 1; $i <= 6; ++$i) { + if ($team_data["participant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; +} +?> +Code d'accès : + + +
+

Mes autorisations

+ fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name : Télécharger
"; + } + ?> + +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+
+ +
+
+ +
+ + + diff --git a/server_files/rejoindre_equipe.php b/server_files/rejoindre_equipe.php new file mode 100644 index 0000000..0463f5a --- /dev/null +++ b/server_files/rejoindre_equipe.php @@ -0,0 +1,93 @@ +query("SELECT * FROM `teams` WHERE `access_code` = '" . $access_code . "' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + return "Ce code d'accès est invalide."; + + if ($_SESSION["role"] != "PARTICIPANT" && $_SESSION["role"] != "ENCADRANT") + return "Seuls les participants et les encadrants peuvent rejoindre une équipe."; + + if ($data["validation_status"] != "NOT_READY") + return "Cette équipe est déjà en cours de validation ou validée, vous ne pouvez pas la rejoindre."; + + for ($i = 1; $i <= $_SESSION["role"] == "PARTICIPANT" ? 6 : 2; ++$i) { + if ($data[strtolower($_SESSION["role"]) . "_" . strval($i)] == NULL) + break; + } + + if ($_SESSION["role"] == "PARTICIPANT" && $i == 7 || $_SESSION["role"] == "ENCADRANT" && $i == 3) + return "Il n'y a plus de place pour vous dans l'équipe."; + + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data["id"]]); + /** @noinspection SqlResolve */ + $DB->prepare("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_" . strval($i) . "` = ? WHERE `id` = " . $data["id"] . ";")->execute([$_SESSION["user_id"]]); + + $_SESSION["team_id"] = $data["id"]; + $_SESSION["team_validation_status"] = $data["validation_status"]; + + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; + $msg .= "Vous venez de rejoindre l'équipe « " . $data["name"] . " » (" . $data["trigram"] . ") pour le TFJM² de " . $data["name"] . " et nous vous en remercions.\r\n\r\n"; + $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; + mail($_SESSION["email"], "Équipe rejointe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

+ + Vous avez bien rejoint l'équipe ! + +

Vous êtes déjà dans une équipe.

+ + +Erreur : " . $error_message . ""; ?> + +
+ + + + + + + + + + + +
+ + + +
+ +
+
+ + + + diff --git a/server_files/solutions.php b/server_files/solutions.php new file mode 100644 index 0000000..d243f31 --- /dev/null +++ b/server_files/solutions.php @@ -0,0 +1,115 @@ +prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? GROUP BY `problem` ORDER BY `problem` ASC, `uploaded_at` DESC;"); +$solutions_req->execute([$_SESSION["team_id"]]); + +function saveSolution() { + global $LOCAL_PATH, $DB; + + try { + $problem = $_POST["problem"]; + if ($problem < 1 || $problem > 9) + return "Le numéro de problème est invalide."; + } + catch (Throwable $t) { + return "Le numéro de problème n'est pas valide. Merci de ne pas créer vos propres requêtes."; + } + + $file = $_FILES["solution"]; + + if ($file["size"] > 5000000 || $file["error"]) + return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; + + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') + return "Le fichier doit être au format PDF."; + + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) + return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; + + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) + return "Une erreur est survenue lors de l'envoi du fichier."; + + $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) + VALUES (?, ?, ?, ?);"); + $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $problem]); + + return false; +} + +?> + + + +Erreur : " . $error_message . ""; + } else { + echo "

Le fichier a été correctement envoyé !

"; + } +}?> + +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ +
+ +

Solutions soumises :

+ +fetch()) !== false) { + $file_id = $data["file_id"]; + $problem = $data["problem"]; + $version = $data["version"]; + echo "Problème $problem (Version $version) : Télécharger
"; +} +?> + + diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php new file mode 100644 index 0000000..58b67df --- /dev/null +++ b/server_files/solutions_orga.php @@ -0,0 +1,29 @@ + + + + +query("SELECT `id`, `name` FROM `tournaments` WHERE " + . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") + . "`year` = $YEAR ORDER BY `name`;"); + +while (($data_tournament = $req->fetch()) !== false) { + echo "

Tournoi de " . $data_tournament["name"] . "

\n"; + $id = $data_tournament["id"]; + $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + while (($data_file = $files_req->fetch()) !== false) { + $file_id = $data_file["file_id"]; + $problem = $data_file["problem"]; + $version = $data_file["version"]; + $team_id = $data_file["team"]; + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); + $team_name = $team_data["name"]; + $team_trigram = $team_data["trigram"]; + echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
"; + } +} + +?> + + diff --git a/server_files/syntheses.php b/server_files/syntheses.php new file mode 100644 index 0000000..377825f --- /dev/null +++ b/server_files/syntheses.php @@ -0,0 +1,109 @@ +prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? GROUP BY `dest` ORDER BY `dest` ASC, `uploaded_at` DESC;"); +$syntheses_req->execute([$_SESSION["team_id"]]); + +function saveSynthese() { + global $LOCAL_PATH, $DB; + + $dest = strtoupper(htmlspecialchars($_POST["dest"])); + + if (!isset($dest) || ($dest != "OPPOSANT" && $dest != "RAPPORTEUR")) + return "Le destinataire est invalide."; + + $file = $_FILES["synthese"]; + + if ($file["size"] > 5000000 || $file["error"]) + return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; + + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') + return "Le fichier doit être au destmat PDF."; + + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) + return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; + + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) + return "Une erreur est survenue lors de l'envoi du fichier."; + + $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) + VALUES (?, ?, ?, ?);"); + $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $dest]); + + return false; +} + +?> + + + +Erreur : " . $error_message . ""; + } + else { + echo "

Le fichier a été correctement envoyé !

"; + } +}?> + +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ +
+ +

Notes de synthèse soumises :

+ +fetch()) !== false) { + $file_id = $data["file_id"]; + $dest = $data["dest"]; + $version = $data["version"]; + echo "Note de synthèse pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . " (Version $version) : Télécharger
"; +} +?> + + diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php new file mode 100644 index 0000000..348b6e6 --- /dev/null +++ b/server_files/syntheses_orga.php @@ -0,0 +1,30 @@ + + + + +query("SELECT `id`, `name` FROM `tournaments` WHERE " + . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") + . "`year` = $YEAR ORDER BY `name`;"); + +while (($data_tournament = $req->fetch()) !== false) { + echo "

Tournoi de " . $data_tournament["name"] . "

\n"; + $id = $data_tournament["id"]; + $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + while (($data_file = $files_req->fetch()) !== false) { + $file_id = $data_file["file_id"]; + $dest = $data_file["dest"]; + $version = $data_file["version"]; + $team_id = $data_file["team"]; + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); + $team_name = $team_data["name"]; + $team_trigram = $team_data["trigram"]; + echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") + . ", version $version : Télécharger
"; + } +} + +?> + + diff --git a/server_files/tournoi.php b/server_files/tournoi.php new file mode 100644 index 0000000..b0780eb --- /dev/null +++ b/server_files/tournoi.php @@ -0,0 +1,107 @@ +prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year` = $YEAR;"); +$response->execute([$tournament_name]); +$data = $response->fetch(); + +$orga_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $data["organizer"] . " AND `year` = $YEAR;")->fetch(); +$orga_name = $orga_data["first_name"] . " " . $orga_data["surname"]; + +$teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); + +?> + + + +

Tournoi de

+ + Organisateur :
+ Nombre d'équipes maximal :
+ Lieu :
+ Prix par partipant :
+ Dates : Du au
+ Clôture des inscriptions :
+ Date limite d'envoi des solutions :
+ Date limite d'envoi des notes de synthèse :
+ Description : + +

Équipes inscrites à ce tournoi :

+ + + + + + + + + + + + fetch()) != false) { + ?> + + + + + + + + + + + + + + + + +
+ Équipe + + Trigramme + + Date d'inscription + + État de validation de l'inscription +
+ " . $team_data["name"] . ""; + else + echo $team_data["name"]; + ?> + + +
+ Équipe + + Trigramme + + Date d'inscription + + État de validation de l'inscription +
+ + \ No newline at end of file diff --git a/server_files/tournois.php b/server_files/tournois.php new file mode 100644 index 0000000..a5b04fb --- /dev/null +++ b/server_files/tournois.php @@ -0,0 +1,50 @@ +query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` + WHERE `year` = '$YEAR' ORDER BY `date_start`, `name`;"); + +?> + + + +

Liste des tournois

+ + + + + + + + + + + + + fetch()) !== FALSE) { + ?> + + + + + + + + + + + + + + + + + + +
LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
">Du au
LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
+ + \ No newline at end of file diff --git a/server_files/view_file.php b/server_files/view_file.php new file mode 100644 index 0000000..81c3432 --- /dev/null +++ b/server_files/view_file.php @@ -0,0 +1,67 @@ +query("SELECT * FROM `solutions` WHERE `file_id` = '$id';"); +if (($data = $req->fetch()) === false) { + $req = $DB->query("SELECT * FROM `syntheses` WHERE `file_id` = '$id';"); + $type = "SYNTHESE"; + + if (($data = $req->fetch()) === false) { + $req = $DB->query("SELECT * FROM `documents` WHERE `file_id` = '$id';"); + $type = "DOCUMENT"; + $data = $req->fetch(); + } +} +print_r($type); +if ($data !== false) { + $team_data = $DB->query("SELECT `trigram` FROM `teams` WHERE `id` = " . $data["team"] . ";")->fetch(); + $tournament_data = $DB->query("SELECT `name` FROM `tournaments` WHERE `id` = " . $data["tournament"] . ";")->fetch(); + $trigram = $team_data["trigram"]; + if ($type == "SOLUTION") { + $problem = $data["problem"]; + $name = "Problème $problem $trigram.pdf"; + } + else if ($type == "SYNTHESE") { + $dest = $data["dest"]; + $name = "Note de synthèse $trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"; + } + else if ($type == "DOCUMENT") { + $user_id = $data["user"]; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = 'user';")->fetch(); + $surname = $user_data["surname"]; + $first_name = $user_data["first_name"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + $name .= " de $first_name $surname.pdf"; + } +} +else { + include_once "404.php"; + http_response_code(404); + exit(); +} + +header("Content-Type: application/pdf"); +header("Content-Disposition: inline; filename=\"$name\""); + +readfile("$URL_BASE/files/$id"); + +exit(); \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..c3f206e --- /dev/null +++ b/style.css @@ -0,0 +1,80 @@ +body { + display: flex; +} + +html, body { + height: 100%; + width: 100%; + margin: 0; +} + +#menu { + list-style-type: none; + margin: 0; + padding: 0; + width: 200px; + background-color: #f1f1f1; + height: 100%; + overflow: auto; + flex-grow: 0; +} + +#menu a { + display: block; + color: #000; + padding: 10px 20px; + text-decoration: none; +} + +#menu a.active { + background-color: #4CAF50; + color: white; +} + +#menu a:hover:not(.active) { + background-color: #555; + color: white; +} + +#menu-logo img { + width: calc(100% - 40px); + margin: 40px auto; + display: block; +} + +#main-container { + margin: 0; + flex-grow: 1; + height: 100%; + overflow-y: scroll; +} + +#main-content { + padding-top: 100px; + padding-bottom: 100px; + margin: 0 auto; + max-width: 800px; + text-align: justify; +} + +@media only screen and (max-width: 700px) { + body { + flex-direction: column; + height: auto; + } + #menu { + height: auto; + width: 100%; + padding-bottom: 20px; + } + #menu-logo img { + height: 70px; + padding-left: 7px; + } + #menu a { + text-align: center; + } + #main-content { + padding: 100px 16px; + } +} From 4604ddd758697e1fc5c8963370caf085ac664ab4 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 24 Aug 2019 11:45:18 +0200 Subject: [PATCH 002/120] =?UTF-8?q?Les=20organisateurs=20peuvent=20valider?= =?UTF-8?q?=20une=20=C3=A9quipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/equipe.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/server_files/equipe.php b/server_files/equipe.php index 4298a5f..478d7d1 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -4,13 +4,19 @@ include "config.php"; $trigram = htmlspecialchars($_GET["trigram"]); -$team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram';")->fetch(); +if (isset($_POST["validate"])) { + $DB->exec("UPDATE `teams` SET `validation_status` = 'VALIDATED' WHERE `trigram` = '$trigram' AND `year` = $YEAR;"); +} + +$team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND `year` = $YEAR;")->fetch(); $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); $documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `type` ORDER BY `user`, `type` ASC, `uploaded_at` DESC;"); $documents_req->execute([$team_data["id"]]); + + ?> @@ -61,4 +67,12 @@ while (($data = $documents_req->fetch()) !== false) { } ?> + +
+ +
+ + From 1f186b43f7eb3b86afc0fffd7a6dc7bd4ef5c9c1 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Mon, 26 Aug 2019 12:16:39 +0200 Subject: [PATCH 003/120] =?UTF-8?q?Possibilit=C3=A9=20de=20modifier=20nom?= =?UTF-8?q?=20et=20trigramme=20d'une=20=C3=A9quipe=20avant=20validation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .htaccess | 2 +- server_files/ajouter_equipe.php | 42 +++++++------- server_files/mon_equipe.php | 97 ++++++++++++++++++++++++++++++++- 3 files changed, 118 insertions(+), 23 deletions(-) diff --git a/.htaccess b/.htaccess index 7f2d8b2..bde2839 100644 --- a/.htaccess +++ b/.htaccess @@ -17,7 +17,7 @@ RewriteRule ^deconnexion$ server_files/deconnexion.php [L] RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] RewriteRule ^inscription$ server_files/inscription.php [L] -RewriteRule ^mon_compte$ server_files/mon_compte.php [L] +RewriteRule ^mon_equipe/(.*?)$ server_files/mon_equipe.php?$1 [L] RewriteRule ^mon_equipe$ server_files/mon_equipe.php [L] RewriteRule ^rejoindre_equipe$ server_files/rejoindre_equipe.php [L] RewriteRule ^solutions$ server_files/solutions.php [L] diff --git a/server_files/ajouter_equipe.php b/server_files/ajouter_equipe.php index 9dd42ae..b0bc049 100644 --- a/server_files/ajouter_equipe.php +++ b/server_files/ajouter_equipe.php @@ -5,27 +5,27 @@ include 'config.php'; $tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); if (isset($_POST["submitted"])) { - $error_message = registerTournament(); + $error_message = registerTeam(); } -function registerTournament() { +function registerTeam() { global $DB, $YEAR, $MAIL_ADDRESS, $access_code; - + if ($_SESSION["team_id"] != NULL) return "Vous êtes déjà dans une équipe."; $name = htmlspecialchars($_POST["name"]); - + if (!isset($name) || $name == "") return "Vous devez spécifier un nom d'équipe."; - + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); if ($result->fetch()) return "Une équipe existe déjà avec ce nom."; - $trigram = htmlspecialchars($_POST["trigram"]); - - if (!preg_match("#[A-Z][A-Z][A-Z]#", $trigram)) + $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); + + if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) return "Le trigramme entré n'est pas valide."; $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); @@ -44,15 +44,15 @@ function registerTournament() { for ($i = 0; $i < 6; ++$i) $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; - $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?);"); - $result = $req->execute([$name, $trigram, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, + $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); + $req->execute([$name, $trigram, $tournament_id, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); - + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); $data_team = $result->fetch(); $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); - + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; @@ -81,14 +81,14 @@ if (!isset($_SESSION["role"]) or ($_SESSION["role"] != "PARTICIPANT" && $_SESSIO
- +
- - @@ -96,7 +96,7 @@ if (!isset($_SESSION["role"]) or ($_SESSION["role"] != "PARTICIPANT" && $_SESSIO @@ -104,7 +104,7 @@ if (!isset($_SESSION["role"]) or ($_SESSION["role"] != "PARTICIPANT" && $_SESSIO - diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php index c29fd22..3e00703 100644 --- a/server_files/mon_equipe.php +++ b/server_files/mon_equipe.php @@ -35,6 +35,8 @@ if (isset($_POST["leave_team"])) { exit(); } +$tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); + if (isset($_POST["send_document"])) { sendDocument(); } @@ -54,6 +56,10 @@ if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { $documents_req->execute([$_SESSION["user_id"]]); } +if (isset($_POST["team_edit"])) { + $error_message = updateTeam(); +} + function sendDocument() { global $LOCAL_PATH, $DB; @@ -92,6 +98,46 @@ function sendDocument() { return false; } +function updateTeam() { + global $DB, $YEAR, $URL_BASE, $MAIL_ADDRESS, $team_data; + + if ($_SESSION["team_id"] == NULL) + return "Vous n'êtes pas dans une équipe."; + + $name = htmlspecialchars($_POST["name"]); + + if (!isset($name) || $name == "") + return "Vous devez spécifier un nom d'équipe."; + + echo $team_data["id"]; + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `id` != " . $team_data["id"] . " AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe existe déjà avec ce nom." . $team_data["id"]; + + $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); + + if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) + return "Le trigramme entré n'est pas valide."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `id` != '" . $team_data["id"] . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe a déjà choisi ce trigramme."; + + $tournament_id = intval(htmlspecialchars($_POST["tournament"])); + + $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "Le tournoi spécifié n'existe pas."; + + $req = $DB->prepare("UPDATE `teams` SET `name` = ?, `trigram` = ?, `tournament` = ? WHERE `id` = ?;"); + $req->execute([$name, $trigram, $tournament_id, $team_data["id"]]); + + header("Location: $URL_BASE/mon_equipe"); + + return false; +} + ?> @@ -130,9 +176,57 @@ for ($i = 1; $i <= 6; ++$i) { echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; } ?> -Code d'accès : +Code d'accès :
+ + + + + +
+ - + +
- +
- fetch()) !== FALSE) { echo "\n"; @@ -114,8 +114,8 @@ if (!isset($_SESSION["role"]) or ($_SESSION["role"] != "PARTICIPANT" && $_SESSIO
- + +
+ + + + + + + + + + + + + + + + + +
+ + + " /> +
+ + + " /> +
+ + + +
+ +
+
+ + + Modifier mon équipe

Mes autorisations

+ From 369fb4fd5b2127a07471f8b8081edc493b3b4889 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Mon, 26 Aug 2019 12:18:51 +0200 Subject: [PATCH 004/120] =?UTF-8?q?La=20page=20"mon=20compte"=20n'=C3=A9ta?= =?UTF-8?q?it=20pas=20accessible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .htaccess | 1 + 1 file changed, 1 insertion(+) diff --git a/.htaccess b/.htaccess index bde2839..4f6016d 100644 --- a/.htaccess +++ b/.htaccess @@ -17,6 +17,7 @@ RewriteRule ^deconnexion$ server_files/deconnexion.php [L] RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] RewriteRule ^inscription$ server_files/inscription.php [L] +RewriteRule ^mon_compte$ server_files/mon_compte.php [L] RewriteRule ^mon_equipe/(.*?)$ server_files/mon_equipe.php?$1 [L] RewriteRule ^mon_equipe$ server_files/mon_equipe.php [L] RewriteRule ^rejoindre_equipe$ server_files/rejoindre_equipe.php [L] From 2272a8b45df4f5012f7c4acef0080ac22dc0074a Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Mon, 26 Aug 2019 16:27:55 +0200 Subject: [PATCH 005/120] =?UTF-8?q?Possibilit=C3=A9=20de=20t=C3=A9l=C3=A9c?= =?UTF-8?q?harger=20une=20archive=20des=20solutions=20et=20notes=20de=20sy?= =?UTF-8?q?nth=C3=A8se=20pour=20les=20organisateurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/solutions_orga.php | 48 +++++++++++++++++++++++++++++++++ server_files/syntheses_orga.php | 48 ++++++++++++++++++++++++++++++++- server_files/view_file.php | 2 +- 3 files changed, 96 insertions(+), 2 deletions(-) diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php index 58b67df..c464893 100644 --- a/server_files/solutions_orga.php +++ b/server_files/solutions_orga.php @@ -1,5 +1,45 @@ +query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + + $zip = new ZipArchive(); + + $temp = tempnam("tmp", "tfjm-"); + + if ($zip->open($temp, ZipArchive::CREATE) !== true) { + die("Impossible de créer le fichier zip."); + } + + while (($data_file = $files_req->fetch()) !== false) { + $file_id = $data_file["file_id"]; + $problem = $data_file["problem"]; + $version = $data_file["version"]; + $team_id = $data_file["team"]; + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); + $team_name = $team_data["name"]; + $team_trigram = $team_data["trigram"]; + + $zip->addFile("$LOCAL_PATH/files/$file_id", "Problème $problem $team_trigram.pdf"); + } + + $zip->close(); + + header("Content-Type: application/zip"); + header("Content-Disposition: attachment; filename=\"Solutions du tournoi de $tournament_name.zip\""); + header("Content-Length: " . strval(filesize($temp) + 1)); + + readfile($temp); + + exit(); +} + +?> + fetch()) !== false) { $team_trigram = $team_data["trigram"]; echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
"; } + + ?> +
+ + " /> + +
+ diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php index 348b6e6..a2adc23 100644 --- a/server_files/syntheses_orga.php +++ b/server_files/syntheses_orga.php @@ -1,5 +1,45 @@ +query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + + $zip = new ZipArchive(); + + $temp = tempnam("tmp", "tfjm-"); + + if ($zip->open($temp, ZipArchive::CREATE) !== true) { + die("Impossible de créer le fichier zip."); + } + + while (($data_file = $files_req->fetch()) !== false) { + $file_id = $data_file["file_id"]; + $dest = $data_file["dest"]; + $version = $data_file["version"]; + $team_id = $data_file["team"]; + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); + $team_name = $team_data["name"]; + $team_trigram = $team_data["trigram"]; + + $zip->addFile("$LOCAL_PATH/files/$file_id", "Note de synthèse $team_trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"); + } + + $zip->close(); + + header("Content-Type: application/zip"); + header("Content-Disposition: attachment; filename=\"Notes de syntèses du tournoi de $tournament_name.zip\""); + header("Content-Length: " . strval(filesize($temp) + 1)); + + readfile($temp); + + exit(); +} + +?> + fetch()) !== false) { echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ", version $version : Télécharger
"; } + ?> +
+ + " /> + +
+ diff --git a/server_files/view_file.php b/server_files/view_file.php index 81c3432..3acf2fe 100644 --- a/server_files/view_file.php +++ b/server_files/view_file.php @@ -21,7 +21,7 @@ if (($data = $req->fetch()) === false) { $data = $req->fetch(); } } -print_r($type); + if ($data !== false) { $team_data = $DB->query("SELECT `trigram` FROM `teams` WHERE `id` = " . $data["team"] . ";")->fetch(); $tournament_data = $DB->query("SELECT `name` FROM `tournaments` WHERE `id` = " . $data["tournament"] . ";")->fetch(); From 7a81d09b88b4c00271eb25c62341eb727660960d Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Mon, 26 Aug 2019 16:51:07 +0200 Subject: [PATCH 006/120] =?UTF-8?q?Ajout=20d'un=20s=C3=A9parateur=20horizo?= =?UTF-8?q?ntal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/equipe.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server_files/equipe.php b/server_files/equipe.php index 478d7d1..73d2993 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -15,8 +15,6 @@ $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WH $documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `type` ORDER BY `user`, `type` ASC, `uploaded_at` DESC;"); $documents_req->execute([$team_data["id"]]); - - ?> @@ -41,6 +39,8 @@ for ($i = 1; $i <= 6; ++$i) { } ?> +
+

Autorisations

Date: Mon, 26 Aug 2019 20:14:29 +0200 Subject: [PATCH 007/120] Organisateurs multiples, modification des tournois --- .htaccess | 1 + server_files/ajouter_tournoi.php | 78 ++++---- server_files/solutions_orga.php | 4 +- server_files/syntheses_orga.php | 4 +- server_files/tournoi.php | 293 +++++++++++++++++++++++++++---- 5 files changed, 310 insertions(+), 70 deletions(-) diff --git a/.htaccess b/.htaccess index 4f6016d..ac61a1f 100644 --- a/.htaccess +++ b/.htaccess @@ -25,5 +25,6 @@ RewriteRule ^solutions$ server_files/solutions.php [L] RewriteRule ^solutions_orga$ server_files/solutions_orga.php [L] RewriteRule ^syntheses$ server_files/syntheses.php [L] RewriteRule ^syntheses_orga$ server_files/syntheses_orga.php [L] +RewriteRule ^tournoi/(.*?)/(.*?)$ server_files/tournoi.php?nom=$1&$2 [L] RewriteRule ^tournoi/(.*?)$ server_files/tournoi.php?nom=$1 [L] RewriteRule ^tournois$ server_files/tournois.php [L] diff --git a/server_files/ajouter_tournoi.php b/server_files/ajouter_tournoi.php index 434897f..829edee 100644 --- a/server_files/ajouter_tournoi.php +++ b/server_files/ajouter_tournoi.php @@ -17,20 +17,21 @@ function registerTournament() { if ($result->fetch()) return "Un tournoi existe déjà avec ce nom."; - try { - $organizer_id = intval(htmlspecialchars($_POST["organizer"])); - } - catch (Exception $ex) { - return "Un problème a eu lieu concernant le choix de l'organisateur. Merci de ne pas formuler vous-même vos requêtes."; - } + if (!isset($_POST["organizer"]) || sizeof($_POST["organizer"]) == 0) + return "Aucun organisateur n'a été choisi."; - $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $organizer_id . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) - return "L'organisateur spécifié n'existe pas."; - if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") - return "L'organisateur indiqué ne peut pas organiser de tournoi."; - $organize_mail = $data["email"]; + $organizers = $_POST["organizer"]; + $orga_mails = []; + + foreach ($organizers as $orga) { + $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $orga . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "L'organisateur spécifié n'existe pas."; + if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") + return "L'organisateur indiqué ne peut pas organiser de tournoi."; + $orga_mails[] = $data["email"]; + } try { $size = intval(htmlspecialchars($_POST["size"])); @@ -80,13 +81,22 @@ function registerTournament() { $description = htmlspecialchars($_POST["description"]); - $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `organizer`, `size`, `place`, `description`, + $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `size`, `place`, `price`, `description`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `year`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $result = $req->execute([$name, $organizer_id, $size, $place, $description, $date_start, $date_end, + $req->execute([$name, $size, $place, $price, $description, $date_start, $date_end, "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $YEAR]); - mail($organize_mail, "Organisateur TFJM² " . $name, "Vous venez d'être promu organisateur du tournoi " . $name . " pour le TFJM² $YEAR !", "From: $MAIL_ADDRESS"); + $req = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '$name' AND `year` = $YEAR;"); + $tournament_id = $req->fetch()["id"]; + + foreach ($organizers as $orga) { + $req = $DB->prepare("INSERT INTO `organizers`(`organizer`, `tournament`) VALUES(?, ?);"); + $req->execute([$orga, $tournament_id]); + } + + foreach ($orga_mails as $orga_mail) + mail($orga_mail, "Organisateur TFJM² " . $name, "Vous venez d'être promu organisateur du tournoi " . $name . " pour le TFJM² $YEAR !", "From: $MAIL_ADDRESS"); return false; } @@ -112,14 +122,14 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") {
- +
- - @@ -127,7 +137,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -149,7 +159,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -157,7 +167,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -165,7 +175,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -173,8 +183,8 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -182,8 +192,8 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -191,8 +201,8 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { @@ -200,12 +210,12 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { - diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php index c464893..041fd32 100644 --- a/server_files/solutions_orga.php +++ b/server_files/solutions_orga.php @@ -44,9 +44,9 @@ if (isset($_POST["download_zip"])) { query("SELECT `id`, `name` FROM `tournaments` WHERE " +$req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR ORDER BY `name`;"); + . "`year` = $YEAR GROUP BY `tournament` ORDER BY `name`;"); while (($data_tournament = $req->fetch()) !== false) { echo "

Tournoi de " . $data_tournament["name"] . "

\n"; diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php index a2adc23..91d69a4 100644 --- a/server_files/syntheses_orga.php +++ b/server_files/syntheses_orga.php @@ -44,9 +44,9 @@ if (isset($_POST["download_zip"])) { query("SELECT `id`, `name` FROM `tournaments` WHERE " +$req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR ORDER BY `name`;"); + . "`year` = $YEAR GROUP BY `tournament` ORDER BY `name`;"); while (($data_tournament = $req->fetch()) !== false) { echo "

Tournoi de " . $data_tournament["name"] . "

\n"; diff --git a/server_files/tournoi.php b/server_files/tournoi.php index b0780eb..5110c18 100644 --- a/server_files/tournoi.php +++ b/server_files/tournoi.php @@ -8,18 +8,129 @@ $response = $DB->prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year $response->execute([$tournament_name]); $data = $response->fetch(); -$orga_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $data["organizer"] . " AND `year` = $YEAR;")->fetch(); -$orga_name = $orga_data["first_name"] . " " . $orga_data["surname"]; +$orgas_req = $DB->query("SELECT `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); +$orgas = []; +while (($orga_data = $orgas_req->fetch()) !== false) { + $orgas[] = $orga_data["first_name"] . " " . $orga_data["surname"]; +} + +if (isset($_POST["edit_tournament"])) { + $error_message = updateTournament(); +} $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); +$orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); + +function updateTournament() { + global $DB, $URL_BASE, $YEAR, $MAIL_ADDRESS, $data; + + $tournament_id = $data["id"]; + + $name = htmlspecialchars($_POST["name"]); + + $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `id` != $tournament_id AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Un tournoi existe déjà avec ce nom."; + + if (!isset($_POST["organizer"]) || sizeof($_POST["organizer"]) == 0) + return "Aucun organisateur n'a été choisi."; + + if ($_SESSION["role"] == "ADMIN") { + $organizers = $_POST["organizer"]; + $orga_mails = []; + + foreach ($organizers as $orga) { + $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $orga . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "L'organisateur spécifié n'existe pas."; + if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") + return "L'organisateur indiqué ne peut pas organiser de tournoi."; + $orga_mails[] = $data["email"]; + } + } + + try { + $size = intval(htmlspecialchars($_POST["size"])); + } + catch (Exception $ex) { + return "Le nombre d'équipes indiqué n'est pas un entier valide."; + } + + if ($size < 3 || $size > 12) + return "Un tournoi doit comporter entre 3 et 12 équipes."; + + $place = htmlspecialchars($_POST["place"]); + + try { + $price = intval(htmlspecialchars($_POST["price"])); + } + catch (Throwable $t) { + return "Le tarif pour les participants n'est pas un nombre valide."; + } + + if ($price < 0) + return "Le TFJM² ne va pas payer les élèves pour venir."; + + if ($price > 50) + return "Soyons raisonnable sur le prix."; + + $date_start = htmlspecialchars($_POST["date_start"]); + $date_start_parsed = date_parse_from_format("yyyy-mm-dd", $date_start); + + $date_end = htmlspecialchars($_POST["date_end"]); + $date_end_parsed = date_parse_from_format("yyyy-mm-dd", $date_end); + + $date_inscription = htmlspecialchars($_POST["date_inscription"]); + $time_inscription = htmlspecialchars($_POST["time_inscription"]); + $date_inscription_parsed = date_parse_from_format("yyyy-mm-dd", $date_inscription . ' ' . $time_inscription); + + $date_solutions = htmlspecialchars($_POST["date_solutions"]); + $time_solutions = htmlspecialchars($_POST["time_solutions"]); + $date_solutions_parsed = date_parse_from_format("yyyy-mm-dd", $date_solutions . ' ' . $time_solutions); + + $date_syntheses = htmlspecialchars($_POST["date_syntheses"]); + $time_syntheses = htmlspecialchars($_POST["time_syntheses"]); + $date_syntheses_parsed = date_parse_from_format("yyyy-mm-dd", $date_syntheses . ' ' . $time_syntheses); + + if (!$date_start_parsed || !$date_end_parsed || !$date_inscription_parsed || !$date_solutions_parsed || !$date_syntheses_parsed) + return "Une date est mal formée."; + + $description = htmlspecialchars($_POST["description"]); + + $req = $DB->prepare("UPDATE `tournaments` SET `name` = ?, `size` = ?, `place` = ?, `price` = ?, `description` = ?, + `date_start` = ?, `date_end` = ?, `date_inscription` = ?, `date_solutions` = ?, `date_syntheses` = ? + WHERE `id` = $tournament_id;"); + $req->execute([$name, $size, $place, $price, $description, $date_start, $date_end, + "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses"]); + + if ($_SESSION["role"] == "ADMIN") { + $DB->exec("DELETE FROM `organizers` WHERE `tournament` = $tournament_id;"); + foreach ($organizers as $orga) { + $req = $DB->prepare("INSERT INTO `organizers`(`organizer`, `tournament`) VALUES(?, ?);"); + $req->execute([$orga, $tournament_id]); + } + } + + header("Location: $URL_BASE/tournoi/" . $name); + exit(); +} + ?>

Tournoi de

- Organisateur :
+ Organisateur= 2 ? 's' : '' ?> : + +
Nombre d'équipes maximal :
Lieu :
Prix par partipant :
@@ -27,7 +138,12 @@ $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date` Clôture des inscriptions :
Date limite d'envoi des solutions :
Date limite d'envoi des notes de synthèse :
- Description : + Description :
+ + + /modifier">Éditer le tournoi + +

Équipes inscrites à ce tournoi :

@@ -49,42 +165,42 @@ $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date` - fetch()) != false) { - ?> + fetch()) != false) { + ?> - + @@ -104,4 +220,117 @@ $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`
+ - + +
- fetch()) !== FALSE) { echo "\n"; @@ -141,7 +151,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { - +
- +
- +
- Du au + Du au
- - + +
- - + +
- - + +
- +
- + +
- " . $team_data["name"] . ""; - else - echo $team_data["name"]; - ?> + " . $team_data["name"] . ""; + else + echo $team_data["name"]; + ?> - +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + " required /> +
+ + + +
+ + + " required /> +
+ + + " required /> +
+ + + " required /> +
+ + + Du " required /> + au " required /> +
+ + + " required /> + " required /> +
+ + + " required /> + " required /> +
+ + + " required /> + " required /> +
+ + + +
+ +
+
+ + \ No newline at end of file From c3de4a9914594719094e39686cd33a0b982da5df Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Wed, 28 Aug 2019 00:28:07 +0200 Subject: [PATCH 008/120] =?UTF-8?q?Am=C3=A9liorations=20au=20niveau=20de?= =?UTF-8?q?=20l'inscription?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/connexion.php | 13 ++++++---- server_files/inscription.php | 49 +++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/server_files/connexion.php b/server_files/connexion.php index e6bcefc..189ddae 100644 --- a/server_files/connexion.php +++ b/server_files/connexion.php @@ -56,17 +56,20 @@ if (isset($error_message) && $error_message === FALSE) {
- +
- - + + - + - + + + +
Mot de passe oublié ?
diff --git a/server_files/inscription.php b/server_files/inscription.php index a2e85b4..7e23a59 100644 --- a/server_files/inscription.php +++ b/server_files/inscription.php @@ -8,6 +8,7 @@ if (isset($_POST["submitted"])) { function register() { global $DB, $YEAR, $URL_BASE, $MAIL_ADDRESS; + global $email, $firstname, $surname, $birth_date, $gender, $address, $postal_code, $city, $country, $phone_number, $role, $school, $class, $responsible_name, $responsible_phone, $responsible_email; $email = strtolower(htmlspecialchars($_POST["email"])); @@ -145,70 +146,70 @@ function register() {
- +
- - + + - + - + - + - + - + - + - + - + - + - + - + - - + - - + - + - + - + - +
" required />
" required />
" required />
" />" required />
- /> + />
" />
" min="1000" max="95999" required />
" />
" />" required />
" />
" />
" />
" />
" />
@@ -242,6 +243,7 @@ function register() { case "participant": document.getElementById("school_label").style.display = "block"; document.getElementById("school").style.display = "block"; + document.getElementById("school").require = "true"; document.getElementById("class_label").style.display = "block"; document.getElementById("class").style.display = "block"; document.getElementById("responsible_name_label").style.display = "block"; @@ -256,6 +258,7 @@ function register() { case "encadrant": document.getElementById("school_label").style.display = "none"; document.getElementById("school").style.display = "none"; + document.getElementById("school").require = "false"; document.getElementById("class_label").style.display = "none"; document.getElementById("class").style.display = "none"; document.getElementById("responsible_name_label").style.display = "none"; From 0b1c3cb86eafa1d39046236337d7f2fc25a1af82 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 16:39:57 +0200 Subject: [PATCH 009/120] =?UTF-8?q?Ajout=20de=20l'option=20de=20r=C3=A9ini?= =?UTF-8?q?tialisation=20de=20mot=20de=20passe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .htaccess | 2 + server_files/connexion.php | 168 +++++++++++++++++++++++++++++++------ 2 files changed, 146 insertions(+), 24 deletions(-) diff --git a/.htaccess b/.htaccess index ac61a1f..3a134f2 100644 --- a/.htaccess +++ b/.htaccess @@ -13,6 +13,8 @@ RewriteRule ^ajouter_organisateur$ server_files/ajouter_organisateur.php [L] RewriteRule ^ajouter_tournoi$ server_files/ajouter_tournoi.php [L] RewriteRule ^confirmer_mail/(.*?)$ server_files/confirmer_mail.php?token=$1 [L] RewriteRule ^connexion$ server_files/connexion.php [L] +RewriteRule ^connexion/reinitialiser_mdp/(.*?)$ server_files/connexion.php?reset_password&token=$1 [L] +RewriteRule ^connexion/(.*?)$ server_files/connexion.php?$1 [L] RewriteRule ^deconnexion$ server_files/deconnexion.php [L] RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] diff --git a/server_files/connexion.php b/server_files/connexion.php index 189ddae..82d7f18 100644 --- a/server_files/connexion.php +++ b/server_files/connexion.php @@ -6,6 +6,21 @@ if (isset($_POST["submitted"]) && !isset($_SESSION["user_id"])) { $error_message = login(); } +if (isset($_POST["forgotten_password"]) && !isset($_SESSION["user_id"])) { + $error_message = recuperateAccount(); +} + +if (isset($_GET["reset_password"]) && isset($_GET["token"]) && !isset($_SESSION["user_id"])) { + $reset_data = $DB->query("SELECT `id`, `email` FROM `users` WHERE `forgotten_password` = '" . htmlspecialchars($_GET["token"]) . "';")->fetch(); + if ($reset_data === FALSE) { + header("Location: $URL_BASE/connexion"); + exit(); + } + + if (isset($_POST["reset_password"])) + $error_message = resetPassword(); +} + function login() { global $DB, $YEAR; @@ -38,6 +53,53 @@ function login() { return false; } +function recuperateAccount() { + global $DB, $MAIL_ADDRESS, $URL_BASE, $YEAR; + + $email = htmlspecialchars($_POST["email"]); + + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) + return "L'email entrée est invalide."; + + $req = $DB->query("SELECT `id` FROM `users` WHERE `email` = '$email' AND `year` = $YEAR;"); + if (!$req->fetch()) + return "Le compte n'existe pas."; + + $token = uniqid(); + + $DB->exec("UPDATE `users` SET `forgotten_password` = '$token' WHERE `email` = '$email' AND `year` = $YEAR;"); + + $msg = "Bonjour,\r\n\r\n" + . "Vous avez indiqué avoir oublié votre mot de passe. Veuillez cliquer ici pour le réinitialiser : $URL_BASE/connexion/reinitialiser_mdp/$token\r\n\r\n" + . "Si vous n'êtes pas à l'origine de cette manipulation, vous pouvez ignorer ce message.\r\n\r\n" + . "Cordialement,\r\n\r\n" + . "Le comité national d'organisation du TFJM²."; + mail("$email", "Mot de passe oublié - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +function resetPassword() { + global $DB, $MAIL_ADDRESS, $reset_data; + + $id = $reset_data["id"]; + $email = $reset_data["email"]; + $password = htmlspecialchars($_POST["password"]); + $confirm = htmlspecialchars($_POST["confirm_password"]); + + if (strlen($password) < 8) + return "Le mot de passe doit comporter au moins 8 caractères."; + + if ($password != $confirm) + return "Les deux mots de passe sont différents."; + + $hash = password_hash($password, PASSWORD_BCRYPT); + + $DB->prepare("UPDATE `users` SET `pwd_hash` = ?, `forgotten_password` = NULL WHERE `id` = ?;")->execute([$hash, $id]); + + return false; +} + ?> @@ -46,34 +108,92 @@ function login() { - Connexion réussie ! - - + if (isset($_GET["mdp_oublie"])) + echo "Le mail de récupération de mot de passe a bien été envoyé."; + else if (isset($_POST["reset_password"])) + echo "Le mot de passe a bien été changé. Vous pouvez désormais vous connecter."; + else + echo "Connexion réussie !"; + } +else if (isset($_SESSION["user_id"])) { ?>

Vous êtes déjà connecté !

-
- - - - - - - - - - - - - - - - -
Mot de passe oublié ?
-
- + +
+ + + + + + + + + + +
+ + + +
+ +
+
+ +
+ " /> + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ +
+ + + + + + + + + + + + + + + + +
+ + Mot de passe oublié ? +
+
+ + From e9579e7e9434f9093a2a79eecf0087bd812a5e7e Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 17:29:27 +0200 Subject: [PATCH 010/120] =?UTF-8?q?L'adresse=20mail=20doit=20=C3=AAtre=20c?= =?UTF-8?q?onfirm=C3=A9e=20pour=20pouvoir=20se=20connecter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/connexion.php | 52 ++++++++++++++++++++++++++++++++++--- server_files/mon_compte.php | 2 +- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/server_files/connexion.php b/server_files/connexion.php index 82d7f18..8791be3 100644 --- a/server_files/connexion.php +++ b/server_files/connexion.php @@ -21,8 +21,12 @@ if (isset($_GET["reset_password"]) && isset($_GET["token"]) && !isset($_SESSION[ $error_message = resetPassword(); } +if (isset($_GET["confirmation-mail"]) && !isset($_SESSION["user_id"])) { + $error_message = sendConfirmEmail(); +} + function login() { - global $DB, $YEAR; + global $DB, $URL_BASE, $YEAR; $email = htmlspecialchars($_POST["email"]); @@ -31,10 +35,15 @@ function login() { $password = htmlspecialchars($_POST["password"]); - $result = $DB->query("SELECT `id`, `pwd_hash`, `email`, `surname`, `first_name`, `role`, `team_id` FROM `users` WHERE `email` = '" . $email . "';"); + $result = $DB->query("SELECT `id`, `pwd_hash`, `email`, `surname`, `first_name`, `role`, `team_id`, `confirm_email` FROM `users` WHERE `email` = '" . $email . "';"); if (($data = $result->fetch()) === FALSE) return "Le compte n'existe pas."; - + + if ($data["confirm_email"] !== NULL) { + $_SESSION["confirm_email"] = $email; + return "L'adresse mail n'a pas été validée. Veuillez vérifier votre boîte mail (surtout vos spams). Cliquez ici pour renvoyer le mail de confirmation."; + } + if (!password_verify($password, $data["pwd_hash"])) return "Le mot de passe est incorrect."; @@ -97,9 +106,41 @@ function resetPassword() { $DB->prepare("UPDATE `users` SET `pwd_hash` = ?, `forgotten_password` = NULL WHERE `id` = ?;")->execute([$hash, $id]); + $msg = "Bonjour,\r\n\r\nNous vous informons que votre mot de passe vient d'être modifié. " + . "Si vous n'êtes pas à l'origine de cette manipulation, veuillez immédiatement vérifier vos accès à votre boîte mail et changer votre mot de passe sur la plateforme d'inscription.\r\n\r\n" + . "Cordialement,\r\n\r\nLe comité national d'organisation du TFJM²"; + mail($email, "Mot de passe modifié TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + return false; } +function sendConfirmEmail() { + global $DB, $URL_BASE, $MAIL_ADDRESS, $YEAR; + + $email = htmlspecialchars($_SESSION["confirm_email"]); + + if (!isset($email)) { + header("Location: $URL_BASE/connexion"); + exit(); + } + + $data = $DB->query("SELECT `confirm_email` FROM `users` WHERE `email` = '$email' AND `year` = $YEAR;")->fetch(); + + if ($data === FALSE) { + unset($_SESSION["confirm_email"]); + header("Location: $URL_BASE/connexion"); + exit(); + } + + $confirm_email_uid = $data["confirm_email"]; + + $msg = "Bonjour,\r\n\r\nPour confirmer votre adresse mail, cliquez ici : $URL_BASE/confirmer_mail/$confirm_email_uid\r\n\r\n" + . "Cordialement,\r\n\r\nLe comité national d'organisation du TFJM²"; + mail($email, "Confirmation d'adresse mail TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + ?> @@ -112,6 +153,8 @@ if (isset($error_message) && $error_message === FALSE) { echo "Le mail de récupération de mot de passe a bien été envoyé."; else if (isset($_POST["reset_password"])) echo "Le mot de passe a bien été changé. Vous pouvez désormais vous connecter."; + else if (isset($_GET["confirmation-mail"])) + echo "Le mail a bien été renvoyé."; else echo "Connexion réussie !"; } @@ -140,7 +183,7 @@ else if (isset($_SESSION["user_id"])) { ?> - +
" /> @@ -169,6 +212,7 @@ else if (isset($_SESSION["user_id"])) { ?>
+
diff --git a/server_files/mon_compte.php b/server_files/mon_compte.php index d4dba41..35b5e0f 100644 --- a/server_files/mon_compte.php +++ b/server_files/mon_compte.php @@ -154,7 +154,7 @@ if (isset($error_message) && $error_message === FALSE) {

Votre compte a bien été mis à jour !

From 7b678e4683cd08621516c8a4b3d93d335e95d933 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 17:54:29 +0200 Subject: [PATCH 011/120] =?UTF-8?q?Dossier=20server=5Ffiles=20d=C3=A9sorma?= =?UTF-8?q?is=20inaccessible?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .htaccess | 5 ++++- 403.php | 2 ++ 404.php | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.htaccess b/.htaccess index 3a134f2..48a8884 100644 --- a/.htaccess +++ b/.htaccess @@ -2,7 +2,7 @@ ErrorDocument 403 /tfjm/403.php ErrorDocument 404 /tfjm/404.php Options +FollowSymlinks -# Options -Indexes +Options -Indexes RewriteEngine On RewriteOptions Inherit RewriteBase /tfjm @@ -30,3 +30,6 @@ RewriteRule ^syntheses_orga$ server_files/syntheses_orga.php [L] RewriteRule ^tournoi/(.*?)/(.*?)$ server_files/tournoi.php?nom=$1&$2 [L] RewriteRule ^tournoi/(.*?)$ server_files/tournoi.php?nom=$1 [L] RewriteRule ^tournois$ server_files/tournois.php [L] + +RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\ /tfjm/server_files.*? [NC] +RewriteRule ^server_files.*?$ - [R=404] diff --git a/403.php b/403.php index fab537f..8c11b98 100644 --- a/403.php +++ b/403.php @@ -3,6 +3,8 @@ include "server_files/config.php"; include "server_files/header.php"; +http_response_code(403); + ?>

Vous n'êtes pas autorisé à accéder à cette page.

diff --git a/404.php b/404.php index 54ac204..804cf82 100644 --- a/404.php +++ b/404.php @@ -3,6 +3,8 @@ include_once "server_files/config.php"; include "server_files/header.php"; +http_response_code(404); + ?>

Cette page n'existe pas.

From 4f4a3aaf4d9c0d2bff58891f51a8f8073f9ca7e4 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 18:00:43 +0200 Subject: [PATCH 012/120] Ajout d'une favicon --- favicon.ico | Bin 0 -> 1514 bytes server_files/header.php | 1 + 2 files changed, 1 insertion(+) create mode 100644 favicon.ico diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..97757d37b247a0f247f1288a6f1a43c15614b612 GIT binary patch literal 1514 zcmcgsO-o{76uz^V)$C^-%w|^elllR+Y!L+NV1Ypz^nr>Lq*i7YrIls*QEDbGl+vhF zGzcTgJ~l}o)-yh5xFX@i%w~?f-uIsOyyrRRIp7_s3MiFIczSxm%gYPO<+A8bPEK%faY0j&bUKax z{(kiJ^lR4NtG6XWXYN_EqEW-=KVjYje1a=GyE z@PNn1M{qwnIx1(hd3$@4I|~a7Fq_Tr`~8@moyG3%E{H`Rdc7X^_xGZs9rJKF9OB1d zFo1sE3-euBS;6-9Hja;vTgQiohX@1$SY2Jk>+7p59^TyC;Qag?$z&3dNJMO?XB>Pd z=G@#I#>U3Pmb|R5uL}mx-pilxbGe-O=3Vke-zo?6LHuYm+QLsH5{SiOQp2UCCFpcI zxx+fHt*yc5^GR&~g1@n`A$1uX9F%AK-A?#BJ39ylgIHW#l(?p+r@=g!LnnOZ^HKi9 zpPHJ2#bOaYKf>SJ+k@BZ1#|a!Jkkf;FE1~HepGzcV}E~N_>0Hm(yMCy+3U4hP5LCC z&$sx$zP<)?V=mlN=%bx~^1&V?-qzNZ*l?x>1_oOEa~{}FJv}`b9v((_cQ;b06r4_{ z+zW@pn3$M=-ENoo$Rm54F=ew^^!E13ERi?%ChIysKQA0|9yA(_^xoOonc%bEv|24} zHXB%rySqD?N%l!76q0yHMn;5RVsf5`hK8hX$RTxBs}*jyTli;B(?_*h#pL9qEc!k; zIFKAnCX?jOJXK-b^g-XW<1BH$Syxqz>*lK0KcP5FkY-{HS`{sP(p$%_C0 literal 0 HcmV?d00001 diff --git a/server_files/header.php b/server_files/header.php index 48a0933..d521b4f 100644 --- a/server_files/header.php +++ b/server_files/header.php @@ -73,6 +73,7 @@ function quitTeam() { Site d'inscription pour le TFJM² <?= $YEAR ?> + From 7adba3f047e3eef4cf1466fd88e86e2db34a0c2a Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 19:45:00 +0200 Subject: [PATCH 013/120] =?UTF-8?q?Correction=20d'un=20probl=C3=A8me=20dan?= =?UTF-8?q?s=20les=20pages=20d'erreur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 403.php | 6 ++++-- 404.php | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/403.php b/403.php index 8c11b98..5bb2466 100644 --- a/403.php +++ b/403.php @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/404.php b/404.php index 804cf82..8541945 100644 --- a/404.php +++ b/404.php @@ -1,7 +1,7 @@ \ No newline at end of file From c2eba2bb2e3b4c78d9210fc48728177925725816 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 19:45:28 +0200 Subject: [PATCH 014/120] Ajout d'une page de visualisation des informations personnelles des participants --- .htaccess | 1 + server_files/equipe.php | 12 +++-- server_files/informations.php | 94 +++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 server_files/informations.php diff --git a/.htaccess b/.htaccess index 48a8884..5c45ecf 100644 --- a/.htaccess +++ b/.htaccess @@ -18,6 +18,7 @@ RewriteRule ^connexion/(.*?)$ server_files/connexion.php?$1 [L] RewriteRule ^deconnexion$ server_files/deconnexion.php [L] RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] +RewriteRule ^informations/(.*?)/.*?$ server_files/informations.php?id=$1 [L] RewriteRule ^inscription$ server_files/inscription.php [L] RewriteRule ^mon_compte$ server_files/mon_compte.php [L] RewriteRule ^mon_equipe/(.*?)$ server_files/mon_equipe.php?$1 [L] diff --git a/server_files/equipe.php b/server_files/equipe.php index 73d2993..6e70360 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -12,7 +12,7 @@ $team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); -$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `type` ORDER BY `user`, `type` ASC, `uploaded_at` DESC;"); +$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); $documents_req->execute([$team_data["id"]]); ?> @@ -28,14 +28,16 @@ Tournoi :
for ($i = 1; $i <= 2; ++$i) { if ($team_data["encadrant_" . $i] == NULL) continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; + $user_data = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + $id = $user_data["id"]; + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; } for ($i = 1; $i <= 6; ++$i) { if ($team_data["participant_" . $i] == NULL) continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; + $user_data = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + $id = $user_data["id"]; + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; } ?> diff --git a/server_files/informations.php b/server_files/informations.php new file mode 100644 index 0000000..c02d3d7 --- /dev/null +++ b/server_files/informations.php @@ -0,0 +1,94 @@ +query("SELECT * FROM `users` WHERE `id` = $id;")->fetch(); + +if ($user_data === false) { + include "../404.php"; +} + +$team_data = false; +if ($user_data["team_id"] !== NULL) + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = " . $user_data["team_id"] . ";")->fetch(); + +$documents_req = $DB->query("SELECT * FROM `documents` WHERE `user` = $id;"); +$tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `name`;"); + +?> + + + +

+ + + Équipe : " . $team_data["name"] . " (" . $team_data["trigram"] . ")" ?>
+ +Date de naissance :
+Sexe :
+Adresse :
+Adresse e-mail : ">
+Numéro de téléphone :
+ + + Lycée :
+ Classe :
+ Nom du responsable légal :
+ Numéro de téléphone du responsable légal :
+ Adresse e-mail du responsable légal : "> + + Description :
+fetch()) !== false) { + echo "Organise le tournoi de " . $tournament_data["name"] . "
"; + } +} +elseif ($user_data["role"] == "PARTICIPANT" || $user_data["role"] == "ENCADRANT") { ?> +
+

Autorisations

+ fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $user_id = $data["user"]; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); + $surname = $user_data["surname"]; + $first_name = $user_data["first_name"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name de $first_name $surname : Télécharger
"; + } +} ?> + + From 864d94c51dbd1448e24fd34203b066ef32e4fdfd Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 19:52:13 +0200 Subject: [PATCH 015/120] =?UTF-8?q?Possibilit=C3=A9=20de=20voir=20les=20in?= =?UTF-8?q?formations=20des=20organisateurs=20d'un=20tournoi=20(pour=20adm?= =?UTF-8?q?ins=20et=20autres=20orgas)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/tournoi.php | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/server_files/tournoi.php b/server_files/tournoi.php index 5110c18..40c2f50 100644 --- a/server_files/tournoi.php +++ b/server_files/tournoi.php @@ -8,10 +8,10 @@ $response = $DB->prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year $response->execute([$tournament_name]); $data = $response->fetch(); -$orgas_req = $DB->query("SELECT `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); +$orgas_req = $DB->query("SELECT `users`.`id` AS `id`, `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); $orgas = []; while (($orga_data = $orgas_req->fetch()) !== false) { - $orgas[] = $orga_data["first_name"] . " " . $orga_data["surname"]; + $orgas[] = [$orga_data["id"], $orga_data["first_name"] . " " . $orga_data["surname"]]; } if (isset($_POST["edit_tournament"])) { @@ -126,8 +126,13 @@ function updateTournament() { Organisateur= 2 ? 's' : '' ?> : $orga[1]"; + else + $s .= $orga[1]; + $s .= ", "; + } echo substr($s, 0, -2); ?>
From 885723af5f997b2e1cc2d95011cd7cb23877a2c2 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 19:56:41 +0200 Subject: [PATCH 016/120] Lien du tournoi cliquable --- server_files/equipe.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/server_files/equipe.php b/server_files/equipe.php index 6e70360..ca955de 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -10,6 +10,9 @@ if (isset($_POST["validate"])) { $team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND `year` = $YEAR;")->fetch(); +if ($team_data === false) + include "../404.php"; + $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); $documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); @@ -21,9 +24,9 @@ $documents_req->execute([$team_data["id"]]);

Informations sur l'équipe

-Nom de l'équipe :
-Trigramme :
-Tournoi :
+Nom de l'équipe :
+Trigramme :
+Tournoi : ">
Date: Mon, 2 Sep 2019 20:07:18 +0200 Subject: [PATCH 017/120] Diminution des marges --- style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/style.css b/style.css index c3f206e..bf10db5 100644 --- a/style.css +++ b/style.css @@ -12,7 +12,7 @@ html, body { list-style-type: none; margin: 0; padding: 0; - width: 200px; + width: 220px; background-color: #f1f1f1; height: 100%; overflow: auto; @@ -53,7 +53,7 @@ html, body { padding-top: 100px; padding-bottom: 100px; margin: 0 auto; - max-width: 800px; + max-width: 1000px; text-align: justify; } From 35aed16e102fa78320e19c657732ebfef7cff784 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 20:08:20 +0200 Subject: [PATCH 018/120] Typo --- server_files/informations.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_files/informations.php b/server_files/informations.php index c02d3d7..c4c66c5 100644 --- a/server_files/informations.php +++ b/server_files/informations.php @@ -61,7 +61,7 @@ Numéro de téléphone :
if ($user_data["role"] == "ADMIN" || $user_data["role"] == "ORGANIZER") { while (($tournament_data = $tournaments_req->fetch()) !== false) { - echo "Organise le tournoi de " . $tournament_data["name"] . "
"; + echo "Organise le tournoi " . $tournament_data["name"] . "
"; } } elseif ($user_data["role"] == "PARTICIPANT" || $user_data["role"] == "ENCADRANT") { ?> From 273bd059443031812e6115b5f5c70e4a00c7a4f8 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 20:57:26 +0200 Subject: [PATCH 019/120] =?UTF-8?q?Quelques=20v=C3=A9rifications=20tempore?= =?UTF-8?q?lles=20et=20autres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/ajouter_equipe.php | 2 +- server_files/config.php | 8 + server_files/equipe.php | 2 +- server_files/footer.php | 3 +- server_files/informations.php | 4 +- server_files/mon_equipe.php | 359 +++++++++++++++++++------------- server_files/solutions.php | 81 +++---- server_files/syntheses.php | 81 ++++--- 8 files changed, 320 insertions(+), 220 deletions(-) diff --git a/server_files/ajouter_equipe.php b/server_files/ajouter_equipe.php index b0bc049..d9aa7fa 100644 --- a/server_files/ajouter_equipe.php +++ b/server_files/ajouter_equipe.php @@ -2,7 +2,7 @@ include 'config.php'; -$tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); +$tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `date_inscription` > CURRENT_DATE AND `year` = '$YEAR';"); if (isset($_POST["submitted"])) { $error_message = registerTeam(); diff --git a/server_files/config.php b/server_files/config.php index 1ecd6c0..18db43f 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -57,4 +57,12 @@ function echo_date($date = NULL, $with_time = false) { return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); } +function error403() { + include "../403.php"; +} + +function error404() { + include "../404.php"; +} + ?> diff --git a/server_files/equipe.php b/server_files/equipe.php index ca955de..bb40602 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -11,7 +11,7 @@ if (isset($_POST["validate"])) { $team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND `year` = $YEAR;")->fetch(); if ($team_data === false) - include "../404.php"; + error404(); $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); diff --git a/server_files/footer.php b/server_files/footer.php index 0289fab..b806435 100644 --- a/server_files/footer.php +++ b/server_files/footer.php @@ -2,4 +2,5 @@
- \ No newline at end of file + + diff --git a/server_files/informations.php b/server_files/informations.php index c4c66c5..be15241 100644 --- a/server_files/informations.php +++ b/server_files/informations.php @@ -3,14 +3,14 @@ include "config.php"; if (!isset($_SESSION["role"]) || $_SESSION["role"] != "ORGANIZER" && $_SESSION["role"] != "ADMIN") { - include "../403.php"; + error403(); } $id = $_GET["id"]; $user_data = $DB->query("SELECT * FROM `users` WHERE `id` = $id;")->fetch(); if ($user_data === false) { - include "../404.php"; + error404(); } $team_data = false; diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php index 3e00703..b853e37 100644 --- a/server_files/mon_equipe.php +++ b/server_files/mon_equipe.php @@ -3,56 +3,60 @@ include 'config.php'; if (isset($_POST["leave_team"])) { - for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); - for ($i = 1; $i <= 5; ++$i) { - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); - } - - $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - - if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { + for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); + for ($i = 1; $i <= 5; ++$i) { + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); + } + + $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + + if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); while (($data = $req->fetch()) !== false) unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); - + $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); + $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); while (($data = $req->fetch()) !== false) unlink("$URL_BASE/files/" . $data["file_id"]); $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); - } - unset($_SESSION["team_id"]); - unset($_SESSION["team_validation_status"]); - header("Location: $URL_BASE"); - exit(); + } + unset($_SESSION["team_id"]); + unset($_SESSION["team_validation_status"]); + header("Location: $URL_BASE"); + exit(); } $tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); if (isset($_POST["send_document"])) { - sendDocument(); + $error_message = sendDocument(); } if (isset($_POST["request_validation"])) { - $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); - $_SESSION["team_validation_status"] = "WAITING"; + if (!checkCanValidate()) + $error_message = "Votre équipe ne peut pas demander la validation : il manque soit des participants, soit des documents."; + else { + $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); + $_SESSION["team_validation_status"] = "WAITING"; + } } if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { - $result = $DB->query("SELECT * FROM `teams` WHERE `id` = '" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); - $team_data = $result->fetch(); - - $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); - - $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? GROUP BY `type` ORDER BY `type` ASC, `uploaded_at` DESC;"); + $result = $DB->query("SELECT * FROM `teams` WHERE `id` = '" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $team_data = $result->fetch(); + + $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); + + $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? GROUP BY `type`, `uploaded_at` ORDER BY `type`, `uploaded_at` DESC;"); $documents_req->execute([$_SESSION["user_id"]]); } @@ -60,128 +64,173 @@ if (isset($_POST["team_edit"])) { $error_message = updateTeam(); } -function sendDocument() { +function sendDocument() +{ global $LOCAL_PATH, $DB; - + $type = strtoupper(htmlspecialchars($_POST["type"])); if (!isset($type) || ($type != "PARENTAL_CONSENT" && $type != "PHOTO_CONSENT" && $type != "SANITARY_PLUG")) - return "Le type de document est invalide. Merci de ne pas formuler vos propres requêtes."; - + return "Le type de document est invalide. Merci de ne pas formuler vos propres requêtes."; + $file = $_FILES["document"]; - + if ($file["size"] > 5000000 || $file["error"]) return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; - + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') return "Le fichier doit être au format PDF."; - + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - + do { $id = ""; for ($i = 0; $i < 64; ++$i) { $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; } - } - while (file_exists("$LOCAL_PATH/files/$id")); - + } while (file_exists("$LOCAL_PATH/files/$id")); + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) return "Une erreur est survenue lors de l'envoi du fichier."; - + $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `tournament`, `type`) VALUES (?, ?, ?, ?, ?);"); $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION["tournament_id"], $type]); - + return false; } -function updateTeam() { - global $DB, $YEAR, $URL_BASE, $MAIL_ADDRESS, $team_data; - +function updateTeam() +{ + global $DB, $YEAR, $URL_BASE, $team_data; + if ($_SESSION["team_id"] == NULL) return "Vous n'êtes pas dans une équipe."; - + $name = htmlspecialchars($_POST["name"]); - + if (!isset($name) || $name == "") return "Vous devez spécifier un nom d'équipe."; - + echo $team_data["id"]; $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `id` != " . $team_data["id"] . " AND `year` = '$YEAR';"); if ($result->fetch()) return "Une équipe existe déjà avec ce nom." . $team_data["id"]; - + $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); - + if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) return "Le trigramme entré n'est pas valide."; - + $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `id` != '" . $team_data["id"] . "' AND `year` = '$YEAR';"); if ($result->fetch()) return "Une équipe a déjà choisi ce trigramme."; - + $tournament_id = intval(htmlspecialchars($_POST["tournament"])); - + $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); $data = $result->fetch(); if ($data === FALSE) return "Le tournoi spécifié n'existe pas."; - + $req = $DB->prepare("UPDATE `teams` SET `name` = ?, `trigram` = ?, `tournament` = ? WHERE `id` = ?;"); $req->execute([$name, $trigram, $tournament_id, $team_data["id"]]); - + header("Location: $URL_BASE/mon_equipe"); - + return false; } +function checkCanValidate() { + global $DB, $team_data, $tournament_data, $YEAR; + $can_validate = $team_data["validation_status"] == "NOT_READY"; + $can_validate &= $team_data["encadrant_1"] != NULL; + $can_validate &= $team_data["participant_4"] != NULL; + for ($i = 1; $i <= 2; ++$i) { + if ($team_data["encadrant_$i"] === NULL) + continue; + + $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); + $req->execute([$team_data["encadrant_$i"], "PHOTO_CONSENT"]); + $d = $req->fetch(); + $can_validate &= $d["version"] > 0; + + $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); + $req->execute([$team_data["encadrant_$i"], "SANITARY_PLUG"]); + $d = $req->fetch(); + $can_validate &= $d["version"] > 0; + } + for ($i = 1; $i <= 6; ++$i) { + if ($team_data["participant_$i"] === NULL) + continue; + + $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); + $req->execute([$team_data["participant_$i"], "PHOTO_CONSENT"]); + $d = $req->fetch(); + $can_validate &= $d["version"] > 0; + + $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); + $req->execute([$team_data["participant_$i"], "SANITARY_PLUG"]); + $d = $req->fetch(); + $can_validate &= $d["version"] > 0; + + $birth_date = $DB->query("SELECT `birth_date` FROM `users` WHERE `id` = " . $team_data["participant_$i"] . ";")->fetch()["birth_date"]; + if ($birth_date > strval($YEAR - 18) . substr($tournament_data["date_start"], 4)) { + $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); + $req->execute([$team_data["participant_$i"], "PARENTAL_CONSENT"]); + $d = $req->fetch(); + $can_validate &= $d["version"] > 0; + } + } + + return $can_validate; +} + ?> Vous devez être dans une équipe pour afficher cette page."; - include "footer.php"; - return; + echo "

Vous devez être dans une équipe pour afficher cette page.

"; + include "footer.php"; + return; } ?> Erreur : " . $error_message . ""; - } - else { + } else { echo "

Le fichier a été correctement envoyé !

"; } -}?> +} ?>

Informations sur l'équipe

-Nom de l'équipe :
-Trigramme :
-Tournoi :
+Nom de l'équipe :
+Trigramme :
+Tournoi : ">
query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; + if ($team_data["encadrant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; } for ($i = 1; $i <= 6; ++$i) { - if ($team_data["participant_" . $i] == NULL) - continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; + if ($team_data["participant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; } ?> -Code d'accès :
+Code d'accès :
- + @@ -189,7 +238,7 @@ Code d'accès :
@@ -197,7 +246,8 @@ Code d'accès :
@@ -216,7 +266,7 @@ Code d'accès :
@@ -224,72 +274,89 @@ Code d'accès :
- - - Modifier mon équipe -
-

Mes autorisations

- fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; + + + + Modifier mon équipe +
+

Mes autorisations

+ fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name : Télécharger
"; } - echo "$name : Télécharger
"; - } - ?> + ?> - - -
- " /> + "/>
- " /> + "/>
- +
- - - - - - - - - - - - - -
- - - -
- - - -
- -
- -
- -
-
- -
- +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+
+ + + + + + + + +
+
+ +
+
+
+ +
+
+ + diff --git a/server_files/solutions.php b/server_files/solutions.php index d243f31..6eb747c 100644 --- a/server_files/solutions.php +++ b/server_files/solutions.php @@ -2,13 +2,20 @@ include 'config.php'; +if (!isset($_SESSION["team_id"])) + error403(); + if (isset($_POST["send_solution"])) { $error_message = saveSolution(); } -$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? GROUP BY `problem` ORDER BY `problem` ASC, `uploaded_at` DESC;"); +$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); $solutions_req->execute([$_SESSION["team_id"]]); +$tournament_req = $DB->prepare("SELECT `date_solutions` FROM `tournaments` WHERE `id` = ?;"); +$tournament_req->execute([$_SESSION["tournament_id"]]); +$tournament_data = $tournament_req->fetch(); + function saveSolution() { global $LOCAL_PATH, $DB; @@ -64,42 +71,44 @@ function saveSolution() { } }?> -
- - - - - - - - - - - - - - - -
- - - -
- - - -
- -
-
+ +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ -
+

Solutions soumises :

diff --git a/server_files/syntheses.php b/server_files/syntheses.php index 377825f..8e692d0 100644 --- a/server_files/syntheses.php +++ b/server_files/syntheses.php @@ -2,13 +2,20 @@ include 'config.php'; +if (!isset($_SESSION["team_id"])) + error403(); + if (isset($_POST["send_synthese"])) { $error_message = saveSynthese(); } -$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? GROUP BY `dest` ORDER BY `dest` ASC, `uploaded_at` DESC;"); +$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); $syntheses_req->execute([$_SESSION["team_id"]]); +$tournament_req = $DB->prepare("SELECT `date_solutions`, `date_syntheses` FROM `tournaments` WHERE `id` = ?;"); +$tournament_req->execute([$_SESSION["tournament_id"]]); +$tournament_data = $tournament_req->fetch(); + function saveSynthese() { global $LOCAL_PATH, $DB; @@ -52,7 +59,13 @@ function saveSynthese() { -Il est trop tôt pour se préoccuper des notes de synthèse, attendez le tirage des poules."; + include "footer.php"; +} + +if (isset($error_message)) { if ($error_message !== false) { echo "

Erreur : " . $error_message . "

"; } @@ -61,37 +74,39 @@ function saveSynthese() { } }?> -
- - - - - - - - - - - - - - - -
- - - -
- - - -
- -
-
+ +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+
From 946d261c713cfca4d20191bd2887fafb7cbe253f Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 21:19:21 +0200 Subject: [PATCH 020/120] Modifications sur les pages d'erreur --- .htaccess | 4 ++-- 403.php | 18 ------------------ 404.php | 18 ------------------ server_files/403.php | 12 ++++++++++++ server_files/404.php | 12 ++++++++++++ server_files/config.php | 10 ---------- server_files/equipe.php | 2 +- server_files/informations.php | 4 ++-- 8 files changed, 29 insertions(+), 51 deletions(-) delete mode 100644 403.php delete mode 100644 404.php create mode 100644 server_files/403.php create mode 100644 server_files/404.php diff --git a/.htaccess b/.htaccess index 5c45ecf..f11ae5e 100644 --- a/.htaccess +++ b/.htaccess @@ -1,5 +1,5 @@ -ErrorDocument 403 /tfjm/403.php -ErrorDocument 404 /tfjm/404.php +ErrorDocument 403 /tfjm/server_files/403.php +ErrorDocument 404 /tfjm/server_files/404.php Options +FollowSymlinks Options -Indexes diff --git a/403.php b/403.php deleted file mode 100644 index 5bb2466..0000000 --- a/403.php +++ /dev/null @@ -1,18 +0,0 @@ - - -

Vous n'êtes pas autorisé à accéder à cette page.

- - \ No newline at end of file diff --git a/404.php b/404.php deleted file mode 100644 index 8541945..0000000 --- a/404.php +++ /dev/null @@ -1,18 +0,0 @@ - - -

Cette page n'existe pas.

- - \ No newline at end of file diff --git a/server_files/403.php b/server_files/403.php new file mode 100644 index 0000000..77bc30d --- /dev/null +++ b/server_files/403.php @@ -0,0 +1,12 @@ +Vous n'êtes pas autorisé à accéder à cette page."; + +include "footer.php"; + +exit(); \ No newline at end of file diff --git a/server_files/404.php b/server_files/404.php new file mode 100644 index 0000000..b47428f --- /dev/null +++ b/server_files/404.php @@ -0,0 +1,12 @@ +Cette page n'existe pas."; + +include "footer.php"; + +exit(); \ No newline at end of file diff --git a/server_files/config.php b/server_files/config.php index 18db43f..c90bb7a 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -56,13 +56,3 @@ function echo_date($date = NULL, $with_time = false) { return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); } - -function error403() { - include "../403.php"; -} - -function error404() { - include "../404.php"; -} - -?> diff --git a/server_files/equipe.php b/server_files/equipe.php index bb40602..fff9af4 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -11,7 +11,7 @@ if (isset($_POST["validate"])) { $team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND `year` = $YEAR;")->fetch(); if ($team_data === false) - error404(); + include "404.php"; $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); diff --git a/server_files/informations.php b/server_files/informations.php index be15241..237d49b 100644 --- a/server_files/informations.php +++ b/server_files/informations.php @@ -3,14 +3,14 @@ include "config.php"; if (!isset($_SESSION["role"]) || $_SESSION["role"] != "ORGANIZER" && $_SESSION["role"] != "ADMIN") { - error403(); + include "403.php"; } $id = $_GET["id"]; $user_data = $DB->query("SELECT * FROM `users` WHERE `id` = $id;")->fetch(); if ($user_data === false) { - error404(); + include "404.php"; } $team_data = false; From 683b8c71b780bc8a7097bacfea6a6fab5afb148d Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 21:21:37 +0200 Subject: [PATCH 021/120] =?UTF-8?q?Quelques=20=C3=A9l=C3=A9ments=20de=20v?= =?UTF-8?q?=C3=A9rification=20de=20s=C3=A9curit=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/solutions.php | 2 +- server_files/solutions_orga.php | 3 +++ server_files/syntheses.php | 2 +- server_files/syntheses_orga.php | 9 ++++++--- server_files/tournoi.php | 22 +++++++++++++++------- 5 files changed, 26 insertions(+), 12 deletions(-) diff --git a/server_files/solutions.php b/server_files/solutions.php index 6eb747c..4e4f85f 100644 --- a/server_files/solutions.php +++ b/server_files/solutions.php @@ -3,7 +3,7 @@ include 'config.php'; if (!isset($_SESSION["team_id"])) - error403(); + include "403.php"; if (isset($_POST["send_solution"])) { $error_message = saveSolution(); diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php index 041fd32..94a52fd 100644 --- a/server_files/solutions_orga.php +++ b/server_files/solutions_orga.php @@ -2,6 +2,9 @@ query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest`, `uploaded_at` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); $zip = new ZipArchive(); @@ -46,12 +49,12 @@ if (isset($_POST["download_zip"])) { $req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR GROUP BY `tournament` ORDER BY `name`;"); + . "`year` = $YEAR GROUP BY `tournament`, `name` ORDER BY `name`;"); while (($data_tournament = $req->fetch()) !== false) { echo "

Tournoi de " . $data_tournament["name"] . "

\n"; $id = $data_tournament["id"]; - $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest`, `uploaded_at` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); while (($data_file = $files_req->fetch()) !== false) { $file_id = $data_file["file_id"]; $dest = $data_file["dest"]; diff --git a/server_files/tournoi.php b/server_files/tournoi.php index 40c2f50..982f764 100644 --- a/server_files/tournoi.php +++ b/server_files/tournoi.php @@ -10,10 +10,15 @@ $data = $response->fetch(); $orgas_req = $DB->query("SELECT `users`.`id` AS `id`, `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); $orgas = []; +$orgas_id = []; while (($orga_data = $orgas_req->fetch()) !== false) { - $orgas[] = [$orga_data["id"], $orga_data["first_name"] . " " . $orga_data["surname"]]; + $orgas[] = $orga_data["first_name"] . " " . $orga_data["surname"]; + $orgas_id[] = $orga_data["id"]; } +if (isset($_GET["modifier"]) && $_SESSION["role"] != "ADMIN" && !in_array($_SESSION["user_id"], $orgas_id)) + include "403.php"; + if (isset($_POST["edit_tournament"])) { $error_message = updateTournament(); } @@ -23,7 +28,7 @@ $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date` $orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); function updateTournament() { - global $DB, $URL_BASE, $YEAR, $MAIL_ADDRESS, $data; + global $DB, $URL_BASE, $YEAR, $data; $tournament_id = $data["id"]; @@ -126,11 +131,11 @@ function updateTournament() { Organisateur= 2 ? 's' : '' ?> : $orga[1]"; + $s .= "$orgas[$i]"; else - $s .= $orga[1]; + $s .= $orgas[$i]; $s .= ", "; } echo substr($s, 0, -2); @@ -145,9 +150,12 @@ function updateTournament() { Date limite d'envoi des notes de synthèse :
Description :
- + /modifier">Éditer le tournoi + + +

Équipes inscrites à ce tournoi :

@@ -176,7 +184,7 @@ function updateTournament() { " . $team_data["name"] . ""; else echo $team_data["name"]; From 8590d8f730174e53fa09778393bb5134b8e19091 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 21:25:06 +0200 Subject: [PATCH 022/120] Pas d'affichage de description pour qui n'en a pas --- server_files/informations.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/server_files/informations.php b/server_files/informations.php index 237d49b..d80d70b 100644 --- a/server_files/informations.php +++ b/server_files/informations.php @@ -18,7 +18,7 @@ if ($user_data["team_id"] !== NULL) $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = " . $user_data["team_id"] . ";")->fetch(); $documents_req = $DB->query("SELECT * FROM `documents` WHERE `user` = $id;"); -$tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `name`;"); +$tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `date_start`, `name`;"); ?> @@ -55,10 +55,12 @@ Numéro de téléphone :
Nom du responsable légal :
Numéro de téléphone du responsable légal :
Adresse e-mail du responsable légal : "> - + Description :
"; + if ($user_data["role"] == "ADMIN" || $user_data["role"] == "ORGANIZER") { while (($tournament_data = $tournaments_req->fetch()) !== false) { echo "Organise le tournoi " . $tournament_data["name"] . "
"; From 2ce1f8387336c79be2b5c2f8864c38e0f79eba32 Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 21:56:28 +0200 Subject: [PATCH 023/120] =?UTF-8?q?Seuls=20les=20organisateurs=20nationaux?= =?UTF-8?q?=20peuvent=20valider=20des=20=C3=A9quipes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/equipe.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_files/equipe.php b/server_files/equipe.php index fff9af4..5b945b2 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -74,7 +74,7 @@ while (($data = $documents_req->fetch()) !== false) { +if ($team_data["validation_status"] == "WAITING" && $_SESSION["role"] == "ADMIN") { ?>
From 10da20f2c05a3cf233af2302b942617051c8593a Mon Sep 17 00:00:00 2001 From: Yohann Date: Mon, 2 Sep 2019 22:01:26 +0200 Subject: [PATCH 024/120] Erreur 404 si le tournoi n'existe pas --- server_files/tournoi.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server_files/tournoi.php b/server_files/tournoi.php index 982f764..dac1568 100644 --- a/server_files/tournoi.php +++ b/server_files/tournoi.php @@ -8,6 +8,9 @@ $response = $DB->prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year $response->execute([$tournament_name]); $data = $response->fetch(); +if ($data === false) + include "404.php"; + $orgas_req = $DB->query("SELECT `users`.`id` AS `id`, `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); $orgas = []; $orgas_id = []; From 39abeec4e6e8ae8ab37920f16d23997a7693aebd Mon Sep 17 00:00:00 2001 From: Yohann Date: Tue, 3 Sep 2019 00:01:54 +0200 Subject: [PATCH 025/120] Support de la finale --- server_files/ajouter_tournoi.php | 25 ++++++-- server_files/config.php | 9 ++- server_files/equipe.php | 98 ++++++++++++++++++++++++++++-- server_files/mon_equipe.php | 101 ++++++++++++++++--------------- server_files/solutions.php | 13 ++-- server_files/solutions_orga.php | 5 +- server_files/syntheses.php | 13 ++-- server_files/syntheses_orga.php | 3 +- server_files/tournoi.php | 9 ++- server_files/tournois.php | 10 ++- 10 files changed, 210 insertions(+), 76 deletions(-) diff --git a/server_files/ajouter_tournoi.php b/server_files/ajouter_tournoi.php index 829edee..7c73a88 100644 --- a/server_files/ajouter_tournoi.php +++ b/server_files/ajouter_tournoi.php @@ -80,12 +80,17 @@ function registerTournament() { return "Une date est mal formée."; $description = htmlspecialchars($_POST["description"]); + + $final = isset($_POST["final"]) && $_POST["final"]; + + if ($final && $DB->query("SELECT `id` FROM `tournaments` WHERE `final` = true AND `year` = $YEAR;")->fetch() !== false) + return "Une finale est déjà enregistrée."; $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `size`, `place`, `price`, `description`, - `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `final`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); $req->execute([$name, $size, $place, $price, $description, $date_start, $date_end, - "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $YEAR]); + "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $final, $YEAR]); $req = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '$name' AND `year` = $YEAR;"); $tournament_id = $req->fetch()["id"]; @@ -175,7 +180,8 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { - Du au + Du au + @@ -184,6 +190,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { + @@ -193,6 +200,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { + @@ -202,6 +210,7 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { + @@ -213,6 +222,14 @@ if (!isset($_SESSION["role"]) or $_SESSION["role"] != "ADMIN") { + + + + + + + + diff --git a/server_files/config.php b/server_files/config.php index c90bb7a..2ee4d36 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -41,11 +41,18 @@ if (isset($_SESSION["user_id"])) { } if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"]) && $_SESSION["team_id"] != NULL) { - $response = $DB->query("SELECT `tournament`, `validation_status` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $response = $DB->query("SELECT `tournament`, `validation_status`, `final_selection` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); $data = $response->fetch(); $_SESSION["tournament_id"] = $data["tournament"]; $_SESSION["team_validation_status"] = $data["validation_status"]; } + + if ((isset($data["final_selection"]) && $data["final_selection"]) || $_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") { + $response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `final` AND `year` = $YEAR;"); + $data = $response->fetch(); + $_SESSION["final_id"] = $data["id"]; + $_SESSION["final_name"] = $data["name"]; + } } setlocale(LC_ALL, "fr_FR.utf8"); diff --git a/server_files/equipe.php b/server_files/equipe.php index 5b945b2..60fe63f 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -10,13 +10,67 @@ if (isset($_POST["validate"])) { $team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND `year` = $YEAR;")->fetch(); +if (isset($_POST["select"])) { + $DB->exec("UPDATE `teams` SET `final_selection` = true, `validation_status` = 'NOT_READY' WHERE `trigram` = '$trigram' AND `year` = $YEAR;"); + $team_data["validation_status"] = "NOT_READY"; + $team_data["final_selection"] = true; + $final_id = $_SESSION["final_id"]; + $team_id = $team_data["id"]; + + $sols_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); + $sols_req->execute([$team_data["id"], $team_data["tournament"]]); + while (($sol_data = $sols_req->fetch()) !== false) { + $old_id = $sol_data["file_id"]; + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); + + $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) + VALUES (?, ?, ?, ?);"); + $req->execute([$id, $team_id, $_SESSION["final_id"], $sol_data["problem"]]); + } + + $syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); + $syntheses_req->execute([$team_data["id"], $team_data["tournament"]]); + while (($synthese_data = $syntheses_req->fetch()) !== false) { + $old_id = $synthese_data["file_id"]; + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); + + $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); + $req->execute([$id, $team_id, $_SESSION["final_id"], $synthese_data["dest"]]); + } +} + if ($team_data === false) include "404.php"; $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); -$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); -$documents_req->execute([$team_data["id"]]); +$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); +$documents_req->execute([$team_data["id"], $team_data["tournament"]]); + +if ($team_data["final_selection"]) { + $documents_final_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` != ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); + $documents_final_req->execute([$team_data["id"], $_SESSION["final_id"]]); +} ?> @@ -42,6 +96,10 @@ for ($i = 1; $i <= 6; ++$i) { $id = $user_data["id"]; echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; } +if ($team_data["final_selection"]) { + $final_name = $_SESSION["final_name"]; + echo "Équipe sélectionnée pour la finale nationale."; +} ?>
@@ -72,11 +130,43 @@ while (($data = $documents_req->fetch()) !== false) { } ?> - +
+

Autorisations pour la finale

+ fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $user_id = $data["user"]; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); + $surname = $user_data["surname"]; + $first_name = $user_data["first_name"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name de $first_name $surname : Télécharger
"; + } +} if ($team_data["validation_status"] == "WAITING" && $_SESSION["role"] == "ADMIN") { ?>
- + +
+ +
+
diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php index b853e37..4553d4e 100644 --- a/server_files/mon_equipe.php +++ b/server_files/mon_equipe.php @@ -42,9 +42,9 @@ if (isset($_POST["send_document"])) { } if (isset($_POST["request_validation"])) { - if (!checkCanValidate()) - $error_message = "Votre équipe ne peut pas demander la validation : il manque soit des participants, soit des documents."; - else { + if (!checkCanValidate()) + $error_message = "Votre équipe ne peut pas demander la validation : il manque soit des participants, soit des documents."; + else { $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); $_SESSION["team_validation_status"] = "WAITING"; } @@ -56,8 +56,8 @@ if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); - $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? GROUP BY `type`, `uploaded_at` ORDER BY `type`, `uploaded_at` DESC;"); - $documents_req->execute([$_SESSION["user_id"]]); + $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? GROUP BY `type`, `uploaded_at` ORDER BY `type`, `uploaded_at` DESC;"); + $documents_req->execute([$_SESSION["user_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); } if (isset($_POST["team_edit"])) { @@ -97,7 +97,7 @@ function sendDocument() $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `tournament`, `type`) VALUES (?, ?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION["tournament_id"], $type]); + $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"], $type]); return false; } @@ -143,9 +143,10 @@ function updateTeam() return false; } -function checkCanValidate() { - global $DB, $team_data, $tournament_data, $YEAR; - $can_validate = $team_data["validation_status"] == "NOT_READY"; +function checkCanValidate() +{ + global $DB, $team_data, $tournament_data, $YEAR; + $can_validate = $team_data["validation_status"] == "NOT_READY"; $can_validate &= $team_data["encadrant_1"] != NULL; $can_validate &= $team_data["participant_4"] != NULL; for ($i = 1; $i <= 2; ++$i) { @@ -226,6 +227,10 @@ for ($i = 1; $i <= 6; ++$i) { } ?> Code d'accès :
+Équipe sélectionnée pour la finale nationale.
"; +} ?> @@ -278,28 +283,28 @@ Code d'accès :
Modifier mon équipe -
-

Mes autorisations

- fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name : Télécharger
"; + +
+

Mes autorisations

+ fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; } - ?> - + echo "$name : Télécharger
"; + } + if ($team_data["validation_status"] == "NOT_READY") { ?>
@@ -334,28 +339,28 @@ Code d'accès :
-
- - - + +
+ +
+ + + - - - - -
+
+ +
+
- +
-
- -
-
- + + + diff --git a/server_files/solutions.php b/server_files/solutions.php index 4e4f85f..4699162 100644 --- a/server_files/solutions.php +++ b/server_files/solutions.php @@ -9,11 +9,11 @@ if (isset($_POST["send_solution"])) { $error_message = saveSolution(); } -$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); -$solutions_req->execute([$_SESSION["team_id"]]); +$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); +$solutions_req->execute([$_SESSION["team_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); $tournament_req = $DB->prepare("SELECT `date_solutions` FROM `tournaments` WHERE `id` = ?;"); -$tournament_req->execute([$_SESSION["tournament_id"]]); +$tournament_req->execute([$_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); $tournament_data = $tournament_req->fetch(); function saveSolution() { @@ -52,8 +52,7 @@ function saveSolution() { if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) return "Une erreur est survenue lors de l'envoi du fichier."; - $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) - VALUES (?, ?, ?, ?);"); + $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) VALUES (?, ?, ?, ?);"); $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $problem]); return false; @@ -74,14 +73,14 @@ function saveSolution() {
- +
- $i\n"; diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php index 94a52fd..891e4be 100644 --- a/server_files/solutions_orga.php +++ b/server_files/solutions_orga.php @@ -54,7 +54,7 @@ $req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `or while (($data_tournament = $req->fetch()) !== false) { echo "

Tournoi de " . $data_tournament["name"] . "

\n"; $id = $data_tournament["id"]; - $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); while (($data_file = $files_req->fetch()) !== false) { $file_id = $data_file["file_id"]; $problem = $data_file["problem"]; @@ -70,8 +70,9 @@ while (($data_tournament = $req->fetch()) !== false) { " /> - + +
prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); -$syntheses_req->execute([$_SESSION["team_id"]]); +$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); +$syntheses_req->execute([$_SESSION["team_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); $tournament_req = $DB->prepare("SELECT `date_solutions`, `date_syntheses` FROM `tournaments` WHERE `id` = ?;"); -$tournament_req->execute([$_SESSION["tournament_id"]]); +$tournament_req->execute([$_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); $tournament_data = $tournament_req->fetch(); function saveSynthese() { @@ -48,8 +48,7 @@ function saveSynthese() { if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) return "Une erreur est survenue lors de l'envoi du fichier."; - $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) - VALUES (?, ?, ?, ?);"); + $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $dest]); return false; @@ -77,14 +76,14 @@ if (isset($error_message)) {
- +
+ + + + + + From d2a0d0fbec3b5884f80b769020bb380349c9e551 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Thu, 5 Sep 2019 19:07:41 +0200 Subject: [PATCH 026/120] Modification mineure --- server_files/403.php | 6 +- server_files/404.php | 6 +- server_files/ajouter_equipe.php | 254 +++++----- server_files/ajouter_organisateur.php | 6 +- server_files/ajouter_tournoi.php | 6 +- server_files/confirmer_mail.php | 6 +- server_files/connexion.php | 6 +- server_files/deconnexion.php | 28 +- server_files/equipe.php | 8 +- server_files/index.php | 6 +- server_files/informations.php | 10 +- server_files/inscription.php | 6 +- server_files/mon_compte.php | 646 +++++++++++++------------- server_files/mon_equipe.php | 8 +- server_files/rejoindre_equipe.php | 186 ++++---- server_files/solutions.php | 8 +- server_files/solutions_orga.php | 8 +- server_files/syntheses.php | 10 +- server_files/syntheses_orga.php | 8 +- server_files/tournoi.php | 10 +- server_files/tournois.php | 6 +- server_files/view_file.php | 4 +- 22 files changed, 621 insertions(+), 621 deletions(-) diff --git a/server_files/403.php b/server_files/403.php index 77bc30d..76739fa 100644 --- a/server_files/403.php +++ b/server_files/403.php @@ -1,12 +1,12 @@ Vous n'êtes pas autorisé à accéder à cette page."; -include "footer.php"; +require_once "footer.php"; exit(); \ No newline at end of file diff --git a/server_files/404.php b/server_files/404.php index b47428f..275bee1 100644 --- a/server_files/404.php +++ b/server_files/404.php @@ -1,12 +1,12 @@ Cette page n'existe pas."; -include "footer.php"; +require_once "footer.php"; exit(); \ No newline at end of file diff --git a/server_files/ajouter_equipe.php b/server_files/ajouter_equipe.php index d9aa7fa..7878268 100644 --- a/server_files/ajouter_equipe.php +++ b/server_files/ajouter_equipe.php @@ -1,127 +1,127 @@ -query("SELECT `id`, `name` FROM `tournaments` WHERE `date_inscription` > CURRENT_DATE AND `year` = '$YEAR';"); - -if (isset($_POST["submitted"])) { - $error_message = registerTeam(); -} - -function registerTeam() { - global $DB, $YEAR, $MAIL_ADDRESS, $access_code; - - if ($_SESSION["team_id"] != NULL) - return "Vous êtes déjà dans une équipe."; - - $name = htmlspecialchars($_POST["name"]); - - if (!isset($name) || $name == "") - return "Vous devez spécifier un nom d'équipe."; - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Une équipe existe déjà avec ce nom."; - - $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); - - if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) - return "Le trigramme entré n'est pas valide."; - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Une équipe a déjà choisi ce trigramme."; - - $tournament_id = intval(htmlspecialchars($_POST["tournament"])); - - $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) - return "Le tournoi spécifié n'existe pas."; - - $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; - $access_code = ""; - for ($i = 0; $i < 6; ++$i) - $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; - - $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$name, $trigram, $tournament_id, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, - $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - $data_team = $result->fetch(); - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); - - $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; - $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; - $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; - $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; - mail($_SESSION["email"], "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; -} - -?> - - - - -

Vous devez être participant ou encadrant pour pouvoir ajouter une équipe.

- -

Vous êtes déjà dans une équipe.

- - Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : - - -Erreur : " . $error_message . ""; ?> - -
- -
- diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php index 322e07e..6e336b6 100644 --- a/server_files/syntheses_orga.php +++ b/server_files/syntheses_orga.php @@ -70,8 +70,9 @@ while (($data_tournament = $req->fetch()) !== false) { " /> - + +
diff --git a/server_files/tournoi.php b/server_files/tournoi.php index dac1568..4855e01 100644 --- a/server_files/tournoi.php +++ b/server_files/tournoi.php @@ -26,7 +26,10 @@ if (isset($_POST["edit_tournament"])) { $error_message = updateTournament(); } -$teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); +if ($data["final"]) + $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `final_selection` AND `year` = $YEAR;"); +else + $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); $orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); @@ -152,6 +155,10 @@ function updateTournament() { Date limite d'envoi des solutions :
Date limite d'envoi des notes de synthèse :
Description :
+ Ce tournoi est la finale nationale du TFJM² 2020.
"; + ?> /modifier">Éditer le tournoi diff --git a/server_files/tournois.php b/server_files/tournois.php index a5b04fb..5d33359 100644 --- a/server_files/tournois.php +++ b/server_files/tournois.php @@ -3,7 +3,8 @@ include 'config.php'; $response = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` - WHERE `year` = '$YEAR' ORDER BY `date_start`, `name`;"); + WHERE `year` = '$YEAR' AND `final` = false ORDER BY `date_start`, `name`;"); +$final_data = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_solutions`, `size` FROM `tournaments` WHERE `final` AND `year` = $YEAR;")->fetch(); ?> @@ -35,6 +36,13 @@ $response = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_inscripti +
">Du au
- - - - - - - - - - - - - - - - - -
- - - -
- - - -
- - - -
- -
- - - - - +query("SELECT `id`, `name` FROM `tournaments` WHERE `date_inscription` > CURRENT_DATE AND `year` = '$YEAR';"); + +if (isset($_POST["submitted"])) { + $error_message = registerTeam(); +} + +function registerTeam() { + global $DB, $YEAR, $MAIL_ADDRESS, $access_code; + + if ($_SESSION["team_id"] != NULL) + return "Vous êtes déjà dans une équipe."; + + $name = htmlspecialchars($_POST["name"]); + + if (!isset($name) || $name == "") + return "Vous devez spécifier un nom d'équipe."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe existe déjà avec ce nom."; + + $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); + + if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) + return "Le trigramme entré n'est pas valide."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe a déjà choisi ce trigramme."; + + $tournament_id = intval(htmlspecialchars($_POST["tournament"])); + + $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "Le tournoi spécifié n'existe pas."; + + $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; + $access_code = ""; + for ($i = 0; $i < 6; ++$i) + $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; + + $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); + $req->execute([$name, $trigram, $tournament_id, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, + $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + $data_team = $result->fetch(); + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); + + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; + $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; + $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; + $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; + mail($_SESSION["email"], "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

Vous devez être participant ou encadrant pour pouvoir ajouter une équipe.

+ +

Vous êtes déjà dans une équipe.

+ + Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : + + +Erreur : " . $error_message . ""; ?> + +
+ + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ +
+
+ + + + diff --git a/server_files/ajouter_organisateur.php b/server_files/ajouter_organisateur.php index 1146426..c3950e5 100644 --- a/server_files/ajouter_organisateur.php +++ b/server_files/ajouter_organisateur.php @@ -1,6 +1,6 @@ - + - + diff --git a/server_files/ajouter_tournoi.php b/server_files/ajouter_tournoi.php index 7c73a88..4ab7e02 100644 --- a/server_files/ajouter_tournoi.php +++ b/server_files/ajouter_tournoi.php @@ -1,6 +1,6 @@ query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); @@ -108,7 +108,7 @@ function registerTournament() { ?> - + - + diff --git a/server_files/confirmer_mail.php b/server_files/confirmer_mail.php index 951d5b4..317e489 100644 --- a/server_files/confirmer_mail.php +++ b/server_files/confirmer_mail.php @@ -1,6 +1,6 @@ - +

- \ No newline at end of file + \ No newline at end of file diff --git a/server_files/connexion.php b/server_files/connexion.php index 8791be3..5e3882b 100644 --- a/server_files/connexion.php +++ b/server_files/connexion.php @@ -1,6 +1,6 @@ - + Erreur : " . $error_message . ""; ?> @@ -238,6 +238,6 @@ else if (isset($_SESSION["user_id"])) { ?> - + diff --git a/server_files/deconnexion.php b/server_files/deconnexion.php index 31b50ac..f2b10b6 100644 --- a/server_files/deconnexion.php +++ b/server_files/deconnexion.php @@ -1,14 +1,14 @@ - - - - -

Déconnexion réussie !

- - + + + + +

Déconnexion réussie !

+ + diff --git a/server_files/equipe.php b/server_files/equipe.php index 60fe63f..7dc2c38 100644 --- a/server_files/equipe.php +++ b/server_files/equipe.php @@ -1,6 +1,6 @@ query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); @@ -74,7 +74,7 @@ if ($team_data["final_selection"]) { ?> - +

Informations sur l'équipe

@@ -170,4 +170,4 @@ if (!$team_data["final_selection"]) { ?> - + diff --git a/server_files/index.php b/server_files/index.php index 39fe89d..e93227b 100644 --- a/server_files/index.php +++ b/server_files/index.php @@ -1,10 +1,10 @@ - +
@@ -111,4 +111,4 @@ include 'config.php';
- \ No newline at end of file + \ No newline at end of file diff --git a/server_files/informations.php b/server_files/informations.php index d80d70b..d32a7f2 100644 --- a/server_files/informations.php +++ b/server_files/informations.php @@ -1,16 +1,16 @@ query("SELECT * FROM `users` WHERE `id` = $id;")->fetch(); if ($user_data === false) { - include "404.php"; + require_once "404.php"; } $team_data = false; @@ -22,7 +22,7 @@ $tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOI ?> - +

@@ -93,4 +93,4 @@ elseif ($user_data["role"] == "PARTICIPANT" || $user_data["role"] == "ENCADRANT" } } ?> - + diff --git a/server_files/inscription.php b/server_files/inscription.php index 7e23a59..751b20d 100644 --- a/server_files/inscription.php +++ b/server_files/inscription.php @@ -1,6 +1,6 @@ - + Erreur : " . $error_message . ""; ?> @@ -276,6 +276,6 @@ function register() { selectRole(); - + diff --git a/server_files/mon_compte.php b/server_files/mon_compte.php index 35b5e0f..1c19358 100644 --- a/server_files/mon_compte.php +++ b/server_files/mon_compte.php @@ -1,323 +1,323 @@ -query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "';"); - $user_data = $result->fetch(); -} - -function updateAccount() -{ - global $DB, $URL_BASE, $MAIL_ADDRESS; - - if (!isset($_SESSION["user_id"])) - return "Vous n'êtes pas connecté."; - - $ID = $_SESSION["user_id"]; - - $surname = htmlspecialchars($_POST["surname"]); - if (isset($surname) && $surname != "") - $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $ID]); - - $first_name = htmlspecialchars($_POST["firstname"]); - if (isset($first_name) && $first_name != "") - $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $ID]); - - $birth_date = htmlspecialchars($_POST["birth_date"]); - if (isset($birth_date) && $birth_date != "") - $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $ID]); - - if (isset($_POST["gender"])) { - $gender = htmlspecialchars($_POST["gender"]); - if (isset($gender) && ($gender == "M" || $gender == "F")) - $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $ID]); - } - - $address = htmlspecialchars($_POST["address"]); - if (isset($address) && $address != "") - $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $ID]); - - $postal_code = htmlspecialchars($_POST["postal_code"]); - if (isset($postal_code) && $postal_code != "") - $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $ID]); - - $city = htmlspecialchars($_POST["city"]); - if (isset($city) && $city != "") - $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $ID]); - - $country = htmlspecialchars($_POST["country"]); - if (isset($country) && $country != "") - $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $ID]); - - $phone_number = htmlspecialchars($_POST["phone_number"]); - if (isset($phone_number) && $phone_number != "") - $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $ID]); - - if (isset($_POST["school"])) { - $school = htmlspecialchars($_POST["school"]); - if (isset($school) && $school != "") - $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $ID]); - } - - if (isset($_POST["class"])) { - $class = htmlspecialchars($_POST["class"]); - if (isset($class) && ($class == "terminale" || $class == "premiere" || $class == "seconde")) - $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([strtoupper($class), $ID]); - } - - if (isset($_POST["responsible_name"])) { - $responsible_name = htmlspecialchars($_POST["responsible_name"]); - if (isset($responsible_name) && $responsible_name != "") - $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $ID]); - } - - if (isset($_POST["responsible_phone"])) { - $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); - if (isset($responsible_phone) && $responsible_phone != "") - $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $ID]); - } - - if (isset($_POST["responsible_email"])) { - $responsible_email = htmlspecialchars($_POST["responsible_email"]); - if (isset($responsible_email) && $responsible_email != "") - $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $ID]); - } - - if (isset($_POST["description"])) { - $description = htmlspecialchars($_POST["description"]); - if (isset($description) && $description != "") - $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$description, $ID]); - } - - $email = htmlspecialchars($_POST["email"]); - if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { - $confirm_email_uid = uniqid(); - $DB->prepare("UPDATE `users` SET `email` = ?, `confirm_email` = ? WHERE `id` = ?;")->execute([$email, $confirm_email_uid, $ID]); - - $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; - mail($email, "Changement d'adresse mail - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); - } - - return false; -} - -function updatePassword() -{ - global $DB, $YEAR; - - $old = htmlspecialchars($_POST["old_password"]); - $new = htmlspecialchars($_POST["new_password"]); - $confirm = htmlspecialchars($_POST["confirm_password"]); - - $result = $DB->query("SELECT `pwd_hash` FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - return "Le compte n'existe pas."; - - if (!password_verify($old, $data["pwd_hash"])) - return "L'ancien mot de passe est incorrect."; - - if (strlen($new) < 8) - return "Le mot de passe doit comporter au moins 8 caractères."; - - if ($new != $confirm) - return "Les deux mots de passe sont différents."; - - $hash = password_hash($new, PASSWORD_BCRYPT); - - $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$hash, $_SESSION["user_id"]]); - - return false; -} - -?> - - - -Vous devez être connecté pour afficher cette page."; - include "footer.php"; - return; -} ?> - -Erreur : " . $error_message . ""; ?> - - -

Votre compte a bien été mis à jour !

- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/> - />
- - - -
- -
- - - -
- -
- - - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - -
-
- - +query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "';"); + $user_data = $result->fetch(); +} + +function updateAccount() +{ + global $DB, $URL_BASE, $MAIL_ADDRESS; + + if (!isset($_SESSION["user_id"])) + return "Vous n'êtes pas connecté."; + + $ID = $_SESSION["user_id"]; + + $surname = htmlspecialchars($_POST["surname"]); + if (isset($surname) && $surname != "") + $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $ID]); + + $first_name = htmlspecialchars($_POST["firstname"]); + if (isset($first_name) && $first_name != "") + $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $ID]); + + $birth_date = htmlspecialchars($_POST["birth_date"]); + if (isset($birth_date) && $birth_date != "") + $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $ID]); + + if (isset($_POST["gender"])) { + $gender = htmlspecialchars($_POST["gender"]); + if (isset($gender) && ($gender == "M" || $gender == "F")) + $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $ID]); + } + + $address = htmlspecialchars($_POST["address"]); + if (isset($address) && $address != "") + $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $ID]); + + $postal_code = htmlspecialchars($_POST["postal_code"]); + if (isset($postal_code) && $postal_code != "") + $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $ID]); + + $city = htmlspecialchars($_POST["city"]); + if (isset($city) && $city != "") + $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $ID]); + + $country = htmlspecialchars($_POST["country"]); + if (isset($country) && $country != "") + $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $ID]); + + $phone_number = htmlspecialchars($_POST["phone_number"]); + if (isset($phone_number) && $phone_number != "") + $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $ID]); + + if (isset($_POST["school"])) { + $school = htmlspecialchars($_POST["school"]); + if (isset($school) && $school != "") + $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $ID]); + } + + if (isset($_POST["class"])) { + $class = htmlspecialchars($_POST["class"]); + if (isset($class) && ($class == "terminale" || $class == "premiere" || $class == "seconde")) + $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([strtoupper($class), $ID]); + } + + if (isset($_POST["responsible_name"])) { + $responsible_name = htmlspecialchars($_POST["responsible_name"]); + if (isset($responsible_name) && $responsible_name != "") + $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $ID]); + } + + if (isset($_POST["responsible_phone"])) { + $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); + if (isset($responsible_phone) && $responsible_phone != "") + $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $ID]); + } + + if (isset($_POST["responsible_email"])) { + $responsible_email = htmlspecialchars($_POST["responsible_email"]); + if (isset($responsible_email) && $responsible_email != "") + $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $ID]); + } + + if (isset($_POST["description"])) { + $description = htmlspecialchars($_POST["description"]); + if (isset($description) && $description != "") + $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$description, $ID]); + } + + $email = htmlspecialchars($_POST["email"]); + if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { + $confirm_email_uid = uniqid(); + $DB->prepare("UPDATE `users` SET `email` = ?, `confirm_email` = ? WHERE `id` = ?;")->execute([$email, $confirm_email_uid, $ID]); + + $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; + mail($email, "Changement d'adresse mail - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + } + + return false; +} + +function updatePassword() +{ + global $DB, $YEAR; + + $old = htmlspecialchars($_POST["old_password"]); + $new = htmlspecialchars($_POST["new_password"]); + $confirm = htmlspecialchars($_POST["confirm_password"]); + + $result = $DB->query("SELECT `pwd_hash` FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + return "Le compte n'existe pas."; + + if (!password_verify($old, $data["pwd_hash"])) + return "L'ancien mot de passe est incorrect."; + + if (strlen($new) < 8) + return "Le mot de passe doit comporter au moins 8 caractères."; + + if ($new != $confirm) + return "Les deux mots de passe sont différents."; + + $hash = password_hash($new, PASSWORD_BCRYPT); + + $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$hash, $_SESSION["user_id"]]); + + return false; +} + +?> + + + +Vous devez être connecté pour afficher cette page."; + require_once "footer.php"; + return; +} ?> + +Erreur : " . $error_message . ""; ?> + + +

Votre compte a bien été mis à jour !

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/> + />
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + +
+
+ + diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php index 4553d4e..92f6a40 100644 --- a/server_files/mon_equipe.php +++ b/server_files/mon_equipe.php @@ -1,6 +1,6 @@ - + Vous devez être dans une équipe pour afficher cette page."; - include "footer.php"; + require_once "footer.php"; return; } ?> @@ -364,4 +364,4 @@ Code d'accès :
- + diff --git a/server_files/rejoindre_equipe.php b/server_files/rejoindre_equipe.php index 0463f5a..3e518ad 100644 --- a/server_files/rejoindre_equipe.php +++ b/server_files/rejoindre_equipe.php @@ -1,93 +1,93 @@ -query("SELECT * FROM `teams` WHERE `access_code` = '" . $access_code . "' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - return "Ce code d'accès est invalide."; - - if ($_SESSION["role"] != "PARTICIPANT" && $_SESSION["role"] != "ENCADRANT") - return "Seuls les participants et les encadrants peuvent rejoindre une équipe."; - - if ($data["validation_status"] != "NOT_READY") - return "Cette équipe est déjà en cours de validation ou validée, vous ne pouvez pas la rejoindre."; - - for ($i = 1; $i <= $_SESSION["role"] == "PARTICIPANT" ? 6 : 2; ++$i) { - if ($data[strtolower($_SESSION["role"]) . "_" . strval($i)] == NULL) - break; - } - - if ($_SESSION["role"] == "PARTICIPANT" && $i == 7 || $_SESSION["role"] == "ENCADRANT" && $i == 3) - return "Il n'y a plus de place pour vous dans l'équipe."; - - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data["id"]]); - /** @noinspection SqlResolve */ - $DB->prepare("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_" . strval($i) . "` = ? WHERE `id` = " . $data["id"] . ";")->execute([$_SESSION["user_id"]]); - - $_SESSION["team_id"] = $data["id"]; - $_SESSION["team_validation_status"] = $data["validation_status"]; - - $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; - $msg .= "Vous venez de rejoindre l'équipe « " . $data["name"] . " » (" . $data["trigram"] . ") pour le TFJM² de " . $data["name"] . " et nous vous en remercions.\r\n\r\n"; - $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; - mail($_SESSION["email"], "Équipe rejointe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; -} - -?> - - - - -

Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

- - Vous avez bien rejoint l'équipe ! - -

Vous êtes déjà dans une équipe.

- - -Erreur : " . $error_message . ""; ?> - -
- - - - - - - - - - - -
- - - -
- -
-
- - - - +query("SELECT * FROM `teams` WHERE `access_code` = '" . $access_code . "' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + return "Ce code d'accès est invalide."; + + if ($_SESSION["role"] != "PARTICIPANT" && $_SESSION["role"] != "ENCADRANT") + return "Seuls les participants et les encadrants peuvent rejoindre une équipe."; + + if ($data["validation_status"] != "NOT_READY") + return "Cette équipe est déjà en cours de validation ou validée, vous ne pouvez pas la rejoindre."; + + for ($i = 1; $i <= $_SESSION["role"] == "PARTICIPANT" ? 6 : 2; ++$i) { + if ($data[strtolower($_SESSION["role"]) . "_" . strval($i)] == NULL) + break; + } + + if ($_SESSION["role"] == "PARTICIPANT" && $i == 7 || $_SESSION["role"] == "ENCADRANT" && $i == 3) + return "Il n'y a plus de place pour vous dans l'équipe."; + + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data["id"]]); + /** @noinspection SqlResolve */ + $DB->prepare("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_" . strval($i) . "` = ? WHERE `id` = " . $data["id"] . ";")->execute([$_SESSION["user_id"]]); + + $_SESSION["team_id"] = $data["id"]; + $_SESSION["team_validation_status"] = $data["validation_status"]; + + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; + $msg .= "Vous venez de rejoindre l'équipe « " . $data["name"] . " » (" . $data["trigram"] . ") pour le TFJM² de " . $data["name"] . " et nous vous en remercions.\r\n\r\n"; + $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; + mail($_SESSION["email"], "Équipe rejointe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

+ + Vous avez bien rejoint l'équipe ! + +

Vous êtes déjà dans une équipe.

+ + +Erreur : " . $error_message . ""; ?> + +
+ + + + + + + + + + + +
+ + + +
+ +
+
+ + + + diff --git a/server_files/solutions.php b/server_files/solutions.php index 4699162..379ccde 100644 --- a/server_files/solutions.php +++ b/server_files/solutions.php @@ -1,9 +1,9 @@ - + fetch()) !== false) { } ?> - + diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php index 891e4be..8030be8 100644 --- a/server_files/solutions_orga.php +++ b/server_files/solutions_orga.php @@ -1,9 +1,9 @@ - + - + fetch()) !== false) { ?> - + diff --git a/server_files/syntheses.php b/server_files/syntheses.php index 4c720d8..96441d7 100644 --- a/server_files/syntheses.php +++ b/server_files/syntheses.php @@ -1,9 +1,9 @@ - + Il est trop tôt pour se préoccuper des notes de synthèse, attendez le tirage des poules."; - include "footer.php"; + require_once "footer.php"; } if (isset($error_message)) { @@ -120,4 +120,4 @@ while (($data = $syntheses_req->fetch()) !== false) { } ?> - + diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php index 6e336b6..1e5b1d2 100644 --- a/server_files/syntheses_orga.php +++ b/server_files/syntheses_orga.php @@ -1,9 +1,9 @@ - + - + fetch()) !== false) { } ?> - + diff --git a/server_files/tournoi.php b/server_files/tournoi.php index 4855e01..4645ab4 100644 --- a/server_files/tournoi.php +++ b/server_files/tournoi.php @@ -1,6 +1,6 @@ execute([$tournament_name]); $data = $response->fetch(); if ($data === false) - include "404.php"; + require_once "404.php"; $orgas_req = $DB->query("SELECT `users`.`id` AS `id`, `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); $orgas = []; @@ -20,7 +20,7 @@ while (($orga_data = $orgas_req->fetch()) !== false) { } if (isset($_GET["modifier"]) && $_SESSION["role"] != "ADMIN" && !in_array($_SESSION["user_id"], $orgas_id)) - include "403.php"; + require_once "403.php"; if (isset($_POST["edit_tournament"])) { $error_message = updateTournament(); @@ -130,7 +130,7 @@ function updateTournament() { ?> - +

Tournoi de

@@ -356,4 +356,4 @@ else { } ?> - \ No newline at end of file + \ No newline at end of file diff --git a/server_files/tournois.php b/server_files/tournois.php index 5d33359..5f160db 100644 --- a/server_files/tournois.php +++ b/server_files/tournois.php @@ -1,6 +1,6 @@ query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` WHERE `year` = '$YEAR' AND `final` = false ORDER BY `date_start`, `name`;"); @@ -8,7 +8,7 @@ $final_data = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_solutio ?> - +

Liste des tournois

@@ -55,4 +55,4 @@ $final_data = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_solutio
- \ No newline at end of file + \ No newline at end of file diff --git a/server_files/view_file.php b/server_files/view_file.php index 3acf2fe..5b8fa4c 100644 --- a/server_files/view_file.php +++ b/server_files/view_file.php @@ -1,6 +1,6 @@ Date: Thu, 5 Sep 2019 19:07:59 +0200 Subject: [PATCH 027/120] =?UTF-8?q?Cr=C3=A9ation=20de=20quelques=20classes?= =?UTF-8?q?=20en=20vue=20d'une=20restructuration=20du=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/classes/role.php | 38 +++ server_files/classes/team.php | 148 +++++++++ server_files/classes/tournament.php | 186 ++++++++++++ server_files/classes/user.php | 334 +++++++++++++++++++++ server_files/classes/validation_status.php | 32 ++ 5 files changed, 738 insertions(+) create mode 100644 server_files/classes/role.php create mode 100644 server_files/classes/team.php create mode 100644 server_files/classes/tournament.php create mode 100644 server_files/classes/user.php create mode 100644 server_files/classes/validation_status.php diff --git a/server_files/classes/role.php b/server_files/classes/role.php new file mode 100644 index 0000000..7bb1ab6 --- /dev/null +++ b/server_files/classes/role.php @@ -0,0 +1,38 @@ +prepare("SELECT * FROM `teams` WHERE `id` = ?;"); + $req->execute([htmlspecialchars($id)]); + $data = $req->fetch(); + + if ($data === false) + throw new InvalidArgumentException("L'équipe spécifiée n'existe pas."); + + $this->id = $id; + $this->name = $data["name"]; + $this->trigram = $data["trigram"]; + $this->tournament = $data["tournament"]; + $this->encadrants = [$data["encadrant_1"], $data["encadrant_2"]]; + $this->participants = [$data["participant_1"], $data["participant_2"], $data["participant_3"], $data["participant_4"], $data["participant_5"], $data["participant_6"]]; + $this->inscription_date = $data["inscription_date"]; + $this->validation_status = ValidationStatus::fromName($data["validation_status"]); + $this->final_selection = $data["final_selection"] == true; + $this->access_code = $data["access_code"]; + $this->year = $data["year"]; + } + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + global $DB; + $this->name = $name; + $DB->prepare("UPDATE `teams` SET `name` = ? WHERE `id` = ?;")->execute([$name, $this->id]); + } + + public function getTrigram() + { + return $this->trigram; + } + + public function setTrigram($trigram) + { + global $DB; + $this->trigram = $trigram; + $DB->prepare("UPDATE `teams` SET `trigram` = ? WHERE `id` = ?;")->execute([$trigram, $this->id]); + } + + public function getTournamentId() + { + return $this->tournament; + } + + public function setTournamentId($tournament) + { + global $DB; + $this->tournament = $tournament; + $DB->prepare("UPDATE `teams` SET `tournament` = ? WHERE `id` = ?;")->execute([$tournament, $this->id]); + } + + public function getEncadrants() + { + return $this->encadrants; + } + + public function setEncadrant($i, $encadrant) + { + global $DB; + $this->encadrants[$i - 1] = $encadrant; + /** @noinspection SqlResolve */ + $DB->prepare("UPDATE `teams` SET `encadrant_$i` = ? WHERE `id` = ?;")->execute([$encadrant, $this->id]); + } + + public function getParticipants() + { + return $this->participants; + } + + public function setParticipant($i, $participant) + { + global $DB; + $this->participants[$i - 1] = $participant; + /** @noinspection SqlResolve */ + $DB->prepare("UPDATE `teams` SET `participant_$i` = ? WHERE `id` = ?;")->execute([$participant, $this->id]); + } + + public function getInscriptionDate() + { + return $this->inscription_date; + } + + public function getValidationStatus() + { + return $this->validation_status; + } + + public function setValidationStatus($status) + { + global $DB; + $this->validation_status = $status; + /** @noinspection PhpUndefinedMethodInspection */ + $DB->prepare("UPDATE `teams` SET `validation_status` = ? WHERE `id` = ?;")->execute([$status->getName(), $this->id]); + } + + public function isSelectedForFinal() + { + return $this->final_selection; + } + + public function selectForFinal($selected) + { + global $DB; + $this->final_selection = $selected; + $DB->prepare("UPDATE `teams` SET `final_selection` = ? WHERE `id` = ?;")->execute([$selected, $this->id]); + } + + public function getAccessCode() + { + return $this->access_code; + } + + public function getYear() + { + return $this->year; + } +} diff --git a/server_files/classes/tournament.php b/server_files/classes/tournament.php new file mode 100644 index 0000000..748cca8 --- /dev/null +++ b/server_files/classes/tournament.php @@ -0,0 +1,186 @@ +prepare("SELECT * FROM `tournaments` WHERE `id` = ?;"); + $req->execute([htmlspecialchars($id)]); + $data = $req->fetch(); + + if ($data === false) + throw new InvalidArgumentException("Le tournoi spécifié n'existe pas."); + + $this->id = $id; + $this->name = $data["name"]; + $this->size = $data["size"]; + $this->place = $data["place"]; + $this->price = $data["price"]; + $this->description = $data["description"]; + $this->date_start = $data["date_start"]; + $this->date_end = $data["date_end"]; + $this->date_inscription = $data["date_inscription"]; + $this->date_solutions = $data["date_solutions"]; + $this->date_syntheses = $data["date_syntheses"]; + $this->final = $data["final"] == true; + $this->year = $data["year"]; + } + + public function getId() + { + return $this->id; + } + + public function getName() + { + return $this->name; + } + + public function setName($name) + { + global $DB; + $this->name = $name; + $DB->prepare("UPDATE `tournaments` SET `name` = ? WHERE `id` = ?;")->execute([$name, $this->id]); + } + + public function getSize() + { + return $this->size; + } + + public function setSize($size) + { + global $DB; + $this->size = $size; + $DB->prepare("UPDATE `tournaments` SET `size` = ? WHERE `id` = ?;")->execute([$size, $this->id]); + } + + public function getPlace() + { + return $this->place; + } + + public function setPlace($place) + { + global $DB; + $this->place = $place; + $DB->prepare("UPDATE `tournaments` SET `place` = ? WHERE `id` = ?;")->execute([$place, $this->id]); + } + + public function getPrice() + { + return $this->price; + } + + public function setPrice($price) + { + global $DB; + $this->price = $price; + $DB->prepare("UPDATE `tournaments` SET `price` = ? WHERE `id` = ?;")->execute([$price, $this->id]); + } + + public function getDescription() + { + return $this->description; + } + + public function setDescription($desc) + { + global $DB; + $this->description = $desc; + $DB->prepare("UPDATE `tournaments` SET `description` = ? WHERE `id` = ?;")->execute([$desc, $this->id]); + } + + public function getStartDate() + { + return $this->date_start; + } + + public function setStartDate($date) + { + global $DB; + $this->date_start = $date; + $DB->prepare("UPDATE `tournaments` SET `date_start` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function getEndDate() + { + return $this->date_end; + } + + public function setEndDate($date) + { + global $DB; + $this->date_end = $date; + $DB->prepare("UPDATE `tournaments` SET `date_end` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function getInscriptionDate() + { + return $this->date_inscription; + } + + public function setInscriptionDate($date) + { + global $DB; + $this->date_inscription = $date; + $DB->prepare("UPDATE `tournaments` SET `date_inscription` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function getSolutionsDate() + { + return $this->date_solutions; + } + + public function setSolutionsDate($date) + { + global $DB; + $this->date_solutions = $date; + $DB->prepare("UPDATE `tournaments` SET `date_solutions` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function getSynthesesDate() + { + return $this->date_syntheses; + } + + public function setSynthesesDate($date) + { + global $DB; + $this->date_syntheses = $date; + $DB->prepare("UPDATE `tournaments` SET `date_syntheses` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function isFinal() + { + return $this->final; + } + + public function setFinal($final) + { + global $DB; + $this->final = $final; + $DB->prepare("UPDATE `tournaments` SET `final` = ? WHERE `id` = ?;")->execute([$final, $this->id]); + } + + public function getYear() + { + return $this->year; + } +} \ No newline at end of file diff --git a/server_files/classes/user.php b/server_files/classes/user.php new file mode 100644 index 0000000..692c678 --- /dev/null +++ b/server_files/classes/user.php @@ -0,0 +1,334 @@ +prepare("SELECT * FROM `users` WHERE `id` = ?;"); + $req->execute([htmlspecialchars($id)]); + $data = $req->fetch(); + + if ($data === false) + throw new InvalidArgumentException("L'utilisateur spécifié n'existe pas."); + + $this->id = $id; + $this->email = $data["email"]; + $this->pwd_hash = $data["pwd_hash"]; + $this->surname = $data["surname"]; + $this->first_name = $data["first_name"]; + $this->birth_date = $data["birth_date"]; + $this->gender = $data["gender"]; + $this->address = $data["address"]; + $this->postal_code = $data["postal_code"]; + $this->city = $data["city"]; + $this->country = $data["country"]; + $this->phone_number = $data["phone_number"]; + $this->school = $data["school"]; + $this->class = $data["class"]; + $this->responsible_name = $data["responsible_name"]; + $this->responsible_phone = $data["responsible_phone"]; + $this->responsible_email = $data["responsible_email"]; + $this->description = $data["description"]; + $this->role = Role::fromName($data["role"]); + $this->team_id = $data["team_id"]; + $this->year = $data["year"]; + $this->confirm_email = $data["confirm_email"]; + $this->forgotten_password = $data["forgotten_password"]; + + } + + public function getEmail() + { + return $this->email; + } + + public function setEmail($email) + { + global $DB; + $this->email = $email; + $DB->prepare("UPDATE `users` SET `email` = ?, WHERE `id` = ?;")->execute([$email, $this->getId()]); + } + + public function getId() + { + return $this->id; + } + + public function checkPassword($password) + { + return password_verify($password, $this->pwd_hash); + } + + public function setPassword($password) + { + $this->setPasswordHash(password_hash($password, PASSWORD_BCRYPT)); + } + + private function setPasswordHash($password_hash) + { + global $DB; + $this->pwd_hash = $password_hash; + $DB->prepare("UPDATE `users` SET `pwd_hash` = ?, WHERE `id` = ?;")->execute([$password_hash, $this->getId()]); + } + + public function getSurname() + { + return $this->surname; + } + + public function setSurname($surname) + { + global $DB; + $this->surname = $surname; + $DB->prepare("UPDATE `users` SET `surname` = ?, WHERE `id` = ?;")->execute([$surname, $this->getId()]); + } + + public function getFirstName() + { + return $this->first_name; + } + + public function setFirstName($first_name) + { + global $DB; + $this->first_name = $first_name; + $DB->prepare("UPDATE `users` SET `first_name` = ?, WHERE `id` = ?;")->execute([$first_name, $this->getId()]); + } + + public function getBirthDate() + { + return $this->birth_date; + } + + public function setBirthDate($birth_date) + { + global $DB; + $this->birth_date = $birth_date; + $DB->prepare("UPDATE `users` SET `birth_date` = ?, WHERE `id` = ?;")->execute([$birth_date, $this->getId()]); + } + + public function getGender() + { + return $this->gender; + } + + public function setGender($gender) + { + global $DB; + $this->gender = $gender; + $DB->prepare("UPDATE `users` SET `email` = ?, WHERE `id` = ?;")->execute([$gender, $this->getId()]); + } + + public function getAddress() + { + return $this->address; + } + + public function setAddress($address) + { + global $DB; + $this->address = $address; + $DB->prepare("UPDATE `users` SET `address` = ?, WHERE `id` = ?;")->execute([$address, $this->getId()]); + } + + public function getPostalCode() + { + return $this->postal_code; + } + + public function setPostalCode($postal_code) + { + global $DB; + $this->postal_code = $postal_code; + $DB->prepare("UPDATE `users` SET `postal_code` = ?, WHERE `id` = ?;")->execute([$postal_code, $this->getId()]); + } + + public function getCity() + { + return $this->city; + } + + public function setCity($city) + { + global $DB; + $this->city = $city; + $DB->prepare("UPDATE `users` SET `city` = ?, WHERE `id` = ?;")->execute([$city, $this->getId()]); + } + + public function getCountry() + { + return $this->country; + } + + public function setCountry($country) + { + global $DB; + $this->country = $country; + $DB->prepare("UPDATE `users` SET `country` = ?, WHERE `id` = ?;")->execute([$country, $this->getId()]); + } + + public function getPhoneNumber() + { + return $this->phone_number; + } + + public function setPhoneNumber($phone_number) + { + global $DB; + $this->phone_number = $phone_number; + $DB->prepare("UPDATE `users` SET `phone_number` = ?, WHERE `id` = ?;")->execute([$phone_number, $this->getId()]); + } + + public function getSchool() + { + return $this->school; + } + + public function setSchool($school) + { + global $DB; + $this->school = $school; + $DB->prepare("UPDATE `users` SET `school` = ?, WHERE `id` = ?;")->execute([$school, $this->getId()]); + } + + public function getClass() + { + return $this->class; + } + + public function setClass($class) + { + global $DB; + $this->class = $class; + $DB->prepare("UPDATE `users` SET `class` = ?, WHERE `id` = ?;")->execute([$class, $this->getId()]); + } + + public function getResponsibleName() + { + return $this->responsible_name; + } + + public function setResponsibleName($responsible_name) + { + global $DB; + $this->responsible_name = $responsible_name; + $DB->prepare("UPDATE `users` SET `responsible_name` = ?, WHERE `id` = ?;")->execute([$responsible_name, $this->getId()]); + } + + public function getResponsiblePhone() + { + return $this->responsible_phone; + } + + public function setResponsiblePhone($responsible_phone) + { + global $DB; + $this->responsible_phone = $responsible_phone; + $DB->prepare("UPDATE `users` SET `responsible_phone` = ?, WHERE `id` = ?;")->execute([$responsible_phone, $this->getId()]); + } + + public function getResponsibleEmail() + { + return $this->responsible_email; + } + + public function setResponsibleEmail($responsible_email) + { + global $DB; + $this->responsible_email = $responsible_email; + $DB->prepare("UPDATE `users` SET `responsible_email` = ?, WHERE `id` = ?;")->execute([$responsible_email, $this->getId()]); + } + + public function getDescription() + { + return $this->description; + } + + public function setDescription($desc) + { + global $DB; + $this->description = $desc; + $DB->prepare("UPDATE `users` SET `description` = ?, WHERE `id` = ?;")->execute([$desc, $this->getId()]); + } + + public function getRole() + { + return $this->role; + } + + public function setRole($role) + { + global $DB; + $this->role = $role; + /** @noinspection PhpUndefinedMethodInspection */ + $DB->prepare("UPDATE `users` SET `email` = ?, WHERE `id` = ?;")->execute([$role->getName(), $this->getId()]); + } + + public function getTeamId() + { + return $this->team_id; + } + + public function setTeamId($team_id) + { + global $DB; + $this->team_id = $team_id; + $DB->prepare("UPDATE `users` SET `team_id` = ?, WHERE `id` = ?;")->execute([$team_id, $this->getId()]); + } + + public function getYear() + { + return $this->year; + } + + public function getConfirmEmailToken() + { + return $this->confirm_email; + } + + public function setConfirmEmailToken($token) + { + global $DB; + $this->confirm_email = $token; + $DB->prepare("UPDATE `users` SET `confirm_email` = ?, WHERE `id` = ?;")->execute([$token, $this->getId()]); + } + + public function getForgottenPasswordToken() + { + return $this->forgotten_password; + } + + public function setForgottenPasswordToken($token) + { + global $DB; + $this->forgotten_password = $token; + $DB->prepare("UPDATE `users` SET `forgotten_password` = ?, WHERE `id` = ?;")->execute([$token, $this->getId()]); + } +} \ No newline at end of file diff --git a/server_files/classes/validation_status.php b/server_files/classes/validation_status.php new file mode 100644 index 0000000..be67370 --- /dev/null +++ b/server_files/classes/validation_status.php @@ -0,0 +1,32 @@ + Date: Fri, 6 Sep 2019 12:27:23 +0200 Subject: [PATCH 028/120] Correction d'un petit bug --- server_files/403.php | 4 ++-- server_files/404.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server_files/403.php b/server_files/403.php index 76739fa..427856f 100644 --- a/server_files/403.php +++ b/server_files/403.php @@ -1,7 +1,7 @@ Date: Fri, 6 Sep 2019 12:29:42 +0200 Subject: [PATCH 029/120] =?UTF-8?q?Affichage=20d'un=20message=20si=20le=20?= =?UTF-8?q?mod=20rewrite=20est=20d=C3=A9sactiv=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/index.html b/index.html index e69de29..57acf64 100644 --- a/index.html +++ b/index.html @@ -0,0 +1 @@ +Le mod Rewrite n'est pas activé. \ No newline at end of file From a1b4c4270783462eca8bc7a135166a526e974394 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Fri, 6 Sep 2019 13:48:09 +0200 Subject: [PATCH 030/120] =?UTF-8?q?D=C3=A9ploiement=20automatique=20sur=20?= =?UTF-8?q?le=20serveur=20du=20TFJM=C2=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/deployment.xml | 7 +++++++ .idea/webServers.xml | 15 +++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 .idea/webServers.xml diff --git a/.idea/deployment.xml b/.idea/deployment.xml index 69e8a41..008b762 100644 --- a/.idea/deployment.xml +++ b/.idea/deployment.xml @@ -9,6 +9,13 @@ + + + + + + +
- - - - - + + + + + + diff --git a/server_files/header.php b/server_files/views/header.php similarity index 54% rename from server_files/header.php rename to server_files/views/header.php index d521b4f..256d8d0 100644 --- a/server_files/header.php +++ b/server_files/views/header.php @@ -1,144 +1,75 @@ -exec("UPDATE `users` SET `role` = 'ADMIN' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_SESSION["user_id"]) && isset($_GET["be-organizer"])) { - $DB->exec("UPDATE `users` SET `role` = 'ORGANIZER' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_SESSION["user_id"]) && isset($_GET["be-participant"])) { - $DB->exec("UPDATE `users` SET `role` = 'PARTICIPANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_SESSION["user_id"]) && isset($_GET["be-encadrant"])) { - $DB->exec("UPDATE `users` SET `role` = 'ENCADRANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -function quitTeam() { - global $DB, $URL_BASE; - - if ($_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") - return; - - for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); - for ($i = 1; $i <= 5; ++$i) { - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); - } - - $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - - if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { - $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); - - $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); - } - unset($_SESSION["team_id"]); - unset($_SESSION["team_validation_status"]); -} - -?> - - - - - - - Site d'inscription pour le TFJM² <?= $YEAR ?> - - - - - - - - - - - - - - - - - - - -
-
- + + + + + + Site d'inscription pour le TFJM² <?= $YEAR ?> + + + + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/server_files/views/index.php b/server_files/views/index.php new file mode 100644 index 0000000..ab44cbc --- /dev/null +++ b/server_files/views/index.php @@ -0,0 +1,104 @@ +
+ + + + + +
+ + +
+ + +

Vous souhaitez participer au tournoi ? Votre équipe est déjà formée ?

+

Créez un compte pour commencer la procédure d'inscription ou connectez-vous si votre équipe a déjà un compte.

+
+ +
+ +
+

Bienvenue sur le site d'inscription du TFJM2 !

+
+ +
+ Ce site a été conçu pour gérer les inscriptions au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens. +
+ Cliquez ici pour accéder au site de présentation du tournoi. +
+ +
+ + +

+ Attention aux échéances ! Chaque tournoi a une date limite pour les inscriptions et une date limite pour déposer vos solutions. Elles sont affichées avec les informations de chaque tournoi. Merci de vous y référer ! +
+ Une fois l'échéance passée, le site bloque tout accès aux inscriptions (et respectivement au dépôt des solutions).
+

+ +

+ Attention, modification du règlement par rapport aux années précédentes : article 4.3 +
+ "l’équipe doit envoyer par mail à contact@tfjm.org, une lettre (au format pdf), répondant aux questions suivantes : +
+ +

    +
  • Comment l’équipe s’est-elle formée ?
  • +
  • Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres avec l’encadrant•e) ?
  • +
+ + Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non l’inscription des équipes concernées par cette lettre." +
+ + Pour plus de détail, voir le règlement : https://tfjm.org/infos-tournois/ +

+ + +
+

Comment ça marche ?

+
+ +

+ Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer par la suite. +

+ +

+ Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : +

    +
  • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
  • +
  • enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière version enregistrée avant + la date limite sera prise en compte pour le tournoi).
  • +
+ + Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, votre inscription pourra être validée par les organisateurs locaux. +

+ + +

ATTENTION ! Votre équipe ne sera considérée comme admissible à participer au tournoi que lorsque cette première étape aura été franchie.

+ +

Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes seront placées en liste d'attente. +

+ +

+ Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers le site pour compléter votre inscription. +

+ + +

ATTENTION ! Les équipes qui ne respecteront pas les délais pour rendre ces documents risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente.

+ +

+ NB : Ce site est récent et il est encore possible que certaines pages ne fonctionnent pas correctement. Si vous remarquez des bugs, merci de les signaler à l'adresse contact@tfjm.org. +

+ + + + + + + + + +
\ No newline at end of file diff --git a/server_files/informations.php b/server_files/views/informations.php similarity index 74% rename from server_files/informations.php rename to server_files/views/informations.php index d32a7f2..a96220e 100644 --- a/server_files/informations.php +++ b/server_files/views/informations.php @@ -1,35 +1,9 @@ -query("SELECT * FROM `users` WHERE `id` = $id;")->fetch(); - -if ($user_data === false) { - require_once "404.php"; -} - -$team_data = false; -if ($user_data["team_id"] !== NULL) - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = " . $user_data["team_id"] . ";")->fetch(); - -$documents_req = $DB->query("SELECT * FROM `documents` WHERE `user` = $id;"); -$tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `date_start`, `name`;"); - -?> - - -

Équipe : " . $team_data["name"] . " (" . $team_data["trigram"] . ")" ?>
-Date de naissance :
+Date de naissance :
Sexe :
Adresse :
Adresse e-mail : ">
@@ -91,6 +65,4 @@ elseif ($user_data["role"] == "PARTICIPANT" || $user_data["role"] == "ENCADRANT" } echo "$name de $first_name $surname : Télécharger
"; } -} ?> - - +} \ No newline at end of file diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php new file mode 100644 index 0000000..4718ea8 --- /dev/null +++ b/server_files/views/inscription.php @@ -0,0 +1,145 @@ +Erreur : " . $error_message . ""; ?> + + + Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. + + +

Vous êtes déjà connecté !

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
" required />
" required />
" required />
" required />
/> + />
" />
" min="1000" max="95999" required />
" />
" required />
" />
" />
" />
" />
" />
+
+ + + + \ No newline at end of file diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php new file mode 100644 index 0000000..bca8208 --- /dev/null +++ b/server_files/views/mon_compte.php @@ -0,0 +1,173 @@ +Erreur : " . $error_message . ""; ?> + + +

Votre compte a bien été mis à jour !

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
/> + />
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php new file mode 100644 index 0000000..988996a --- /dev/null +++ b/server_files/views/mon_equipe.php @@ -0,0 +1,164 @@ +Erreur : " . $error_message . ""; + } else { + echo "

Le fichier a été correctement envoyé !

"; + } +} ?> + +

Informations sur l'équipe

+ +Nom de l'équipe :
+Trigramme :
+Tournoi : ">
+query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; +} +for ($i = 1; $i <= 6; ++$i) { + if ($team_data["participant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; +} +?> +Code d'accès :
+Équipe sélectionnée pour la finale nationale.
"; +} ?> + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + "/> +
+ + + "/> +
+ + + +
+ +
+
+ + + + + + Modifier mon équipe + +
+

Mes autorisations

+ fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name : Télécharger
"; + } + if ($team_data["validation_status"] == "NOT_READY") { ?> +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ +
+ + + + + + + + +
+
+ +
+
+
+ +
+
+ + diff --git a/server_files/views/rejoindre_equipe.php b/server_files/views/rejoindre_equipe.php new file mode 100644 index 0000000..71273c2 --- /dev/null +++ b/server_files/views/rejoindre_equipe.php @@ -0,0 +1,34 @@ + +

Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

+ + Vous avez bien rejoint l'équipe ! + +

Vous êtes déjà dans une équipe.

+ + + Erreur : " . $error_message . ""; ?> + +
+ + + + + + + + + + + +
+ + + +
+ +
+
+ + \ No newline at end of file diff --git a/server_files/views/solutions.php b/server_files/views/solutions.php new file mode 100644 index 0000000..6c1a36f --- /dev/null +++ b/server_files/views/solutions.php @@ -0,0 +1,58 @@ +Erreur : " . $error_message . ""; + } else { + echo "

Le fichier a été correctement envoyé !

"; + } +}?> + + +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ +

Solutions soumises :

+ +fetch()) !== false) { + $file_id = $data["file_id"]; + $problem = $data["problem"]; + $version = $data["version"]; + echo "Problème $problem (Version $version) : Télécharger
"; +} +?> + diff --git a/server_files/views/syntheses.php b/server_files/views/syntheses.php new file mode 100644 index 0000000..e05ed0b --- /dev/null +++ b/server_files/views/syntheses.php @@ -0,0 +1,61 @@ +Il est trop tôt pour se préoccuper des notes de synthèse, attendez le tirage des poules."; + require_once "../views/footer.php"; +} + +if (isset($error_message)) { + if ($error_message !== false) { + echo "

Erreur : " . $error_message . "

"; + } + else { + echo "

Le fichier a été correctement envoyé !

"; + } +}?> + + +
+ + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ +

Notes de synthèse soumises :

+ +fetch()) !== false) { + $file_id = $data["file_id"]; + $dest = $data["dest"]; + $version = $data["version"]; + echo "Note de synthèse pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . " (Version $version) : Télécharger
"; +} +?> \ No newline at end of file diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php new file mode 100644 index 0000000..a058b66 --- /dev/null +++ b/server_files/views/tournoi.php @@ -0,0 +1,222 @@ +

Tournoi de

+ +Organisateur= 2 ? 's' : '' ?> : +$orgas[$i]"; + else + $s .= $orgas[$i]; + $s .= ", "; +} +echo substr($s, 0, -2); +?> +
+Nombre d'équipes maximal :
+Lieu :
+Prix par partipant :
+Dates : Du au
+Clôture des inscriptions :
+Date limite d'envoi des solutions :
+Date limite d'envoi des notes de synthèse :
+Description :
+Ce tournoi est la finale nationale du TFJM² 2020.
"; +?> + + + /modifier">Éditer le tournoi + + + + +
+ +

Équipes inscrites à ce tournoi :

+ + + + + + + + + + + + fetch()) != false) { + ?> + + + + + + + + + + + + + + + + +
+ Équipe + + Trigramme + + Date d'inscription + + État de validation de l'inscription +
+ " . $team_data["name"] . ""; + else + echo $team_data["name"]; + ?> + + +
+ Équipe + + Trigramme + + Date d'inscription + + État de validation de l'inscription +
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + " required /> +
+ + + +
+ + + " required /> +
+ + + " required /> +
+ + + " required /> +
+ + + Du " required /> + au " required /> +
+ + + " required /> + " required /> +
+ + + " required /> + " required /> +
+ + + " required /> + " required /> +
+ + + +
+ +
+
+ + diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php new file mode 100644 index 0000000..b145b75 --- /dev/null +++ b/server_files/views/tournois.php @@ -0,0 +1,44 @@ +

Liste des tournois

+ + + + + + + + + + + + + fetch()) !== FALSE) { + ?> + + + + + + + + + + + + + + + + + + + + + + + + + +
LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
">Du au
">Du au
LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
\ No newline at end of file From b5d567e3644b7b9883257ebefa3ae729f9b0b710 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Fri, 6 Sep 2019 14:02:32 +0200 Subject: [PATCH 032/120] Nouveaux constructeurs pour les classes --- server_files/classes/Team.php | 28 +++++++++++- server_files/classes/Tournament.php | 34 ++++++++++++-- server_files/classes/User.php | 71 +++++++++++++++++++---------- 3 files changed, 102 insertions(+), 31 deletions(-) diff --git a/server_files/classes/Team.php b/server_files/classes/Team.php index 08a2e02..094b1ce 100644 --- a/server_files/classes/Team.php +++ b/server_files/classes/Team.php @@ -16,7 +16,9 @@ class Team private $access_code; private $year; - public function __construct($id) + private function __construct() {} + + public static function fromId($id) { global $DB; $req = $DB->prepare("SELECT * FROM `teams` WHERE `id` = ?;"); @@ -26,7 +28,29 @@ class Team if ($data === false) throw new InvalidArgumentException("L'équipe spécifiée n'existe pas."); - $this->id = $id; + $team = new Team(); + $team->fill($data); + return $team; + } + + public static function fromTrigram($trigram) + { + global $DB, $YEAR; + $req = $DB->prepare("SELECT * FROM `teams` WHERE `trigram` = ? AND `year` = $YEAR;"); + $req->execute([htmlspecialchars($trigram)]); + $data = $req->fetch(); + + if ($data === false) + throw new InvalidArgumentException("L'équipe spécifiée n'existe pas."); + + $team = new Team(); + $team->fill($data); + return $team; + } + + private function fill($data) + { + $this->id = $data["id"]; $this->name = $data["name"]; $this->trigram = $data["trigram"]; $this->tournament = $data["tournament"]; diff --git a/server_files/classes/Tournament.php b/server_files/classes/Tournament.php index 748cca8..fd4cd69 100644 --- a/server_files/classes/Tournament.php +++ b/server_files/classes/Tournament.php @@ -17,9 +17,11 @@ class Tournament private $final; private $year; - public function __construct($id) - { - global $DB; + private function __construct() {} + + public static function fromId($id) + { + global $DB; $req = $DB->prepare("SELECT * FROM `tournaments` WHERE `id` = ?;"); $req->execute([htmlspecialchars($id)]); $data = $req->fetch(); @@ -27,7 +29,29 @@ class Tournament if ($data === false) throw new InvalidArgumentException("Le tournoi spécifié n'existe pas."); - $this->id = $id; + $tournament = new Tournament(); + $tournament->fill($data); + return $tournament; + } + + public static function fromName($name) + { + global $DB, $YEAR; + $req = $DB->prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year` = $YEAR;"); + $req->execute([htmlspecialchars($name)]); + $data = $req->fetch(); + + if ($data === false) + throw new InvalidArgumentException("Le tournoi spécifié n'existe pas."); + + $tournament = new Tournament(); + $tournament->fill($data); + return $tournament; + } + + private function fill($data) + { + $this->id = $data["id"]; $this->name = $data["name"]; $this->size = $data["size"]; $this->place = $data["place"]; @@ -40,7 +64,7 @@ class Tournament $this->date_syntheses = $data["date_syntheses"]; $this->final = $data["final"] == true; $this->year = $data["year"]; - } + } public function getId() { diff --git a/server_files/classes/User.php b/server_files/classes/User.php index 692c678..0f7afad 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -27,8 +27,10 @@ class User private $year; private $confirm_email; private $forgotten_password; + + private function __construct() {} - public function __construct($id) + public static function fromId($id) { global $DB; $req = $DB->prepare("SELECT * FROM `users` WHERE `id` = ?;"); @@ -38,7 +40,29 @@ class User if ($data === false) throw new InvalidArgumentException("L'utilisateur spécifié n'existe pas."); - $this->id = $id; + $user = new User(); + $user->fill($data); + return $user; + } + + public static function fromEmail($email) + { + global $DB, $YEAR; + $req = $DB->prepare("SELECT * FROM `users` WHERE `email` = ? AND `year` = $YEAR;"); + $req->execute([htmlspecialchars($email)]); + $data = $req->fetch(); + + if ($data === false) + throw new InvalidArgumentException("L'utilisateur spécifié n'existe pas."); + + $user = new User(); + $user->fill($data); + return $user; + } + + private function fill($data) + { + $this->id = $data["id"]; $this->email = $data["email"]; $this->pwd_hash = $data["pwd_hash"]; $this->surname = $data["surname"]; @@ -61,7 +85,6 @@ class User $this->year = $data["year"]; $this->confirm_email = $data["confirm_email"]; $this->forgotten_password = $data["forgotten_password"]; - } public function getEmail() @@ -73,7 +96,7 @@ class User { global $DB; $this->email = $email; - $DB->prepare("UPDATE `users` SET `email` = ?, WHERE `id` = ?;")->execute([$email, $this->getId()]); + $DB->prepare("UPDATE `users` SET `email` = ? WHERE `id` = ?;")->execute([$email, $this->getId()]); } public function getId() @@ -95,7 +118,7 @@ class User { global $DB; $this->pwd_hash = $password_hash; - $DB->prepare("UPDATE `users` SET `pwd_hash` = ?, WHERE `id` = ?;")->execute([$password_hash, $this->getId()]); + $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$password_hash, $this->getId()]); } public function getSurname() @@ -107,7 +130,7 @@ class User { global $DB; $this->surname = $surname; - $DB->prepare("UPDATE `users` SET `surname` = ?, WHERE `id` = ?;")->execute([$surname, $this->getId()]); + $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $this->getId()]); } public function getFirstName() @@ -119,7 +142,7 @@ class User { global $DB; $this->first_name = $first_name; - $DB->prepare("UPDATE `users` SET `first_name` = ?, WHERE `id` = ?;")->execute([$first_name, $this->getId()]); + $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $this->getId()]); } public function getBirthDate() @@ -131,7 +154,7 @@ class User { global $DB; $this->birth_date = $birth_date; - $DB->prepare("UPDATE `users` SET `birth_date` = ?, WHERE `id` = ?;")->execute([$birth_date, $this->getId()]); + $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $this->getId()]); } public function getGender() @@ -143,7 +166,7 @@ class User { global $DB; $this->gender = $gender; - $DB->prepare("UPDATE `users` SET `email` = ?, WHERE `id` = ?;")->execute([$gender, $this->getId()]); + $DB->prepare("UPDATE `users` SET `email` = ? WHERE `id` = ?;")->execute([$gender, $this->getId()]); } public function getAddress() @@ -155,7 +178,7 @@ class User { global $DB; $this->address = $address; - $DB->prepare("UPDATE `users` SET `address` = ?, WHERE `id` = ?;")->execute([$address, $this->getId()]); + $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $this->getId()]); } public function getPostalCode() @@ -167,7 +190,7 @@ class User { global $DB; $this->postal_code = $postal_code; - $DB->prepare("UPDATE `users` SET `postal_code` = ?, WHERE `id` = ?;")->execute([$postal_code, $this->getId()]); + $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $this->getId()]); } public function getCity() @@ -179,7 +202,7 @@ class User { global $DB; $this->city = $city; - $DB->prepare("UPDATE `users` SET `city` = ?, WHERE `id` = ?;")->execute([$city, $this->getId()]); + $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $this->getId()]); } public function getCountry() @@ -191,7 +214,7 @@ class User { global $DB; $this->country = $country; - $DB->prepare("UPDATE `users` SET `country` = ?, WHERE `id` = ?;")->execute([$country, $this->getId()]); + $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $this->getId()]); } public function getPhoneNumber() @@ -203,7 +226,7 @@ class User { global $DB; $this->phone_number = $phone_number; - $DB->prepare("UPDATE `users` SET `phone_number` = ?, WHERE `id` = ?;")->execute([$phone_number, $this->getId()]); + $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $this->getId()]); } public function getSchool() @@ -215,7 +238,7 @@ class User { global $DB; $this->school = $school; - $DB->prepare("UPDATE `users` SET `school` = ?, WHERE `id` = ?;")->execute([$school, $this->getId()]); + $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $this->getId()]); } public function getClass() @@ -227,7 +250,7 @@ class User { global $DB; $this->class = $class; - $DB->prepare("UPDATE `users` SET `class` = ?, WHERE `id` = ?;")->execute([$class, $this->getId()]); + $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([$class, $this->getId()]); } public function getResponsibleName() @@ -239,7 +262,7 @@ class User { global $DB; $this->responsible_name = $responsible_name; - $DB->prepare("UPDATE `users` SET `responsible_name` = ?, WHERE `id` = ?;")->execute([$responsible_name, $this->getId()]); + $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $this->getId()]); } public function getResponsiblePhone() @@ -251,7 +274,7 @@ class User { global $DB; $this->responsible_phone = $responsible_phone; - $DB->prepare("UPDATE `users` SET `responsible_phone` = ?, WHERE `id` = ?;")->execute([$responsible_phone, $this->getId()]); + $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $this->getId()]); } public function getResponsibleEmail() @@ -263,7 +286,7 @@ class User { global $DB; $this->responsible_email = $responsible_email; - $DB->prepare("UPDATE `users` SET `responsible_email` = ?, WHERE `id` = ?;")->execute([$responsible_email, $this->getId()]); + $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $this->getId()]); } public function getDescription() @@ -275,7 +298,7 @@ class User { global $DB; $this->description = $desc; - $DB->prepare("UPDATE `users` SET `description` = ?, WHERE `id` = ?;")->execute([$desc, $this->getId()]); + $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$desc, $this->getId()]); } public function getRole() @@ -288,7 +311,7 @@ class User global $DB; $this->role = $role; /** @noinspection PhpUndefinedMethodInspection */ - $DB->prepare("UPDATE `users` SET `email` = ?, WHERE `id` = ?;")->execute([$role->getName(), $this->getId()]); + $DB->prepare("UPDATE `users` SET `email` = ? WHERE `id` = ?;")->execute([$role->getName(), $this->getId()]); } public function getTeamId() @@ -300,7 +323,7 @@ class User { global $DB; $this->team_id = $team_id; - $DB->prepare("UPDATE `users` SET `team_id` = ?, WHERE `id` = ?;")->execute([$team_id, $this->getId()]); + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = ?;")->execute([$team_id, $this->getId()]); } public function getYear() @@ -317,7 +340,7 @@ class User { global $DB; $this->confirm_email = $token; - $DB->prepare("UPDATE `users` SET `confirm_email` = ?, WHERE `id` = ?;")->execute([$token, $this->getId()]); + $DB->prepare("UPDATE `users` SET `confirm_email` = ? WHERE `id` = ?;")->execute([$token, $this->getId()]); } public function getForgottenPasswordToken() @@ -329,6 +352,6 @@ class User { global $DB; $this->forgotten_password = $token; - $DB->prepare("UPDATE `users` SET `forgotten_password` = ?, WHERE `id` = ?;")->execute([$token, $this->getId()]); + $DB->prepare("UPDATE `users` SET `forgotten_password` = ? WHERE `id` = ?;")->execute([$token, $this->getId()]); } } \ No newline at end of file From bffaf4b3608045dea080be8632383e2158176243 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 01:33:05 +0200 Subject: [PATCH 033/120] =?UTF-8?q?Utilisation=20des=20nouvelles=20classes?= =?UTF-8?q?,=20am=C3=A9lioration=20du=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/classes/Role.php | 42 ++++--- server_files/classes/Team.php | 21 +++- server_files/classes/Tournament.php | 18 ++- server_files/classes/User.php | 15 ++- server_files/classes/ValidationStatus.php | 19 ++- server_files/config.php | 5 + server_files/controllers/ajouter_equipe.php | 26 ++-- .../controllers/ajouter_organisateur.php | 2 +- server_files/controllers/ajouter_tournoi.php | 4 +- server_files/controllers/connexion.php | 38 +++--- server_files/controllers/equipe.php | 41 +++---- server_files/controllers/informations.php | 16 +-- server_files/controllers/mon_compte.php | 64 ++++------ server_files/controllers/mon_equipe.php | 78 ++++++------ server_files/controllers/rejoindre_equipe.php | 48 ++++---- server_files/controllers/solutions_orga.php | 23 ++-- server_files/controllers/syntheses_orga.php | 23 ++-- server_files/controllers/tournoi.php | 43 +++---- server_files/controllers/view_file.php | 6 +- server_files/model.php | 112 ++++++++---------- server_files/views/ajouter_equipe.php | 7 +- server_files/views/ajouter_organisateur.php | 2 +- server_files/views/equipe.php | 32 ++--- server_files/views/header.php | 18 +-- server_files/views/informations.php | 37 +++--- server_files/views/inscription.php | 4 +- server_files/views/mon_compte.php | 40 +++---- server_files/views/mon_equipe.php | 38 +++--- server_files/views/rejoindre_equipe.php | 10 +- server_files/views/tournoi.php | 80 +++++++------ 30 files changed, 472 insertions(+), 440 deletions(-) diff --git a/server_files/classes/Role.php b/server_files/classes/Role.php index 7bb1ab6..5fa557a 100644 --- a/server_files/classes/Role.php +++ b/server_files/classes/Role.php @@ -1,27 +1,37 @@ fetch(); if ($data === false) - throw new InvalidArgumentException("L'équipe spécifiée n'existe pas."); + return null; $team = new Team(); $team->fill($data); @@ -41,7 +41,22 @@ class Team $data = $req->fetch(); if ($data === false) - throw new InvalidArgumentException("L'équipe spécifiée n'existe pas."); + return null; + + $team = new Team(); + $team->fill($data); + return $team; + } + + public static function fromAccessCode($access_code) + { + global $DB, $YEAR; + $req = $DB->prepare("SELECT * FROM `teams` WHERE `access_code` = ? AND `year` = $YEAR;"); + $req->execute([htmlspecialchars($access_code)]); + $data = $req->fetch(); + + if ($data === false) + return null; $team = new Team(); $team->fill($data); @@ -145,7 +160,7 @@ class Team global $DB; $this->validation_status = $status; /** @noinspection PhpUndefinedMethodInspection */ - $DB->prepare("UPDATE `teams` SET `validation_status` = ? WHERE `id` = ?;")->execute([$status->getName(), $this->id]); + $DB->prepare("UPDATE `teams` SET `validation_status` = ? WHERE `id` = ?;")->execute([ValidationStatus::getName($status), $this->id]); } public function isSelectedForFinal() diff --git a/server_files/classes/Tournament.php b/server_files/classes/Tournament.php index fd4cd69..9c4641c 100644 --- a/server_files/classes/Tournament.php +++ b/server_files/classes/Tournament.php @@ -27,7 +27,7 @@ class Tournament $data = $req->fetch(); if ($data === false) - throw new InvalidArgumentException("Le tournoi spécifié n'existe pas."); + return null; $tournament = new Tournament(); $tournament->fill($data); @@ -42,7 +42,21 @@ class Tournament $data = $req->fetch(); if ($data === false) - throw new InvalidArgumentException("Le tournoi spécifié n'existe pas."); + return null; + + $tournament = new Tournament(); + $tournament->fill($data); + return $tournament; + } + + public static function getFinalTournament() + { + global $DB, $YEAR; + $req = $DB->query("SELECT * FROM `tournaments` WHERE `final` AND `year` = $YEAR;"); + $data = $req->fetch(); + + if ($data === false) + return null; $tournament = new Tournament(); $tournament->fill($data); diff --git a/server_files/classes/User.php b/server_files/classes/User.php index 0f7afad..b9326bc 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -27,6 +27,7 @@ class User private $year; private $confirm_email; private $forgotten_password; + private $inscription_date; private function __construct() {} @@ -38,7 +39,7 @@ class User $data = $req->fetch(); if ($data === false) - throw new InvalidArgumentException("L'utilisateur spécifié n'existe pas."); + return null; $user = new User(); $user->fill($data); @@ -53,7 +54,7 @@ class User $data = $req->fetch(); if ($data === false) - throw new InvalidArgumentException("L'utilisateur spécifié n'existe pas."); + return null; $user = new User(); $user->fill($data); @@ -85,6 +86,7 @@ class User $this->year = $data["year"]; $this->confirm_email = $data["confirm_email"]; $this->forgotten_password = $data["forgotten_password"]; + $this->inscription_date = $data["inscription_date"]; } public function getEmail() @@ -166,7 +168,7 @@ class User { global $DB; $this->gender = $gender; - $DB->prepare("UPDATE `users` SET `email` = ? WHERE `id` = ?;")->execute([$gender, $this->getId()]); + $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $this->getId()]); } public function getAddress() @@ -311,7 +313,7 @@ class User global $DB; $this->role = $role; /** @noinspection PhpUndefinedMethodInspection */ - $DB->prepare("UPDATE `users` SET `email` = ? WHERE `id` = ?;")->execute([$role->getName(), $this->getId()]); + $DB->prepare("UPDATE `users` SET `role` = ? WHERE `id` = ?;")->execute([Role::getName($role), $this->getId()]); } public function getTeamId() @@ -354,4 +356,9 @@ class User $this->forgotten_password = $token; $DB->prepare("UPDATE `users` SET `forgotten_password` = ? WHERE `id` = ?;")->execute([$token, $this->getId()]); } + + public function getInscriptionDate() + { + return $this->inscription_date; + } } \ No newline at end of file diff --git a/server_files/classes/ValidationStatus.php b/server_files/classes/ValidationStatus.php index be67370..459d7ad 100644 --- a/server_files/classes/ValidationStatus.php +++ b/server_files/classes/ValidationStatus.php @@ -1,15 +1,13 @@ query("SELECT `id`, `name` FROM `tournaments` WHERE `date_inscription` > CURRENT_DATE AND `year` = '$YEAR';"); if (isset($_POST["submitted"])) { @@ -11,7 +14,7 @@ if (isset($_POST["submitted"])) { function registerTeam() { global $DB, $YEAR, $MAIL_ADDRESS, $access_code; - if ($_SESSION["team_id"] != NULL) + if ($_SESSION["team"] != NULL) return "Vous êtes déjà dans une équipe."; $name = htmlspecialchars($_POST["name"]); @@ -33,10 +36,8 @@ function registerTeam() { return "Une équipe a déjà choisi ce trigramme."; $tournament_id = intval(htmlspecialchars($_POST["tournament"])); - - $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) + $tournament = Tournament::fromId($tournament_id); + if ($tournament === null) return "Le tournoi spécifié n'existe pas."; $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; @@ -46,18 +47,17 @@ function registerTeam() { $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$name, $trigram, $tournament_id, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, - $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); + $req->execute([$name, $trigram, $tournament_id, $_SESSION["role"] == Role::ENCADRANT ? $_SESSION["user_id"] : NULL, + $_SESSION["role"] == Role::PARTICIPANT ? $_SESSION["user_id"] : NULL, ValidationStatus::NOT_READY, $access_code, $YEAR]); - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - $data_team = $result->fetch(); - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); + $_SESSION["team"] = Team::fromTrigram($trigram); + $_SESSION["user"]->setTeamId($_SESSION["team"]->getId()); - $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; - $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; + $msg = "Bonjour " . $_SESSION["user"]->getFirstName() . " " . $_SESSION["user"]->getSurname() . ",\r\n\r\n"; + $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $tournament->getName() . " et nous vous en remercions. "; $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; - mail($_SESSION["email"], "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + mail($_SESSION["user"]->getEmail(), "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); return false; } diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index 6c91bfe..3300334 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -2,7 +2,7 @@ require_once "../config.php"; -if (!isset($_SESSION["role"]) || $_SESSION["role"] != "ADMIN") +if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) require_once "../403.php"; if (isset($_POST["submitted"])) { diff --git a/server_files/controllers/ajouter_tournoi.php b/server_files/controllers/ajouter_tournoi.php index c323c7e..5b6a3d8 100644 --- a/server_files/controllers/ajouter_tournoi.php +++ b/server_files/controllers/ajouter_tournoi.php @@ -2,7 +2,7 @@ require_once "../config.php"; -if (!isset($_SESSION["role"]) || $_SESSION["role"] != "ADMIN") +if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) require_once "../403.php"; $orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); @@ -31,7 +31,7 @@ function registerTournament() { $data = $result->fetch(); if ($data === FALSE) return "L'organisateur spécifié n'existe pas."; - if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") + if ($data["role"] != Role::ORGANIZER && $data["role"] != Role::ADMIN) return "L'organisateur indiqué ne peut pas organiser de tournoi."; $orga_mails[] = $data["email"]; } diff --git a/server_files/controllers/connexion.php b/server_files/controllers/connexion.php index a5dd18b..dda3d3e 100644 --- a/server_files/controllers/connexion.php +++ b/server_files/controllers/connexion.php @@ -26,7 +26,7 @@ if (isset($_GET["confirmation-mail"]) && !isset($_SESSION["user_id"])) { } function login() { - global $DB, $URL_BASE; + global $URL_BASE; $email = htmlspecialchars($_POST["email"]); @@ -35,39 +35,39 @@ function login() { $password = htmlspecialchars($_POST["password"]); - $result = $DB->query("SELECT `id`, `pwd_hash`, `email`, `surname`, `first_name`, `role`, `team_id`, `confirm_email` FROM `users` WHERE `email` = '" . $email . "';"); - if (($data = $result->fetch()) === FALSE) + $user = User::fromEmail($email); + if ($user === FALSE) return "Le compte n'existe pas."; - if ($data["confirm_email"] !== NULL) { + if ($user->getConfirmEmailToken() !== NULL) { $_SESSION["confirm_email"] = $email; return "L'adresse mail n'a pas été validée. Veuillez vérifier votre boîte mail (surtout vos spams). Cliquez ici pour renvoyer le mail de confirmation."; } - if (!password_verify($password, $data["pwd_hash"])) + if (!$user->checkPassword($password)) return "Le mot de passe est incorrect."; - $_SESSION["user_id"] = $data["id"]; + $_SESSION["user_id"] = $user->getId(); loadUserValues(); return false; } function recuperateAccount() { - global $DB, $MAIL_ADDRESS, $URL_BASE, $YEAR; + global $MAIL_ADDRESS, $URL_BASE; $email = htmlspecialchars($_POST["email"]); if (!filter_var($email, FILTER_VALIDATE_EMAIL)) return "L'email entrée est invalide."; - $req = $DB->query("SELECT `id` FROM `users` WHERE `email` = '$email' AND `year` = $YEAR;"); - if (!$req->fetch()) + $user = User::fromEmail($email); + if ($user == null) return "Le compte n'existe pas."; $token = uniqid(); - - $DB->exec("UPDATE `users` SET `forgotten_password` = '$token' WHERE `email` = '$email' AND `year` = $YEAR;"); + + $user->setForgottenPasswordToken($token); $msg = "Bonjour,\r\n\r\n" . "Vous avez indiqué avoir oublié votre mot de passe. Veuillez cliquer ici pour le réinitialiser : $URL_BASE/connexion/reinitialiser_mdp/$token\r\n\r\n" @@ -81,7 +81,7 @@ function recuperateAccount() { function resetPassword() { global $DB, $MAIL_ADDRESS, $reset_data; - + $id = $reset_data["id"]; $email = $reset_data["email"]; $password = htmlspecialchars($_POST["password"]); @@ -92,9 +92,9 @@ function resetPassword() { if ($password != $confirm) return "Les deux mots de passe sont différents."; - + $hash = password_hash($password, PASSWORD_BCRYPT); - + $DB->prepare("UPDATE `users` SET `pwd_hash` = ?, `forgotten_password` = NULL WHERE `id` = ?;")->execute([$hash, $id]); $msg = "Bonjour,\r\n\r\nNous vous informons que votre mot de passe vient d'être modifié. " @@ -106,7 +106,7 @@ function resetPassword() { } function sendConfirmEmail() { - global $DB, $URL_BASE, $MAIL_ADDRESS, $YEAR; + global $URL_BASE, $MAIL_ADDRESS, $YEAR; $email = htmlspecialchars($_SESSION["confirm_email"]); @@ -114,16 +114,16 @@ function sendConfirmEmail() { header("Location: $URL_BASE/connexion"); exit(); } + + $user = User::fromEmail($email); - $data = $DB->query("SELECT `confirm_email` FROM `users` WHERE `email` = '$email' AND `year` = $YEAR;")->fetch(); - - if ($data === FALSE) { + if ($user === null) { unset($_SESSION["confirm_email"]); header("Location: $URL_BASE/connexion"); exit(); } - $confirm_email_uid = $data["confirm_email"]; + $confirm_email_uid = $user->getConfirmEmailToken(); $msg = "Bonjour,\r\n\r\nPour confirmer votre adresse mail, cliquez ici : $URL_BASE/confirmer_mail/$confirm_email_uid\r\n\r\n" . "Cordialement,\r\n\r\nLe comité national d'organisation du TFJM²"; diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 4fdec18..40364aa 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -2,23 +2,27 @@ require_once "../config.php"; +if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ORGANIZER && $_SESSION["role"] != Role::ADMIN) + require_once "../403.php"; + $trigram = htmlspecialchars($_GET["trigram"]); +$team = Team::fromTrigram($trigram); + +if ($team === null) + require_once "../404.php"; + if (isset($_POST["validate"])) { - $DB->exec("UPDATE `teams` SET `validation_status` = 'VALIDATED' WHERE `trigram` = '$trigram' AND `year` = $YEAR;"); + $team->setValidationStatus(ValidationStatus::VALIDATED); } -$team_data = $DB->query("SELECT * FROM `teams` WHERE `trigram` = '$trigram' AND `year` = $YEAR;")->fetch(); - if (isset($_POST["select"])) { - $DB->exec("UPDATE `teams` SET `final_selection` = true, `validation_status` = 'NOT_READY' WHERE `trigram` = '$trigram' AND `year` = $YEAR;"); - $team_data["validation_status"] = "NOT_READY"; - $team_data["final_selection"] = true; - $final_id = $_SESSION["final_id"]; - $team_id = $team_data["id"]; + $team->selectForFinal(true); + $team->setValidationStatus(ValidationStatus::NOT_READY); + $_SESSION["final"] = Tournament::getFinalTournament(); $sols_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); - $sols_req->execute([$team_data["id"], $team_data["tournament"]]); + $sols_req->execute([$team->getId(), $team->getTournamentId()]); while (($sol_data = $sols_req->fetch()) !== false) { $old_id = $sol_data["file_id"]; $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -35,11 +39,11 @@ if (isset($_POST["select"])) { $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team_id, $_SESSION["final_id"], $sol_data["problem"]]); + $req->execute([$id, $team->getId(), $_SESSION["final_id"], $sol_data["problem"]]); } $syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); - $syntheses_req->execute([$team_data["id"], $team_data["tournament"]]); + $syntheses_req->execute([$team->getId(), $team->getTournamentId()]); while (($synthese_data = $syntheses_req->fetch()) !== false) { $old_id = $synthese_data["file_id"]; $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; @@ -55,23 +59,20 @@ if (isset($_POST["select"])) { copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team_id, $_SESSION["final_id"], $synthese_data["dest"]]); + $req->execute([$id, $team->getId(), $_SESSION["final"]->getId(), $synthese_data["dest"]]); } } -if ($team_data === false) - require_once "../404.php"; - -$tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); - $documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); -$documents_req->execute([$team_data["id"], $team_data["tournament"]]); +$documents_req->execute([$team->getId(), $team->getId()]); -if ($team_data["final_selection"]) { +if ($team->isSelectedForFinal()) { $documents_final_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` != ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); - $documents_final_req->execute([$team_data["id"], $_SESSION["final_id"]]); + $documents_final_req->execute([$team->getId(), $_SESSION["final"]->getId()]); } +$tournament = Tournament::fromId($team->getTournamentId()); + require_once "../views/header.php"; require_once "../views/equipe.php"; require_once "../views/footer.php"; diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index 8a1612e..a977749 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -2,20 +2,22 @@ require_once "../config.php"; -if (!isset($_SESSION["role"]) || $_SESSION["role"] != "ORGANIZER" && $_SESSION["role"] != "ADMIN") { +if (!isset($_SESSION["role"])) require_once "../403.php"; -} $id = $_GET["id"]; -$user_data = $DB->query("SELECT * FROM `users` WHERE `id` = $id;")->fetch(); +$user = User::fromId($id); -if ($user_data === false) { +if ($_SESSION["role"] != Role::ORGANIZER && $_SESSION["role"] != Role::ADMIN) { + if ($user->getId() != $_SESSION["user_id"] && ($user->getTeamId() == null || $user->getTeamId() != $_SESSION["user"]->getTeamId())) + require_once "../403.php"; +} + +if ($user === null) { require_once "../404.php"; } -$team_data = false; -if ($user_data["team_id"] !== NULL) - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = " . $user_data["team_id"] . ";")->fetch(); +$team = Team::fromId($user->getTeamId()); $documents_req = $DB->query("SELECT * FROM `documents` WHERE `user` = $id;"); $tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `date_start`, `name`;"); diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index cef24b8..283a321 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -8,102 +8,96 @@ if (isset($_POST["submitted"])) { $error_message = updatePassword(); } -if (isset($_SESSION["user_id"])) { - $result = $DB->query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "';"); - $user_data = $result->fetch(); -} -else +if (!isset($_SESSION["user_id"])) require_once "../403.php"; +/** @var User $user */ +$user = $_SESSION["user"]; + function updateAccount() { - global $DB, $URL_BASE, $MAIL_ADDRESS; - - if (!isset($_SESSION["user_id"])) - return "Vous n'êtes pas connecté."; - - $ID = $_SESSION["user_id"]; + global $URL_BASE, $MAIL_ADDRESS, $user; $surname = htmlspecialchars($_POST["surname"]); if (isset($surname) && $surname != "") - $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $ID]); + $user->setSurname($surname); $first_name = htmlspecialchars($_POST["firstname"]); if (isset($first_name) && $first_name != "") - $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $ID]); + $user->setFirstName($first_name); $birth_date = htmlspecialchars($_POST["birth_date"]); if (isset($birth_date) && $birth_date != "") - $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $ID]); + $user->setBirthDate($birth_date); if (isset($_POST["gender"])) { $gender = htmlspecialchars($_POST["gender"]); if (isset($gender) && ($gender == "M" || $gender == "F")) - $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $ID]); + $user->setGender($gender); } $address = htmlspecialchars($_POST["address"]); if (isset($address) && $address != "") - $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $ID]); + $user->setAddress($address); $postal_code = htmlspecialchars($_POST["postal_code"]); if (isset($postal_code) && $postal_code != "") - $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $ID]); + $user->setPostalCode($postal_code); $city = htmlspecialchars($_POST["city"]); if (isset($city) && $city != "") - $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $ID]); + $user->setCity($city); $country = htmlspecialchars($_POST["country"]); if (isset($country) && $country != "") - $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $ID]); + $user->setCountry($country); $phone_number = htmlspecialchars($_POST["phone_number"]); if (isset($phone_number) && $phone_number != "") - $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $ID]); + $user->setPhoneNumber($phone_number); if (isset($_POST["school"])) { $school = htmlspecialchars($_POST["school"]); if (isset($school) && $school != "") - $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $ID]); + $user->setSchool($school); } if (isset($_POST["class"])) { $class = htmlspecialchars($_POST["class"]); if (isset($class) && ($class == "terminale" || $class == "premiere" || $class == "seconde")) - $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([strtoupper($class), $ID]); + $user->setClass($class); } if (isset($_POST["responsible_name"])) { $responsible_name = htmlspecialchars($_POST["responsible_name"]); if (isset($responsible_name) && $responsible_name != "") - $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $ID]); + $user->setResponsibleName($responsible_name); } if (isset($_POST["responsible_phone"])) { $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); if (isset($responsible_phone) && $responsible_phone != "") - $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $ID]); + $user->setResponsiblePhone($responsible_phone); } if (isset($_POST["responsible_email"])) { $responsible_email = htmlspecialchars($_POST["responsible_email"]); if (isset($responsible_email) && $responsible_email != "") - $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $ID]); + $user->setResponsibleEmail($responsible_email); } if (isset($_POST["description"])) { $description = htmlspecialchars($_POST["description"]); if (isset($description) && $description != "") - $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$description, $ID]); + $user->setDescription($description); } $email = htmlspecialchars($_POST["email"]); if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { - $confirm_email_uid = uniqid(); - $DB->prepare("UPDATE `users` SET `email` = ?, `confirm_email` = ? WHERE `id` = ?;")->execute([$email, $confirm_email_uid, $ID]); + $confirm_email_token = uniqid(); + $user->setConfirmEmailToken($confirm_email_token); - $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; + $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_token"; mail($email, "Changement d'adresse mail - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); } @@ -112,17 +106,13 @@ function updateAccount() function updatePassword() { - global $DB, $YEAR; + global $user; $old = htmlspecialchars($_POST["old_password"]); $new = htmlspecialchars($_POST["new_password"]); $confirm = htmlspecialchars($_POST["confirm_password"]); - $result = $DB->query("SELECT `pwd_hash` FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - return "Le compte n'existe pas."; - - if (!password_verify($old, $data["pwd_hash"])) + if (!$user->checkPassword($old)) return "L'ancien mot de passe est incorrect."; if (strlen($new) < 8) @@ -131,9 +121,7 @@ function updatePassword() if ($new != $confirm) return "Les deux mots de passe sont différents."; - $hash = password_hash($new, PASSWORD_BCRYPT); - - $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$hash, $_SESSION["user_id"]]); + $user->setPassword($new); return false; } diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php index f76ca1e..7d43c33 100644 --- a/server_files/controllers/mon_equipe.php +++ b/server_files/controllers/mon_equipe.php @@ -4,6 +4,7 @@ require_once "../config.php"; if (isset($_POST["leave_team"])) { quitTeam(); + exit(); } $tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); @@ -15,20 +16,18 @@ if (isset($_POST["send_document"])) { if (isset($_POST["request_validation"])) { if (!checkCanValidate()) $error_message = "Votre équipe ne peut pas demander la validation : il manque soit des participants, soit des documents."; - else { - $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); - $_SESSION["team_validation_status"] = "WAITING"; - } + else + $_SESSION["team"]->setValidationStatus(ValidationStatus::WAITING); } -if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { - $result = $DB->query("SELECT * FROM `teams` WHERE `id` = '" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); - $team_data = $result->fetch(); - - $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); - +if (isset($_SESSION["user_id"]) && isset($_SESSION["team"]) && $_SESSION["team"] !== null) { + /** @var Team $team */ + $team = $_SESSION["team"]; + + $tournament = Tournament::fromId($team->getTournamentId()); + $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? GROUP BY `type`, `uploaded_at` ORDER BY `type`, `uploaded_at` DESC;"); - $documents_req->execute([$_SESSION["user_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); + $documents_req->execute([$_SESSION["user_id"], $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $tournament->getId()]]); } else require_once "../403.php"; @@ -77,39 +76,35 @@ function sendDocument() function updateTeam() { - global $DB, $YEAR, $URL_BASE, $team_data; - - if ($_SESSION["team_id"] == NULL) - return "Vous n'êtes pas dans une équipe."; - + global $DB, $YEAR, $URL_BASE, $team; + $name = htmlspecialchars($_POST["name"]); if (!isset($name) || $name == "") return "Vous devez spécifier un nom d'équipe."; - - echo $team_data["id"]; - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `id` != " . $team_data["id"] . " AND `year` = '$YEAR';"); + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `id` != " . $team->getId() . " AND `year` = '$YEAR';"); if ($result->fetch()) - return "Une équipe existe déjà avec ce nom." . $team_data["id"]; + return "Une équipe existe déjà avec ce nom."; $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) return "Le trigramme entré n'est pas valide."; - $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `id` != '" . $team_data["id"] . "' AND `year` = '$YEAR';"); + $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `id` != '" . $team->getId() . "' AND `year` = '$YEAR';"); if ($result->fetch()) return "Une équipe a déjà choisi ce trigramme."; $tournament_id = intval(htmlspecialchars($_POST["tournament"])); - - $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) + $tournament = Tournament::fromId($tournament_id); + if ($tournament === null) return "Le tournoi spécifié n'existe pas."; - - $req = $DB->prepare("UPDATE `teams` SET `name` = ?, `trigram` = ?, `tournament` = ? WHERE `id` = ?;"); - $req->execute([$name, $trigram, $tournament_id, $team_data["id"]]); + + $team->setName($name); + $team->setTrigram($trigram); + $team->setTournamentId($tournament_id); + $_SESSION["tournament"] = $tournament; header("Location: $URL_BASE/mon_equipe"); @@ -118,42 +113,43 @@ function updateTeam() function checkCanValidate() { - global $DB, $team_data, $tournament_data, $YEAR; - $can_validate = $team_data["validation_status"] == "NOT_READY"; - $can_validate &= $team_data["encadrant_1"] != NULL; - $can_validate &= $team_data["participant_4"] != NULL; + global $DB, $team, $tournament, $YEAR; + + $can_validate = $team->getValidationStatus() == ValidationStatus::NOT_READY; + $can_validate &= $team->getEncadrants()[0] != NULL; + $can_validate &= $team->getParticipants()[3] != NULL; for ($i = 1; $i <= 2; ++$i) { - if ($team_data["encadrant_$i"] === NULL) + if ($team->getEncadrants()[$i - 1] === NULL) continue; $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); - $req->execute([$team_data["encadrant_$i"], "PHOTO_CONSENT"]); + $req->execute([$team->getEncadrants()[$i - 1], "PHOTO_CONSENT"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); - $req->execute([$team_data["encadrant_$i"], "SANITARY_PLUG"]); + $req->execute([$team->getEncadrants()[$i - 1], "SANITARY_PLUG"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; } for ($i = 1; $i <= 6; ++$i) { - if ($team_data["participant_$i"] === NULL) + if ($team->getParticipants()[$i] === NULL) continue; $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); - $req->execute([$team_data["participant_$i"], "PHOTO_CONSENT"]); + $req->execute([$team->getParticipants()[$i], "PHOTO_CONSENT"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); - $req->execute([$team_data["participant_$i"], "SANITARY_PLUG"]); + $req->execute([$team->getParticipants()[$i], "SANITARY_PLUG"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; - $birth_date = $DB->query("SELECT `birth_date` FROM `users` WHERE `id` = " . $team_data["participant_$i"] . ";")->fetch()["birth_date"]; - if ($birth_date > strval($YEAR - 18) . substr($tournament_data["date_start"], 4)) { + $birth_date = $DB->query("SELECT `birth_date` FROM `users` WHERE `id` = " . $team->getParticipants()[$i] . ";")->fetch()["birth_date"]; + if ($birth_date > strval($YEAR - 18) . substr($tournament->getStartDate(), 4)) { $req = $DB->prepare("SELECT COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `type` = ? GROUP BY `uploaded_at` ORDER BY `uploaded_at` DESC;"); - $req->execute([$team_data["participant_$i"], "PARENTAL_CONSENT"]); + $req->execute([$team->getParticipants()[$i], "PARENTAL_CONSENT"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; } diff --git a/server_files/controllers/rejoindre_equipe.php b/server_files/controllers/rejoindre_equipe.php index 17a3860..bc41129 100644 --- a/server_files/controllers/rejoindre_equipe.php +++ b/server_files/controllers/rejoindre_equipe.php @@ -2,48 +2,50 @@ require_once "../config.php"; +if (isset($_SESSION["team"]) || !isset($_SESSION["user"]) || ($_SESSION["role"] != Role::PARTICIPANT && $_SESSION["role"] != Role::ENCADRANT)) + require_once "../403.php"; + if (isset($_POST["submitted"])) { $error_message = joinTeam(); } function joinTeam() { - global $DB, $YEAR, $MAIL_ADDRESS, $access_code, $data; - - if ($_SESSION["team_id"] != NULL) - return "Vous êtes déjà dans une équipe."; + global $YEAR, $MAIL_ADDRESS, $access_code; $access_code = htmlspecialchars($_POST["access_code"]); if (!isset($access_code) || strlen($access_code) != 6) return "Le code d'accès doit comporter 6 caractères."; - - $result = $DB->query("SELECT * FROM `teams` WHERE `access_code` = '" . $access_code . "' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - return "Ce code d'accès est invalide."; - - if ($_SESSION["role"] != "PARTICIPANT" && $_SESSION["role"] != "ENCADRANT") - return "Seuls les participants et les encadrants peuvent rejoindre une équipe."; - if ($data["validation_status"] != "NOT_READY") + /** @var User $user */ + $user = $_SESSION["user"]; + $team = Team::fromAccessCode($access_code); + if ($team === null) + return "Ce code d'accès est invalide."; + + if ($team->getValidationStatus() != ValidationStatus::NOT_READY) return "Cette équipe est déjà en cours de validation ou validée, vous ne pouvez pas la rejoindre."; - for ($i = 1; $i <= $_SESSION["role"] == "PARTICIPANT" ? 6 : 2; ++$i) { - if ($data[strtolower($_SESSION["role"]) . "_" . strval($i)] == NULL) + for ($i = 1; $i <= $_SESSION["role"] == Role::PARTICIPANT ? 6 : 2; ++$i) { + if (($_SESSION["role"] == Role::PARTICIPANT ? $team->getParticipants()[$i - 1] : $team->getEncadrants()[$i - 1]) == NULL) break; } - if ($_SESSION["role"] == "PARTICIPANT" && $i == 7 || $_SESSION["role"] == "ENCADRANT" && $i == 3) + if ($_SESSION["role"] == Role::PARTICIPANT && $i == 7 || $_SESSION["role"] == Role::ENCADRANT && $i == 3) return "Il n'y a plus de place pour vous dans l'équipe."; - - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data["id"]]); - /** @noinspection SqlResolve */ - $DB->prepare("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_" . strval($i) . "` = ? WHERE `id` = " . $data["id"] . ";")->execute([$_SESSION["user_id"]]); - $_SESSION["team_id"] = $data["id"]; - $_SESSION["team_validation_status"] = $data["validation_status"]; + $user->setTeamId($team->getId()); - $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; - $msg .= "Vous venez de rejoindre l'équipe « " . $data["name"] . " » (" . $data["trigram"] . ") pour le TFJM² de " . $data["name"] . " et nous vous en remercions.\r\n\r\n"; + if ($_SESSION["role"] == Role::ENCADRANT) + $team->setEncadrant($i, $user->getId()); + else + $team->setParticipant($i, $user->getId()); + + $_SESSION["team"] = $team; + $tournament = $_SESSION["tournament"] = Tournament::fromId($team->getTournamentId()); + + $msg = "Bonjour " . $user->getFirstName() . " " . $user->getSurname() . ",\r\n\r\n"; + $msg .= "Vous venez de rejoindre l'équipe « " . $team->getName() . " » (" . $team->getTrigram() . ") pour le TFJM² de " . $tournament->getId() . " et nous vous en remercions.\r\n\r\n"; $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; mail($_SESSION["email"], "Équipe rejointe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); diff --git a/server_files/controllers/solutions_orga.php b/server_files/controllers/solutions_orga.php index 7dc2540..b1054d8 100644 --- a/server_files/controllers/solutions_orga.php +++ b/server_files/controllers/solutions_orga.php @@ -2,17 +2,19 @@ require_once "../config.php"; -if (!isset($_SESSION["role"]) || $_SESSION["role"] != "ADMIN" && $_SESSION["role"] != "ORGANIZER") +if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN && $_SESSION["role"] != Role::ORGANIZER) require_once "../403.php"; +/** @noinspection SqlAggregates */ $req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " - . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") + . ($_SESSION["role"] == Role::ADMIN ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") . "`year` = $YEAR GROUP BY `tournament` ORDER BY `name`;"); if (isset($_POST["download_zip"])) { $id = $_POST["tournament"]; $tournament_name = $_POST["tournament_name"]; - $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + /** @noinspection SqlAggregates */ + $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); $zip = new ZipArchive(); @@ -27,9 +29,9 @@ if (isset($_POST["download_zip"])) { $problem = $data_file["problem"]; $version = $data_file["version"]; $team_id = $data_file["team"]; - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); - $team_name = $team_data["name"]; - $team_trigram = $team_data["trigram"]; + $team = Team::fromId($team_id); + $team_name = $team->getName(); + $team_trigram = $team->getTrigram(); $zip->addFile("$LOCAL_PATH/files/$file_id", "Problème $problem $team_trigram.pdf"); } @@ -50,15 +52,16 @@ require_once "../views/header.php"; while (($data_tournament = $req->fetch()) !== false) { echo "

Tournoi de " . $data_tournament["name"] . "

\n"; $id = $data_tournament["id"]; - $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + /** @noinspection SqlAggregates */ + $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); while (($data_file = $files_req->fetch()) !== false) { $file_id = $data_file["file_id"]; $problem = $data_file["problem"]; $version = $data_file["version"]; $team_id = $data_file["team"]; - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); - $team_name = $team_data["name"]; - $team_trigram = $team_data["trigram"]; + $team = Team::fromId($team_id); + $team_name = $team->getName(); + $team_trigram = $team->getTrigram(); echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
"; } diff --git a/server_files/controllers/syntheses_orga.php b/server_files/controllers/syntheses_orga.php index 4286085..6841076 100644 --- a/server_files/controllers/syntheses_orga.php +++ b/server_files/controllers/syntheses_orga.php @@ -1,14 +1,13 @@ - +query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest`, `uploaded_at` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + /** @noinspection SqlAggregates */ + $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); $zip = new ZipArchive(); @@ -23,9 +22,9 @@ if (isset($_POST["download_zip"])) { $dest = $data_file["dest"]; $version = $data_file["version"]; $team_id = $data_file["team"]; - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); - $team_name = $team_data["name"]; - $team_trigram = $team_data["trigram"]; + $team = Team::fromId($team_id); + $team_name = $team->getName(); + $team_trigram = $team->getTrigram(); $zip->addFile("$LOCAL_PATH/files/$file_id", "Note de synthèse $team_trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"); } @@ -44,7 +43,7 @@ if (isset($_POST["download_zip"])) { require_once "../views/header.php"; $req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " - . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") + . ($_SESSION["role"] == Role::ADMIN ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") . "`year` = $YEAR GROUP BY `tournament`, `name` ORDER BY `name`;"); while (($data_tournament = $req->fetch()) !== false) { @@ -56,9 +55,9 @@ while (($data_tournament = $req->fetch()) !== false) { $dest = $data_file["dest"]; $version = $data_file["version"]; $team_id = $data_file["team"]; - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); - $team_name = $team_data["name"]; - $team_trigram = $team_data["trigram"]; + $team = Team::fromId($team_id); + $team_name = $team->getName(); + $team_trigram = $team->getTrigram(); echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ", version $version : Télécharger
"; } diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 3a55c44..7fbafce 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -4,61 +4,56 @@ require_once "../config.php"; $tournament_name = htmlspecialchars($_GET["nom"]); -$response = $DB->prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year` = $YEAR;"); -$response->execute([$tournament_name]); -$data = $response->fetch(); +$tournament = Tournament::fromName($tournament_name); -if ($data === false) +if ($tournament === null) require_once "../404.php"; -$orgas_req = $DB->query("SELECT `users`.`id` AS `id`, `surname`, `first_name` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $data["id"] . ";"); +$orgas_req = $DB->query("SELECT `users`.`id` AS `id` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $tournament->getId() . ";"); $orgas = []; $orgas_id = []; while (($orga_data = $orgas_req->fetch()) !== false) { - $orgas[] = $orga_data["first_name"] . " " . $orga_data["surname"]; + $orgas[] = User::fromId($orga_data["id"]); $orgas_id[] = $orga_data["id"]; } -if (isset($_GET["modifier"]) && $_SESSION["role"] != "ADMIN" && !in_array($_SESSION["user_id"], $orgas_id)) +if (isset($_GET["modifier"]) && $_SESSION["role"] != Role::ADMIN && !in_array($_SESSION["user_id"], $orgas_id)) require_once "../403.php"; if (isset($_POST["edit_tournament"])) { $error_message = updateTournament(); } -if ($data["final"]) +if ($tournament->isFinal()) $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `final_selection` AND `year` = $YEAR;"); else - $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); + $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $tournament->getId() . " AND `year` = $YEAR;"); $orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); function updateTournament() { - global $DB, $URL_BASE, $YEAR, $data; - - $tournament_id = $data["id"]; + global $DB, $URL_BASE, $YEAR, $tournament; $name = htmlspecialchars($_POST["name"]); - $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `id` != $tournament_id AND `year` = '$YEAR';"); + $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `id` != " . $tournament->getId() . " AND `year` = '$YEAR';"); if ($result->fetch()) return "Un tournoi existe déjà avec ce nom."; if (!isset($_POST["organizer"]) || sizeof($_POST["organizer"]) == 0) return "Aucun organisateur n'a été choisi."; - if ($_SESSION["role"] == "ADMIN") { + if ($_SESSION["role"] == Role::ADMIN) { $organizers = $_POST["organizer"]; $orga_mails = []; - foreach ($organizers as $orga) { - $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $orga . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) + foreach ($organizers as $orga_id) { + $orga = User::fromId($orga_id); + if ($orga === null) return "L'organisateur spécifié n'existe pas."; - if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") + if ($orga->getRole() != Role::ORGANIZER && $orga->getRole() != Role::ADMIN) return "L'organisateur indiqué ne peut pas organiser de tournoi."; - $orga_mails[] = $data["email"]; + $orga_mails[] = $orga->getEmail(); } } @@ -112,15 +107,15 @@ function updateTournament() { $req = $DB->prepare("UPDATE `tournaments` SET `name` = ?, `size` = ?, `place` = ?, `price` = ?, `description` = ?, `date_start` = ?, `date_end` = ?, `date_inscription` = ?, `date_solutions` = ?, `date_syntheses` = ? - WHERE `id` = $tournament_id;"); + WHERE `id` = " . $tournament->getId() . ";"); $req->execute([$name, $size, $place, $price, $description, $date_start, $date_end, "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses"]); - if ($_SESSION["role"] == "ADMIN") { - $DB->exec("DELETE FROM `organizers` WHERE `tournament` = $tournament_id;"); + if ($_SESSION["role"] == Role::ADMIN) { + $DB->exec("DELETE FROM `organizers` WHERE `tournament` = " . $tournament->getId() . ";"); foreach ($organizers as $orga) { $req = $DB->prepare("INSERT INTO `organizers`(`organizer`, `tournament`) VALUES(?, ?);"); - $req->execute([$orga, $tournament_id]); + $req->execute([$orga->getId(), $tournament->getId()]); } } diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index 029e01c..5147060 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -23,9 +23,9 @@ if (($data = $req->fetch()) === false) { } if ($data !== false) { - $team_data = $DB->query("SELECT `trigram` FROM `teams` WHERE `id` = " . $data["team"] . ";")->fetch(); - $tournament_data = $DB->query("SELECT `name` FROM `tournaments` WHERE `id` = " . $data["tournament"] . ";")->fetch(); - $trigram = $team_data["trigram"]; + $team = Team::fromId($data["team"]); + $tournament = Tournament::fromId($data["tournament"]); + $trigram = $team->getTrigram(); if ($type == "SOLUTION") { $problem = $data["problem"]; $name = "Problème $problem $trigram.pdf"; diff --git a/server_files/model.php b/server_files/model.php index daac47a..79390e7 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -1,63 +1,46 @@ query("SELECT * FROM `users` WHERE `id` ='" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); - $data = $response->fetch(); - if ($data === FALSE) - unset($_SESSION["user_id"]); - else { - $_SESSION["email"] = $data["email"]; - $_SESSION["surname"] = $data["surname"]; - $_SESSION["first_name"] = $data["first_name"]; - $_SESSION["birth_date"] = $data["birth_date"]; - $_SESSION["role"] = $data["role"]; - $_SESSION["team_id"] = $data["team_id"]; + $user = $_SESSION["user"] = User::fromId($_SESSION["user_id"]); + $_SESSION["role"] = $user->getRole(); + + if ($user->getTeamId() !== null) { + $team = $_SESSION["team"] = Team::fromId($user->getTeamId()); + $_SESSION["tournament"] = Tournament::fromId($team->getTournamentId()); } - if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"]) && $_SESSION["team_id"] != NULL) { - $response = $DB->query("SELECT `tournament`, `validation_status`, `final_selection` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); - $data = $response->fetch(); - $_SESSION["tournament_id"] = $data["tournament"]; - $_SESSION["team_validation_status"] = $data["validation_status"]; + if (isset($_GET["be-admin"])) { + quitTeam(); + $user->setRole(Role::ADMIN); + exit(); } - if ((isset($data["final_selection"]) && $data["final_selection"]) || $_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") { - $response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `final` AND `year` = $YEAR;"); - $data = $response->fetch(); - $_SESSION["final_id"] = $data["id"]; - $_SESSION["final_name"] = $data["name"]; + if (isset($_GET["be-organizer"])) { + quitTeam(); + $user->setRole(Role::ORGANIZER); + exit(); } - } - if (isset($_SESSION["user_id"]) && isset($_GET["be-admin"])) { - $DB->exec("UPDATE `users` SET `role` = 'ADMIN' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); - } + if (isset($_GET["be-participant"])) { + quitTeam(); + $user->setRole(Role::PARTICIPANT); + exit(); + } - if (isset($_SESSION["user_id"]) && isset($_GET["be-organizer"])) { - $DB->exec("UPDATE `users` SET `role` = 'ORGANIZER' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); - } - - if (isset($_SESSION["user_id"]) && isset($_GET["be-participant"])) { - $DB->exec("UPDATE `users` SET `role` = 'PARTICIPANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); - } - - if (isset($_SESSION["user_id"]) && isset($_GET["be-encadrant"])) { - $DB->exec("UPDATE `users` SET `role` = 'ENCADRANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); + if (isset($_GET["be-encadrant"])) { + quitTeam(); + $user->setRole(Role::ENCADRANT); + exit(); + } } } @@ -71,35 +54,44 @@ function echoDate($date = NULL, $with_time = false) { function quitTeam() { global $DB, $URL_BASE; - if ($_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") + header("Location: $URL_BASE"); + + /** @var User $user */ + $user = $_SESSION["user"]; + $user_id = $user->getId(); + $role = $user->getRole(); + + if ($role == Role::ADMIN || $role == Role::ORGANIZER) return; - for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) + for ($i = 1; $i <= ($role == Role::ENCADRANT ? 6 : 2); ++$i) /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `teams` SET `" . strtolower(Role::getName($role)) . "_$i` = NULL WHERE `" . strtolower(Role::getName($role)) . "_$i` = $user_id;"); + $user->setTeamId(null); $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); for ($i = 1; $i <= 5; ++$i) { /** @noinspection SqlResolve */ $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); } - $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = $user_id;"); while (($data = $req->fetch()) !== false) unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + $DB->exec("DELETE FROM `documents` WHERE `user` = $user_id;"); if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { - $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + $team_id = $user->getTeamId(); + $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = $team_id;"); while (($data = $req->fetch()) !== false) unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); + $DB->exec("DELETE FROM `solutions` WHERE `team` = $team_id;"); - $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = $team_id;"); while (($data = $req->fetch()) !== false) unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); + $DB->exec("DELETE FROM `syntheses` WHERE `team` = $team_id;"); } - unset($_SESSION["team_id"]); - unset($_SESSION["team_validation_status"]); + + $_SESSION["team"] = null; + unset($_SESSION["team"]); } \ No newline at end of file diff --git a/server_files/views/ajouter_equipe.php b/server_files/views/ajouter_equipe.php index a7def93..d63ec03 100644 --- a/server_files/views/ajouter_equipe.php +++ b/server_files/views/ajouter_equipe.php @@ -1,10 +1,7 @@ - -

Vous devez être participant ou encadrant pour pouvoir ajouter une équipe.

- +

Vous êtes déjà dans une équipe.

- Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : + Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : Erreur : " . $error_message . ""; ?> diff --git a/server_files/views/ajouter_organisateur.php b/server_files/views/ajouter_organisateur.php index 4ca6ba0..f17603e 100644 --- a/server_files/views/ajouter_organisateur.php +++ b/server_files/views/ajouter_organisateur.php @@ -50,4 +50,4 @@ if (isset($error_message)) { - \ No newline at end of file + diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index 40f0c73..a19b3f2 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -1,25 +1,25 @@

Informations sur l'équipe

-Nom de l'équipe :
-Trigramme :
-Tournoi : ">
+Nom de l'équipe : getName() ?>
+Trigramme : getTrigram() ?>
+Tournoi : getName() ?>">getName() ?>
getEncadrants()[$i] == NULL) continue; - $user_data = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - $id = $user_data["id"]; - echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; + $encadrant = User::fromId($team->getEncadrants()[$i - 1]); + $id = $encadrant->getId(); + echo "Encadrant $i : getFirstName() . " " . $encadrant->getSurname() . "\">" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "
"; } for ($i = 1; $i <= 6; ++$i) { - if ($team_data["participant_" . $i] == NULL) + if ($team->getParticipants()[$i - 1] == NULL) continue; - $user_data = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - $id = $user_data["id"]; - echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
"; + $participant = User::fromId($team->getParticipants()[$i - 1]); + $id = $participant->getId(); + echo "Participant $i : getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
"; } -if ($team_data["final_selection"]) { - $final_name = $_SESSION["final_name"]; +if ($team->isSelectedForFinal()) { + $final_name = $_SESSION["final"]->getName(); echo "Équipe sélectionnée pour la finale nationale."; } ?> @@ -52,7 +52,7 @@ while (($data = $documents_req->fetch()) !== false) { } ?> - +isSelectedForFinal()) { ?>

Autorisations pour la finale

fetch()) !== false) { } } -if ($team_data["validation_status"] == "WAITING" && $_SESSION["role"] == "ADMIN") { ?> +if ($team->getValidationStatus() == ValidationStatus::WAITING && $_SESSION["role"] == Role::ADMIN) { ?>
+if (!$team->isSelectedForFinal() && isset($_SESSION["user_id"]) && $_SESSION["role"] == Role::ADMIN) { ?>
diff --git a/server_files/views/header.php b/server_files/views/header.php index 256d8d0..5917855 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -30,40 +30,40 @@
  • Inscription
  • Mon compte
  • - - + +
  • Ajouter une équipe
  • Rejoindre une équipe
  • Mon équipe
  • - + getValidationStatus() == ValidationStatus::VALIDATED || true) { ?>
  • Paiement
  • Solutions
  • Notes de synthèse
  • - +
  • Ajouter un tournoi
  • Ajouter un organisateur
  • - +
  • Solutions
  • Notes de synthèse
  • Déconnexion

  • Devenir administrateur"; } - if ($_SESSION["role"] != "ORGANIZER") { + if ($_SESSION["role"] != Role::ORGANIZER) { echo "
  • Devenir organisateur
  • "; } - if ($_SESSION["role"] != "PARTICIPANT") { + if ($_SESSION["role"] != Role::PARTICIPANT) { echo "
  • Devenir participant
  • "; } - if ($_SESSION["role"] != "ENCADRANT") { + if ($_SESSION["role"] != Role::ENCADRANT) { echo "
  • Devenir encadrant
  • "; } ?> diff --git a/server_files/views/informations.php b/server_files/views/informations.php index a96220e..4ba340a 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -1,17 +1,17 @@ -

    +

    getFirstName() . " " . $user->getSurname() ?>

    - - Équipe : " . $team_data["name"] . " (" . $team_data["trigram"] . ")" ?>
    +getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { ?> + Équipe : getTrigram() . "\">" . $team->getName() . " (" . $team->getTrigram() . ")" ?>
    -Date de naissance :
    -Sexe :
    -Adresse :
    -Adresse e-mail : ">
    -Numéro de téléphone :
    +Date de naissance : getBirthDate()) ?>
    +Sexe : getGender() == "M" ? "Masculin" : "Féminin" ?>
    +Adresse : getAddress() . ", " . $user->getPostalCode() . " " . $user->getCity() . ($user->getCountry() == "France" ? "" : ", " . $user->getCountry()) ?>
    +Adresse e-mail : getEmail() ?>
    +Numéro de téléphone : getPhoneNumber() ?>
    - - Lycée :
    - Classe : getRole() == Role::PARTICIPANT) { ?> + Lycée : getSchool() ?>
    + Classe : getClass()) { case "TERMINALE": echo "Terminale"; break; @@ -26,22 +26,21 @@ Numéro de téléphone :
    break; } ?>
    - Nom du responsable légal :
    - Numéro de téléphone du responsable légal :
    - Adresse e-mail du responsable légal : "> - - Description :
    + Nom du responsable légal : getResponsibleName() ?>
    + Numéro de téléphone du responsable légal : getResponsiblePhone() ?>
    + Adresse e-mail du responsable légal : getResponsibleEmail() ?> +getDescription() != "") { ?> + Description : getDescription() ?>
    "; -if ($user_data["role"] == "ADMIN" || $user_data["role"] == "ORGANIZER") { +if ($user->getRole() == Role::ADMIN || $user->getRole() == Role::ORGANIZER) { while (($tournament_data = $tournaments_req->fetch()) !== false) { echo "Organise le tournoi " . $tournament_data["name"] . "
    "; } } -elseif ($user_data["role"] == "PARTICIPANT" || $user_data["role"] == "ENCADRANT") { ?> -
    +elseif ($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { ?>

    Autorisations

    fetch()) !== false) { diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index 4718ea8..4ecff3c 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -5,9 +5,7 @@ if (isset($error_message) && $error_message === FALSE) { ?> Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. -

    Vous êtes déjà connecté !

    -
    @@ -56,7 +54,7 @@ if (isset($error_message) && $error_message === FALSE) { - " required /> + " required /> diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index bca8208..dffbbe3 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -16,76 +16,76 @@ if (isset($error_message) && $error_message === FALSE) { - + - + - + - + - + - + - + - + - + - + - + getRole() == Role::PARTICIPANT) { ?> - + @@ -93,9 +93,9 @@ if (isset($error_message) && $error_message === FALSE) { @@ -103,7 +103,7 @@ if (isset($error_message) && $error_message === FALSE) { @@ -116,7 +116,7 @@ if (isset($error_message) && $error_message === FALSE) { @@ -129,7 +129,7 @@ if (isset($error_message) && $error_message === FALSE) { @@ -140,7 +140,7 @@ if (isset($error_message) && $error_message === FALSE) { - + diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index 988996a..71e7a65 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -8,26 +8,28 @@

    Informations sur l'équipe

    -Nom de l'équipe :
    -Trigramme :
    -Tournoi : ">
    +Nom de l'équipe : getName() ?>
    +Trigramme : getTrigram() ?>
    +Tournoi : getName() ?>
    getEncadrants()[$i] == NULL) continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; + $encadrant = User::fromId($team->getEncadrants()[$i - 1]); + $id = $encadrant->getId(); + echo "Encadrant $i : getFirstName() . " " . $encadrant->getSurname() . "\">" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "
    "; } for ($i = 1; $i <= 6; ++$i) { - if ($team_data["participant_" . $i] == NULL) + if ($team->getParticipants()[$i - 1] == NULL) continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; + $participant = User::fromId($team->getParticipants()[$i - 1]); + $id = $participant->getId(); + echo "Participant $i : getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
    "; } ?> -Code d'accès :
    -getAccessCode() ?>
    +isSelectedForFinal()) { + $final_name = $_SESSION["final"]->getName(); echo "Équipe sélectionnée pour la finale nationale.
    "; } ?> @@ -42,7 +44,7 @@ Code d'accès :
    @@ -51,7 +53,7 @@ Code d'accès :
    @@ -79,7 +81,7 @@ Code d'accès :
    - + Modifier mon équipe @@ -103,7 +105,7 @@ Code d'accès :
    } echo "$name : Télécharger
    "; } - if ($team_data["validation_status"] == "NOT_READY") { ?> + if ($team->getValidationStatus() == ValidationStatus::NOT_READY) { ?>
    getEmail() ?>
    getSurname() ?>
    getFirstName() ?>
    getBirthDate()) ?>
    /> - />getGender() == "M") echo "checked" ?> /> + getGender() == "F") echo "checked" ?> />
    getAddress() ?>
    getPostalCode() ?>
    getCity() ?>
    getCountry() ?>
    getPhoneNumber() ?>
    getSchool() ?>
    - + getResponsibleName() ?>
    - + getResponsiblePhone() ?>
    - + getResponsibleEmail() ?>
    - "/> +
    "/> + value="getTrigram() ?>"/>
    @@ -114,7 +116,7 @@ Code d'accès :
    fetch()) != false) { ?> - - + + - + @@ -155,7 +159,7 @@ else { @@ -163,7 +167,7 @@ else { @@ -171,8 +175,8 @@ else { @@ -180,8 +184,8 @@ else { @@ -189,8 +193,8 @@ else { @@ -198,8 +202,8 @@ else { @@ -207,7 +211,7 @@ else { From fd861ca8c95f25fdeaedcaad3e0bbda1c51034fd Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 01:55:10 +0200 Subject: [PATCH 034/120] =?UTF-8?q?Quelques=20restrictions=20d'acc=C3=A8s?= =?UTF-8?q?=20lors=20du=20t=C3=A9l=C3=A9chargement=20de=20fichiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/view_file.php | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index 5147060..0ce1807 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -7,6 +7,9 @@ if (!isset($_GET["file_id"])) { exit(); } +if (!isset($_SESSION["user_id"])) + require_once "../403.php"; + $id = htmlspecialchars($_GET["file_id"]); $type = "SOLUTION"; @@ -29,16 +32,29 @@ if ($data !== false) { if ($type == "SOLUTION") { $problem = $data["problem"]; $name = "Problème $problem $trigram.pdf"; + + if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) + require_once "../403.php"; + + // TODO Seuls les organisateurs concernés doivent pouvoir télécharger les fichiers } else if ($type == "SYNTHESE") { $dest = $data["dest"]; $name = "Note de synthèse $trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"; + + // TODO Seuls les organisateurs, défenseurs, opposants et rapporteurs doivent pouvoir télécharger les fichiers } else if ($type == "DOCUMENT") { $user_id = $data["user"]; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = 'user';")->fetch(); - $surname = $user_data["surname"]; - $first_name = $user_data["first_name"]; + $user = User::fromId($user_id); + + if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && $user_id != $_SESSION["user_id"]) + require_once "../403.php"; + + // TODO Seuls les organisateurs concernés doivent pouvoir télécharger les fichiers + + $surname = $user->getSurname(); + $first_name = $user->getFirstName(); switch ($data["type"]) { case "PARENTAL_CONSENT": $name = "Autorisation parentale"; From 977f22af27aee7c776ce4687ffdfbf7cb1447f62 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 11:35:47 +0200 Subject: [PATCH 035/120] Utilisation de variables d'environnement pour les fichiers de configuration --- server_files/config.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/server_files/config.php b/server_files/config.php index 13bf1ed..14c2f7f 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -3,22 +3,22 @@ * Config options */ -$YEAR = 2020; -$URL_BASE = "https://galaxyoyo.com/tfjm"; -$LOCAL_PATH = "/var/www/html/tfjm"; -$MAIL_ADDRESS = "contact@galaxyoyo.com"; +$YEAR = $_ENV["TFJM_YEAR"]; +$URL_BASE = $_ENV["TFJM_URL_BASE"]; +$LOCAL_PATH = $_ENV["TFJM_LOCAL_PATH"]; +$MAIL_ADDRESS = $_ENV["TFJM_MAIL_ADDRESS"]; /** * DB infos */ -$DB_HOST = "localhost"; -$DB_NAME = "tfjm"; -$DB_USER = "galaxyoyo"; -$DB_PWD = "***REMOVED***"; +$DB_HOST = $_ENV["TFJM_DB_HOST"]; +$DB_NAME = $_ENV["TFJM_DB_NAME"]; +$DB_USER = $_ENV["TFJM_DB_USER"]; +$DB_PASSWORD = $_ENV["TFJM_DB_PASSWORD"]; try { - $DB = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8", "$DB_USER", "$DB_PWD", array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); + $DB = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8", "$DB_USER", "$DB_PASSWORD", array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); } catch (Exception $ex) { die("Erreur lors de la connexion à la base de données : " . $ex->getMessage()); From ae648d7615b53e86362e11902e8ba8188e829688 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Wed, 21 Aug 2019 22:56:46 +0200 Subject: [PATCH 036/120] Initial commit --- .htaccess | 52 ++--- 403.php | 14 ++ 404.php | 14 ++ server_files/ajouter_equipe.php | 127 ++++++++++ server_files/ajouter_organisateur.php | 124 ++++++++++ server_files/ajouter_tournoi.php | 217 +++++++++++++++++ server_files/config.php | 9 - server_files/confirmer_mail.php | 26 +++ server_files/connexion.php | 76 ++++++ server_files/deconnexion.php | 14 ++ server_files/equipe.php | 64 +++++ server_files/footer.php | 5 + server_files/header.php | 143 ++++++++++++ server_files/index.php | 114 +++++++++ server_files/inscription.php | 278 ++++++++++++++++++++++ server_files/mon_compte.php | 323 ++++++++++++++++++++++++++ server_files/mon_equipe.php | 200 ++++++++++++++++ server_files/rejoindre_equipe.php | 93 ++++++++ server_files/solutions.php | 115 +++++++++ server_files/solutions_orga.php | 29 +++ server_files/syntheses.php | 109 +++++++++ server_files/syntheses_orga.php | 30 +++ server_files/tournoi.php | 107 +++++++++ server_files/tournois.php | 50 ++++ server_files/view_file.php | 67 ++++++ 25 files changed, 2361 insertions(+), 39 deletions(-) create mode 100644 403.php create mode 100644 404.php create mode 100644 server_files/ajouter_equipe.php create mode 100644 server_files/ajouter_organisateur.php create mode 100644 server_files/ajouter_tournoi.php create mode 100644 server_files/confirmer_mail.php create mode 100644 server_files/connexion.php create mode 100644 server_files/deconnexion.php create mode 100644 server_files/equipe.php create mode 100644 server_files/footer.php create mode 100644 server_files/header.php create mode 100644 server_files/index.php create mode 100644 server_files/inscription.php create mode 100644 server_files/mon_compte.php create mode 100644 server_files/mon_equipe.php create mode 100644 server_files/rejoindre_equipe.php create mode 100644 server_files/solutions.php create mode 100644 server_files/solutions_orga.php create mode 100644 server_files/syntheses.php create mode 100644 server_files/syntheses_orga.php create mode 100644 server_files/tournoi.php create mode 100644 server_files/tournois.php create mode 100644 server_files/view_file.php diff --git a/.htaccess b/.htaccess index f69d89c..7f2d8b2 100644 --- a/.htaccess +++ b/.htaccess @@ -1,36 +1,28 @@ -ErrorDocument 403 /tfjm/server_files/403.php -ErrorDocument 404 /tfjm/server_files/404.php +ErrorDocument 403 /tfjm/403.php +ErrorDocument 404 /tfjm/404.php Options +FollowSymlinks -Options -Indexes +# Options -Indexes RewriteEngine On RewriteOptions Inherit RewriteBase /tfjm RewriteRule index.html accueil [L] -RewriteRule ^accueil$ server_files/controllers/index.php [L] -RewriteRule ^ajouter_equipe$ server_files/controllers/ajouter_equipe.php [L] -RewriteRule ^ajouter_organisateur$ server_files/controllers/ajouter_organisateur.php [L] -RewriteRule ^ajouter_tournoi$ server_files/controllers/ajouter_tournoi.php [L] -RewriteRule ^confirmer_mail/(.*?)$ server_files/controllers/confirmer_mail.php?token=$1 [L] -RewriteRule ^connexion$ server_files/controllers/connexion.php [L] -RewriteRule ^connexion/reinitialiser_mdp/(.*?)$ server_files/controllers/connexion.php?reset_password&token=$1 [L] -RewriteRule ^connexion/(.*?)$ server_files/controllers/connexion.php?$1 [L] -RewriteRule ^deconnexion$ server_files/controllers/deconnexion.php [L] -RewriteRule ^equipe/(.*?)$ server_files/controllers/equipe.php?trigram=$1 [L] -RewriteRule ^file/(.*?)$ server_files/controllers/view_file.php?file_id=$1 [L] -RewriteRule ^informations/(.*?)/.*?$ server_files/controllers/informations.php?id=$1 [L] -RewriteRule ^inscription$ server_files/controllers/inscription.php [L] -RewriteRule ^mon_compte$ server_files/controllers/mon_compte.php [L] -RewriteRule ^mon_equipe/(.*?)$ server_files/controllers/mon_equipe.php?$1 [L] -RewriteRule ^mon_equipe$ server_files/controllers/mon_equipe.php [L] -RewriteRule ^rejoindre_equipe$ server_files/controllers/rejoindre_equipe.php [L] -RewriteRule ^solutions$ server_files/controllers/solutions.php [L] -RewriteRule ^solutions_orga$ server_files/controllers/solutions_orga.php [L] -RewriteRule ^syntheses$ server_files/controllers/syntheses.php [L] -RewriteRule ^syntheses_orga$ server_files/controllers/syntheses_orga.php [L] -RewriteRule ^tournoi/(.*?)/(.*?)$ server_files/controllers/tournoi.php?nom=$1&$2 [L] -RewriteRule ^tournoi/(.*?)$ server_files/controllers/tournoi.php?nom=$1 [L] -RewriteRule ^tournois$ server_files/controllers/tournois.php [L] - -RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\ /tfjm/server_files.*? [NC] -RewriteRule ^server_files.*?$ - [R=404] +RewriteRule ^accueil$ server_files/index.php [L] +RewriteRule ^ajouter_equipe$ server_files/ajouter_equipe.php [L] +RewriteRule ^ajouter_organisateur$ server_files/ajouter_organisateur.php [L] +RewriteRule ^ajouter_tournoi$ server_files/ajouter_tournoi.php [L] +RewriteRule ^confirmer_mail/(.*?)$ server_files/confirmer_mail.php?token=$1 [L] +RewriteRule ^connexion$ server_files/connexion.php [L] +RewriteRule ^deconnexion$ server_files/deconnexion.php [L] +RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] +RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] +RewriteRule ^inscription$ server_files/inscription.php [L] +RewriteRule ^mon_compte$ server_files/mon_compte.php [L] +RewriteRule ^mon_equipe$ server_files/mon_equipe.php [L] +RewriteRule ^rejoindre_equipe$ server_files/rejoindre_equipe.php [L] +RewriteRule ^solutions$ server_files/solutions.php [L] +RewriteRule ^solutions_orga$ server_files/solutions_orga.php [L] +RewriteRule ^syntheses$ server_files/syntheses.php [L] +RewriteRule ^syntheses_orga$ server_files/syntheses_orga.php [L] +RewriteRule ^tournoi/(.*?)$ server_files/tournoi.php?nom=$1 [L] +RewriteRule ^tournois$ server_files/tournois.php [L] diff --git a/403.php b/403.php new file mode 100644 index 0000000..fab537f --- /dev/null +++ b/403.php @@ -0,0 +1,14 @@ + + +

    Vous n'êtes pas autorisé à accéder à cette page.

    + + \ No newline at end of file diff --git a/404.php b/404.php new file mode 100644 index 0000000..54ac204 --- /dev/null +++ b/404.php @@ -0,0 +1,14 @@ + + +

    Cette page n'existe pas.

    + + \ No newline at end of file diff --git a/server_files/ajouter_equipe.php b/server_files/ajouter_equipe.php new file mode 100644 index 0000000..9dd42ae --- /dev/null +++ b/server_files/ajouter_equipe.php @@ -0,0 +1,127 @@ +query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); + +if (isset($_POST["submitted"])) { + $error_message = registerTournament(); +} + +function registerTournament() { + global $DB, $YEAR, $MAIL_ADDRESS, $access_code; + + if ($_SESSION["team_id"] != NULL) + return "Vous êtes déjà dans une équipe."; + + $name = htmlspecialchars($_POST["name"]); + + if (!isset($name) || $name == "") + return "Vous devez spécifier un nom d'équipe."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe existe déjà avec ce nom."; + + $trigram = htmlspecialchars($_POST["trigram"]); + + if (!preg_match("#[A-Z][A-Z][A-Z]#", $trigram)) + return "Le trigramme entré n'est pas valide."; + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Une équipe a déjà choisi ce trigramme."; + + $tournament_id = intval(htmlspecialchars($_POST["tournament"])); + + $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "Le tournoi spécifié n'existe pas."; + + $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; + $access_code = ""; + for ($i = 0; $i < 6; ++$i) + $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; + + $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?);"); + $result = $req->execute([$name, $trigram, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, + $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); + + $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + $data_team = $result->fetch(); + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); + + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; + $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; + $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; + $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; + mail($_SESSION["email"], "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

    Vous devez être participant ou encadrant pour pouvoir ajouter une équipe.

    + +

    Vous êtes déjà dans une équipe.

    + + Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : + + +Erreur : " . $error_message . ""; ?> + + + +
    diff --git a/server_files/views/rejoindre_equipe.php b/server_files/views/rejoindre_equipe.php index 71273c2..b99154a 100644 --- a/server_files/views/rejoindre_equipe.php +++ b/server_files/views/rejoindre_equipe.php @@ -1,11 +1,5 @@ - -

    Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

    - - Vous avez bien rejoint l'équipe ! - -

    Vous êtes déjà dans une équipe.

    + + Vous avez bien rejoint l'équipe getName() ?> ! Erreur : " . $error_message . ""; ?> diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index a058b66..39c6426 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -1,33 +1,36 @@ -

    Tournoi de

    +

    Tournoi de getName() ?>

    Organisateur= 2 ? 's' : '' ?> : $orgas[$i]"; +/** @var User $orga */ +foreach ($orgas as $orga) { + $orga_id = $orga->getId(); + $orga_name = $orga->getFirstName() . " " . $orga->getSurname(); + if ($_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) + $s .= "$orga_name"; else - $s .= $orgas[$i]; + $s .= $orga_name; $s .= ", "; } echo substr($s, 0, -2); ?>
    -Nombre d'équipes maximal :
    -Lieu :
    -Prix par partipant :
    -Dates : Du au
    -Clôture des inscriptions :
    -Date limite d'envoi des solutions :
    -Date limite d'envoi des notes de synthèse :
    -Description :
    +Nombre d'équipes maximal : getSize() ?>
    +Lieu : getPlace() ?>
    +Prix par partipant : getPrice() == 0 ? "Gratuit" : $tournament->getPrice() . " €" ?>
    +Dates : Du getStartDate()) ?> au getEndDate()) ?>
    +Clôture des inscriptions : getInscriptionDate(), true) ?>
    +Date limite d'envoi des solutions : getSolutionsDate(), true) ?>
    +Date limite d'envoi des notes de synthèse : getSynthesesDate(), true) ?>
    +Description : getDescription() ?>
    isFinal()) echo "Ce tournoi est la finale nationale du TFJM² 2020.
    "; ?> - - /modifier">Éditer le tournoi + + Éditer le tournoi @@ -55,29 +58,30 @@ if ($data["final"])
    " . $team_data["name"] . ""; else echo $team_data["name"]; ?> Nom : - " required /> +
    @@ -134,7 +138,7 @@ else { - " required /> +
    - " required /> +
    - " required /> +
    - Du " required /> - au " required /> + Du + au
    - " required /> - " required /> + +
    - " required /> - " required /> + +
    - " required /> - " required /> + +
    - +
    + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + +
    + +
    + + + + + diff --git a/server_files/ajouter_organisateur.php b/server_files/ajouter_organisateur.php new file mode 100644 index 0000000..1146426 --- /dev/null +++ b/server_files/ajouter_organisateur.php @@ -0,0 +1,124 @@ +prepare("SELECT `id` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); + $req->execute([$email]); + if ($req->fetch() !== FALSE) + return "Cette adresse e-mail est déjà utilisée."; + + $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $password = ""; + for ($i = 0; $i < 16; ++$i) + $password .= $alphabet[rand(0, strlen($alphabet) - 1)]; + $hash = password_hash($password, PASSWORD_BCRYPT); + + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) + VALUES (?, ?, ?, ?, ?, ?);"); + $req->execute([$email, $hash, $surname, $first_name, $admin ? "ADMIN" : "ORGANIZER", $YEAR]); + + $msg = "Bonjour " . $first_name . " " . $surname . ",\r\n\r\n" + . "Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM². " + . "Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. " + . "Elles vous permettront de gérer les inscriptions des équipes de votre tournoi.\r\n\r\n" + . "Votre mot de passe est : $password\r\n\r\n" + . "Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer " + . "lors de votre prochaine connexion sur le site.\r\n\r\n" + . "Merci beaucoup pour votre aide !\r\n\r\n" + . "Les organisateurs du TFJM²"; + + mail($email, "Organisateur du TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

    Vous n'êtes pas autorisé à accéder à cette page.

    + + + Erreur : " . $error_message . ""; + } else { + echo "

    Organisateur ajouté avec succès ! Ses identifiants ont été transmis par mail.

    "; + } + }?> + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    + +
    +
    + + + + diff --git a/server_files/ajouter_tournoi.php b/server_files/ajouter_tournoi.php new file mode 100644 index 0000000..434897f --- /dev/null +++ b/server_files/ajouter_tournoi.php @@ -0,0 +1,217 @@ +query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); + +if (isset($_POST["submitted"])) { + $error_message = registerTournament(); +} + +function registerTournament() { + global $DB, $YEAR, $MAIL_ADDRESS; + + $name = htmlspecialchars($_POST["name"]); + + $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Un tournoi existe déjà avec ce nom."; + + try { + $organizer_id = intval(htmlspecialchars($_POST["organizer"])); + } + catch (Exception $ex) { + return "Un problème a eu lieu concernant le choix de l'organisateur. Merci de ne pas formuler vous-même vos requêtes."; + } + + $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $organizer_id . "' AND `year` = '$YEAR';"); + $data = $result->fetch(); + if ($data === FALSE) + return "L'organisateur spécifié n'existe pas."; + if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") + return "L'organisateur indiqué ne peut pas organiser de tournoi."; + $organize_mail = $data["email"]; + + try { + $size = intval(htmlspecialchars($_POST["size"])); + } + catch (Exception $ex) { + return "Le nombre d'équipes indiqué n'est pas un entier valide."; + } + + if ($size < 3 || $size > 12) + return "Un tournoi doit comporter entre 3 et 12 équipes."; + + $place = htmlspecialchars($_POST["place"]); + + try { + $price = intval(htmlspecialchars($_POST["price"])); + } + catch (Throwable $t) { + return "Le tarif pour les participants n'est pas un nombre valide."; + } + + if ($price < 0) + return "Le TFJM² ne va pas payer les élèves pour venir."; + + if ($price > 50) + return "Soyons raisonnable sur le prix."; + + $date_start = htmlspecialchars($_POST["date_start"]); + $date_start_parsed = date_parse_from_format("yyyy-mm-dd", $date_start); + + $date_end = htmlspecialchars($_POST["date_end"]); + $date_end_parsed = date_parse_from_format("yyyy-mm-dd", $date_end); + + $date_inscription = htmlspecialchars($_POST["date_inscription"]); + $time_inscription = htmlspecialchars($_POST["time_inscription"]); + $date_inscription_parsed = date_parse_from_format("yyyy-mm-dd", $date_inscription . ' ' . $time_inscription); + + $date_solutions = htmlspecialchars($_POST["date_solutions"]); + $time_solutions = htmlspecialchars($_POST["time_solutions"]); + $date_solutions_parsed = date_parse_from_format("yyyy-mm-dd", $date_solutions . ' ' . $time_solutions); + + $date_syntheses = htmlspecialchars($_POST["date_syntheses"]); + $time_syntheses = htmlspecialchars($_POST["time_syntheses"]); + $date_syntheses_parsed = date_parse_from_format("yyyy-mm-dd", $date_syntheses . ' ' . $time_syntheses); + + if (!$date_start_parsed || !$date_end_parsed || !$date_inscription_parsed || !$date_solutions_parsed || !$date_syntheses_parsed) + return "Une date est mal formée."; + + $description = htmlspecialchars($_POST["description"]); + + $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `organizer`, `size`, `place`, `description`, + `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + $result = $req->execute([$name, $organizer_id, $size, $place, $description, $date_start, $date_end, + "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $YEAR]); + + mail($organize_mail, "Organisateur TFJM² " . $name, "Vous venez d'être promu organisateur du tournoi " . $name . " pour le TFJM² $YEAR !", "From: $MAIL_ADDRESS"); + + return false; +} + +?> + + + + +

    Vous n'êtes pas autorisé à accéder à cette page.

    + + +Erreur : " . $error_message . ""; + } else { + echo "

    Tournoi de " . htmlspecialchars($_POST["name"]) . " ajouté avec succès !

    "; + } + }?> + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    + + + +
    + + + Du au +
    + + + + +
    + + + + +
    + + + + +
    + + + +
    + +
    +
    + + + + diff --git a/server_files/config.php b/server_files/config.php index 14c2f7f..b973cdf 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -26,12 +26,3 @@ catch (Exception $ex) { session_start(); setlocale(LC_ALL, "fr_FR.utf8"); - -require_once "model.php"; -require_once "classes/Role.php"; -require_once "classes/Team.php"; -require_once "classes/Tournament.php"; -require_once "classes/User.php"; -require_once "classes/ValidationStatus.php"; - -loadUserValues(); \ No newline at end of file diff --git a/server_files/confirmer_mail.php b/server_files/confirmer_mail.php new file mode 100644 index 0000000..951d5b4 --- /dev/null +++ b/server_files/confirmer_mail.php @@ -0,0 +1,26 @@ +query("SELECT `email` FROM `users` WHERE `confirm_email` = '$token' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + $error_message = "Le jeton est invalide. Votre compte est peut-être déjà validé ?"; + else { + $DB->exec("UPDATE `users` SET `confirm_email` = NULL WHERE `confirm_email` = '$token';"); + $error_message = "Votre adresse mail a été validée ! Vous pouvez désormais vous connecter."; + } +} +else { + $error_message = "Il n'y a pas de compte à valider !"; +} + +?> + + + +

    + + \ No newline at end of file diff --git a/server_files/connexion.php b/server_files/connexion.php new file mode 100644 index 0000000..e6bcefc --- /dev/null +++ b/server_files/connexion.php @@ -0,0 +1,76 @@ +query("SELECT `id`, `pwd_hash`, `email`, `surname`, `first_name`, `role`, `team_id` FROM `users` WHERE `email` = '" . $email . "';"); + if (($data = $result->fetch()) === FALSE) + return "Le compte n'existe pas."; + + if (!password_verify($password, $data["pwd_hash"])) + return "Le mot de passe est incorrect."; + + $_SESSION["user_id"] = $data["id"]; + $_SESSION["email"] = $data["email"]; + $_SESSION["surname"] = $data["surname"]; + $_SESSION["first_name"] = $data["first_name"]; + $_SESSION["role"] = $data["role"]; + $_SESSION["team_id"] = $data["team_id"]; + + $response = $DB->query("SELECT `tournament`, `validation_status` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $data = $response->fetch(); + $_SESSION["tournament_id"] = $data["tournament"]; + $_SESSION["team_validation_status"] = $data["validation_status"]; + + return false; +} + +?> + + + +Erreur : " . $error_message . ""; ?> + + + Connexion réussie ! + + +

    Vous êtes déjà connecté !

    + + + +
    + + + + + + + + + + + + + +
    +
    + + + + diff --git a/server_files/deconnexion.php b/server_files/deconnexion.php new file mode 100644 index 0000000..31b50ac --- /dev/null +++ b/server_files/deconnexion.php @@ -0,0 +1,14 @@ + + + + +

    Déconnexion réussie !

    + + diff --git a/server_files/equipe.php b/server_files/equipe.php new file mode 100644 index 0000000..4298a5f --- /dev/null +++ b/server_files/equipe.php @@ -0,0 +1,64 @@ +query("SELECT * FROM `teams` WHERE `trigram` = '$trigram';")->fetch(); + +$tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); + +$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `type` ORDER BY `user`, `type` ASC, `uploaded_at` DESC;"); +$documents_req->execute([$team_data["id"]]); + +?> + + + +

    Informations sur l'équipe

    + +Nom de l'équipe :
    +Trigramme :
    +Tournoi :
    +query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; +} +for ($i = 1; $i <= 6; ++$i) { + if ($team_data["participant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; +} +?> + +

    Autorisations

    + +fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $user_id = $data["user"]; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); + $surname = $user_data["surname"]; + $first_name = $user_data["first_name"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name de $first_name $surname : Télécharger
    "; +} +?> + + diff --git a/server_files/footer.php b/server_files/footer.php new file mode 100644 index 0000000..0289fab --- /dev/null +++ b/server_files/footer.php @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/server_files/header.php b/server_files/header.php new file mode 100644 index 0000000..48a0933 --- /dev/null +++ b/server_files/header.php @@ -0,0 +1,143 @@ +exec("UPDATE `users` SET `role` = 'ADMIN' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_SESSION["user_id"]) && isset($_GET["be-organizer"])) { + $DB->exec("UPDATE `users` SET `role` = 'ORGANIZER' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_SESSION["user_id"]) && isset($_GET["be-participant"])) { + $DB->exec("UPDATE `users` SET `role` = 'PARTICIPANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_SESSION["user_id"]) && isset($_GET["be-encadrant"])) { + $DB->exec("UPDATE `users` SET `role` = 'ENCADRANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); + quitTeam(); + header("Location: $URL_BASE"); + exit(); +} + +function quitTeam() { + global $DB, $URL_BASE; + + if ($_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") + return; + + for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); + for ($i = 1; $i <= 5; ++$i) { + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); + } + + $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + + if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { + $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); + + $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); + } + unset($_SESSION["team_id"]); + unset($_SESSION["team_validation_status"]); +} + +?> + + + + + + + Site d'inscription pour le TFJM² <?= $YEAR ?> + + + + + + + + + + + + + + + + + + +
    +
    + +
    \ No newline at end of file diff --git a/server_files/index.php b/server_files/index.php new file mode 100644 index 0000000..39fe89d --- /dev/null +++ b/server_files/index.php @@ -0,0 +1,114 @@ + + + + +
    + + + + + +
    + + +
    + + +

    Vous souhaitez participer au tournoi ? Votre équipe est déjà formée ?

    +

    Créez un compte pour commencer la procédure d'inscription ou connectez-vous si votre équipe a déjà un compte.

    +
    + +
    + +
    +

    Bienvenue sur le site d'inscription du TFJM2 !

    +
    + +
    + Ce site a été conçu pour gérer les inscriptions au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens. +
    + Cliquez ici pour accéder au site de présentation du tournoi. +
    + +
    + + +

    + Attention aux échéances ! Chaque tournoi a une date limite pour les inscriptions et une date limite pour déposer vos solutions. Elles sont affichées avec les informations de chaque tournoi. Merci de vous y référer ! +
    + Une fois l'échéance passée, le site bloque tout accès aux inscriptions (et respectivement au dépôt des solutions).
    +

    + +

    + Attention, modification du règlement par rapport aux années précédentes : article 4.3 +
    + "l’équipe doit envoyer par mail à contact@tfjm.org, une lettre (au format pdf), répondant aux questions suivantes : +
    + +

      +
    • Comment l’équipe s’est-elle formée ?
    • +
    • Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres avec l’encadrant•e) ?
    • +
    + + Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non l’inscription des équipes concernées par cette lettre." +
    + + Pour plus de détail, voir le règlement : https://tfjm.org/infos-tournois/ +

    + + +
    +

    Comment ça marche ?

    +
    + +

    + Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer par la suite. +

    + +

    + Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : +

      +
    • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
    • +
    • enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière version enregistrée avant + la date limite sera prise en compte pour le tournoi).
    • +
    + + Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, votre inscription pourra être validée par les organisateurs locaux. +

    + + +

    ATTENTION ! Votre équipe ne sera considérée comme admissible à participer au tournoi que lorsque cette première étape aura été franchie.

    + +

    Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes seront placées en liste d'attente. +

    + +

    + Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers le site pour compléter votre inscription. +

    + + +

    ATTENTION ! Les équipes qui ne respecteront pas les délais pour rendre ces documents risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente.

    + +

    + NB : Ce site est récent et il est encore possible que certaines pages ne fonctionnent pas correctement. Si vous remarquez des bugs, merci de les signaler à l'adresse contact@tfjm.org. +

    + + + + + + + + + +
    + + \ No newline at end of file diff --git a/server_files/inscription.php b/server_files/inscription.php new file mode 100644 index 0000000..a2e85b4 --- /dev/null +++ b/server_files/inscription.php @@ -0,0 +1,278 @@ +query("SELECT `email` FROM `users` WHERE `email` = '" . $email . "' AND `year` = '$YEAR';"); + if ($result->fetch()) + return "Un compte existe déjà avec cette adresse e-mail."; + + $password = htmlspecialchars($_POST["password"]); + if (strlen($password) < 8) + return "Le mot de passe doit comporter au moins 8 caractères."; + if ($password != $_POST["confirm_password"]) + return "Les deux mots de passe sont différents."; + + $password = password_hash($password, PASSWORD_BCRYPT); + + $surname = strtoupper(htmlspecialchars($_POST["surname"])); + if (!isset($surname) || $surname == "") + return "Le nom de famille est obligatoire."; + + $firstname = htmlspecialchars($_POST["firstname"]); + if (!isset($surname) || $surname == "") + return "Le prénom est obligatoire."; + + $birth_date = date_parse_from_format("yyyy-mm-dd", htmlspecialchars($_POST["birth_date"])); + + if ($birth_date === FALSE) + return "La date de naissance est invalide."; + + if (htmlspecialchars($_POST["birth_date"]) >= $YEAR . "-01-01") + return "Vous devez avoir un âge strictement positif. Date de naissance rentrée : " . htmlspecialchars($_POST["birth_date"]); + + $gender = htmlspecialchars($_POST["gender"]); + + if (!isset($gender) || ($gender != "M" && $gender != "F")) + return "Le sexe indiqué est invalide."; + + $address = htmlspecialchars($_POST["address"]); + + if (!isset($address)) + $address = ""; + + try { + $postal_code = intval($_POST["postal_code"]); + if ($postal_code < 1000 || $postal_code > 95999) + return "Le code postal est invalide."; + } + catch (Exception $ex) { + return "Le code postal n'est pas un nombre valide."; + } + + $city = htmlspecialchars($_POST["city"]); + + if (!isset($city)) + $city = ""; + + $country = htmlspecialchars($_POST["country"]); + + if (!isset($country)) + $country = "France"; + + $phone_number = htmlspecialchars($_POST["phone_number"]); + + if (!isset($phone_number) || $phone_number == "") + return "Vous devez renseigner un numéro de téléphone."; + + $role = htmlspecialchars($_POST["role"]); + + if (!isset($role) || ($role != "participant" && $role != "encadrant")) + return "Le rôle entré n'est pas valide."; + + $role = strtoupper($role); + + $school = htmlspecialchars($_POST["school"]); + $class = strtoupper(htmlspecialchars($_POST["class"])); + $responsible_name = htmlspecialchars($_POST["responsible_name"]); + $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); + $responsible_email = htmlspecialchars($_POST["responsible_email"]); + + if ($role == "ENCADRANT") { + $school = NULL; + $class = NULL; + $responsible_name = NULL; + $responsible_phone = NULL; + $responsible_email = NULL; + } + else { + if (!isset($class) && $class != "TERMINALE" && $class != "PREMIERE" && $class != "SECONDE") + return "La classe spécifiée est invalide. Merci de ne pas créer vos propres requêtes."; + + if ((!isset($responsible_name) || $responsible_name == "") && $birth_date > strval($YEAR - 18) . "-05-01") + return "Veuillez spécifier un nom de responsable légal."; + + if ((!isset($responsible_phone) || $responsible_phone == "") && (!isset($responsible_email) || !filter_var($responsible_email, FILTER_VALIDATE_EMAIL)) + && $birth_date > strval($YEAR - 18) . "-05-01") + return "Veuillez préciser au moins le numéro de téléphone ou l'addresse e-mail de votre responsable légal."; + } + + $description = $_POST["description"]; + + if ($role == "PARTICIPANT") + $description = NULL; + + $confirm_email_uid = uniqid(); + + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, + `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + $req->execute([$email, $password, $confirm_email_uid, $surname, $firstname, $_POST["birth_date"], $gender, $address, $postal_code, + $city, $country, $phone_number, $school, $class, $role, $description, $YEAR]); + + $msg = "Merci pour votre inscription au TFJM² $YEAR ! Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; + mail($email, "Inscription au TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + Erreur : " . $error_message . ""; ?> + + + Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. + + +

    Vous êtes déjà connecté !

    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    " />
    +
    " />
    +
    + + + + + + diff --git a/server_files/mon_compte.php b/server_files/mon_compte.php new file mode 100644 index 0000000..d4dba41 --- /dev/null +++ b/server_files/mon_compte.php @@ -0,0 +1,323 @@ +query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "';"); + $user_data = $result->fetch(); +} + +function updateAccount() +{ + global $DB, $URL_BASE, $MAIL_ADDRESS; + + if (!isset($_SESSION["user_id"])) + return "Vous n'êtes pas connecté."; + + $ID = $_SESSION["user_id"]; + + $surname = htmlspecialchars($_POST["surname"]); + if (isset($surname) && $surname != "") + $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $ID]); + + $first_name = htmlspecialchars($_POST["firstname"]); + if (isset($first_name) && $first_name != "") + $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $ID]); + + $birth_date = htmlspecialchars($_POST["birth_date"]); + if (isset($birth_date) && $birth_date != "") + $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $ID]); + + if (isset($_POST["gender"])) { + $gender = htmlspecialchars($_POST["gender"]); + if (isset($gender) && ($gender == "M" || $gender == "F")) + $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $ID]); + } + + $address = htmlspecialchars($_POST["address"]); + if (isset($address) && $address != "") + $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $ID]); + + $postal_code = htmlspecialchars($_POST["postal_code"]); + if (isset($postal_code) && $postal_code != "") + $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $ID]); + + $city = htmlspecialchars($_POST["city"]); + if (isset($city) && $city != "") + $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $ID]); + + $country = htmlspecialchars($_POST["country"]); + if (isset($country) && $country != "") + $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $ID]); + + $phone_number = htmlspecialchars($_POST["phone_number"]); + if (isset($phone_number) && $phone_number != "") + $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $ID]); + + if (isset($_POST["school"])) { + $school = htmlspecialchars($_POST["school"]); + if (isset($school) && $school != "") + $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $ID]); + } + + if (isset($_POST["class"])) { + $class = htmlspecialchars($_POST["class"]); + if (isset($class) && ($class == "terminale" || $class == "premiere" || $class == "seconde")) + $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([strtoupper($class), $ID]); + } + + if (isset($_POST["responsible_name"])) { + $responsible_name = htmlspecialchars($_POST["responsible_name"]); + if (isset($responsible_name) && $responsible_name != "") + $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $ID]); + } + + if (isset($_POST["responsible_phone"])) { + $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); + if (isset($responsible_phone) && $responsible_phone != "") + $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $ID]); + } + + if (isset($_POST["responsible_email"])) { + $responsible_email = htmlspecialchars($_POST["responsible_email"]); + if (isset($responsible_email) && $responsible_email != "") + $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $ID]); + } + + if (isset($_POST["description"])) { + $description = htmlspecialchars($_POST["description"]); + if (isset($description) && $description != "") + $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$description, $ID]); + } + + $email = htmlspecialchars($_POST["email"]); + if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { + $confirm_email_uid = uniqid(); + $DB->prepare("UPDATE `users` SET `email` = ?, `confirm_email` = ? WHERE `id` = ?;")->execute([$email, $confirm_email_uid, $ID]); + + $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; + mail($email, "Changement d'adresse mail - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); + } + + return false; +} + +function updatePassword() +{ + global $DB, $YEAR; + + $old = htmlspecialchars($_POST["old_password"]); + $new = htmlspecialchars($_POST["new_password"]); + $confirm = htmlspecialchars($_POST["confirm_password"]); + + $result = $DB->query("SELECT `pwd_hash` FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + return "Le compte n'existe pas."; + + if (!password_verify($old, $data["pwd_hash"])) + return "L'ancien mot de passe est incorrect."; + + if (strlen($new) < 8) + return "Le mot de passe doit comporter au moins 8 caractères."; + + if ($new != $confirm) + return "Les deux mots de passe sont différents."; + + $hash = password_hash($new, PASSWORD_BCRYPT); + + $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$hash, $_SESSION["user_id"]]); + + return false; +} + +?> + + + +Vous devez être connecté pour afficher cette page."; + include "footer.php"; + return; +} ?> + +Erreur : " . $error_message . ""; ?> + + +

    Votre compte a bien été mis à jour !

    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    /> + />
    + + + +
    + +
    + + + +
    + +
    + + + +
    + +
    +
    + +
    + +
    + + + + + + + + + + + + + + + + + +
    +
    + + diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php new file mode 100644 index 0000000..c29fd22 --- /dev/null +++ b/server_files/mon_equipe.php @@ -0,0 +1,200 @@ +exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); + $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); + for ($i = 1; $i <= 5; ++$i) { + /** @noinspection SqlResolve */ + $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); + } + + $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); + + if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { + $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); + + $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); + while (($data = $req->fetch()) !== false) + unlink("$URL_BASE/files/" . $data["file_id"]); + $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); + } + unset($_SESSION["team_id"]); + unset($_SESSION["team_validation_status"]); + header("Location: $URL_BASE"); + exit(); +} + +if (isset($_POST["send_document"])) { + sendDocument(); +} + +if (isset($_POST["request_validation"])) { + $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); + $_SESSION["team_validation_status"] = "WAITING"; +} + +if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { + $result = $DB->query("SELECT * FROM `teams` WHERE `id` = '" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); + $team_data = $result->fetch(); + + $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); + + $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? GROUP BY `type` ORDER BY `type` ASC, `uploaded_at` DESC;"); + $documents_req->execute([$_SESSION["user_id"]]); +} + +function sendDocument() { + global $LOCAL_PATH, $DB; + + $type = strtoupper(htmlspecialchars($_POST["type"])); + if (!isset($type) || ($type != "PARENTAL_CONSENT" && $type != "PHOTO_CONSENT" && $type != "SANITARY_PLUG")) + return "Le type de document est invalide. Merci de ne pas formuler vos propres requêtes."; + + $file = $_FILES["document"]; + + if ($file["size"] > 5000000 || $file["error"]) + return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; + + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') + return "Le fichier doit être au format PDF."; + + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) + return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; + + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) + return "Une erreur est survenue lors de l'envoi du fichier."; + + $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `tournament`, `type`) + VALUES (?, ?, ?, ?, ?);"); + $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION["tournament_id"], $type]); + + return false; +} + +?> + + + +Vous devez être dans une équipe pour afficher cette page."; + include "footer.php"; + return; +} ?> + +Erreur : " . $error_message . ""; + } + else { + echo "

    Le fichier a été correctement envoyé !

    "; + } +}?> + +

    Informations sur l'équipe

    + +Nom de l'équipe :
    +Trigramme :
    +Tournoi :
    +query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; +} +for ($i = 1; $i <= 6; ++$i) { + if ($team_data["participant_" . $i] == NULL) + continue; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); + echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; +} +?> +Code d'accès : + + +
    +

    Mes autorisations

    + fetch()) !== false) { + $file_id = $data["file_id"]; + $type = $data["type"]; + $version = $data["version"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + echo "$name : Télécharger
    "; + } + ?> + +
    + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    +
    +
    + +
    +
    + +
    + + + diff --git a/server_files/rejoindre_equipe.php b/server_files/rejoindre_equipe.php new file mode 100644 index 0000000..0463f5a --- /dev/null +++ b/server_files/rejoindre_equipe.php @@ -0,0 +1,93 @@ +query("SELECT * FROM `teams` WHERE `access_code` = '" . $access_code . "' AND `year` = '$YEAR';"); + if (($data = $result->fetch()) === FALSE) + return "Ce code d'accès est invalide."; + + if ($_SESSION["role"] != "PARTICIPANT" && $_SESSION["role"] != "ENCADRANT") + return "Seuls les participants et les encadrants peuvent rejoindre une équipe."; + + if ($data["validation_status"] != "NOT_READY") + return "Cette équipe est déjà en cours de validation ou validée, vous ne pouvez pas la rejoindre."; + + for ($i = 1; $i <= $_SESSION["role"] == "PARTICIPANT" ? 6 : 2; ++$i) { + if ($data[strtolower($_SESSION["role"]) . "_" . strval($i)] == NULL) + break; + } + + if ($_SESSION["role"] == "PARTICIPANT" && $i == 7 || $_SESSION["role"] == "ENCADRANT" && $i == 3) + return "Il n'y a plus de place pour vous dans l'équipe."; + + $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data["id"]]); + /** @noinspection SqlResolve */ + $DB->prepare("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_" . strval($i) . "` = ? WHERE `id` = " . $data["id"] . ";")->execute([$_SESSION["user_id"]]); + + $_SESSION["team_id"] = $data["id"]; + $_SESSION["team_validation_status"] = $data["validation_status"]; + + $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; + $msg .= "Vous venez de rejoindre l'équipe « " . $data["name"] . " » (" . $data["trigram"] . ") pour le TFJM² de " . $data["name"] . " et nous vous en remercions.\r\n\r\n"; + $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; + mail($_SESSION["email"], "Équipe rejointe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + + return false; +} + +?> + + + + +

    Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

    + + Vous avez bien rejoint l'équipe ! + +

    Vous êtes déjà dans une équipe.

    + + +Erreur : " . $error_message . ""; ?> + +
    + + + + + + + + + + + +
    + + + +
    + +
    +
    + + + + diff --git a/server_files/solutions.php b/server_files/solutions.php new file mode 100644 index 0000000..d243f31 --- /dev/null +++ b/server_files/solutions.php @@ -0,0 +1,115 @@ +prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? GROUP BY `problem` ORDER BY `problem` ASC, `uploaded_at` DESC;"); +$solutions_req->execute([$_SESSION["team_id"]]); + +function saveSolution() { + global $LOCAL_PATH, $DB; + + try { + $problem = $_POST["problem"]; + if ($problem < 1 || $problem > 9) + return "Le numéro de problème est invalide."; + } + catch (Throwable $t) { + return "Le numéro de problème n'est pas valide. Merci de ne pas créer vos propres requêtes."; + } + + $file = $_FILES["solution"]; + + if ($file["size"] > 5000000 || $file["error"]) + return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; + + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') + return "Le fichier doit être au format PDF."; + + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) + return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; + + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) + return "Une erreur est survenue lors de l'envoi du fichier."; + + $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) + VALUES (?, ?, ?, ?);"); + $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $problem]); + + return false; +} + +?> + + + +Erreur : " . $error_message . ""; + } else { + echo "

    Le fichier a été correctement envoyé !

    "; + } +}?> + +
    + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    +
    + +
    + +

    Solutions soumises :

    + +fetch()) !== false) { + $file_id = $data["file_id"]; + $problem = $data["problem"]; + $version = $data["version"]; + echo "Problème $problem (Version $version) : Télécharger
    "; +} +?> + + diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php new file mode 100644 index 0000000..58b67df --- /dev/null +++ b/server_files/solutions_orga.php @@ -0,0 +1,29 @@ + + + + +query("SELECT `id`, `name` FROM `tournaments` WHERE " + . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") + . "`year` = $YEAR ORDER BY `name`;"); + +while (($data_tournament = $req->fetch()) !== false) { + echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; + $id = $data_tournament["id"]; + $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + while (($data_file = $files_req->fetch()) !== false) { + $file_id = $data_file["file_id"]; + $problem = $data_file["problem"]; + $version = $data_file["version"]; + $team_id = $data_file["team"]; + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); + $team_name = $team_data["name"]; + $team_trigram = $team_data["trigram"]; + echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
    "; + } +} + +?> + + diff --git a/server_files/syntheses.php b/server_files/syntheses.php new file mode 100644 index 0000000..377825f --- /dev/null +++ b/server_files/syntheses.php @@ -0,0 +1,109 @@ +prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? GROUP BY `dest` ORDER BY `dest` ASC, `uploaded_at` DESC;"); +$syntheses_req->execute([$_SESSION["team_id"]]); + +function saveSynthese() { + global $LOCAL_PATH, $DB; + + $dest = strtoupper(htmlspecialchars($_POST["dest"])); + + if (!isset($dest) || ($dest != "OPPOSANT" && $dest != "RAPPORTEUR")) + return "Le destinataire est invalide."; + + $file = $_FILES["synthese"]; + + if ($file["size"] > 5000000 || $file["error"]) + return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; + + if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') + return "Le fichier doit être au destmat PDF."; + + if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) + return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; + + $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; + + do { + $id = ""; + for ($i = 0; $i < 64; ++$i) { + $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; + } + } + while (file_exists("$LOCAL_PATH/files/$id")); + + if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) + return "Une erreur est survenue lors de l'envoi du fichier."; + + $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) + VALUES (?, ?, ?, ?);"); + $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $dest]); + + return false; +} + +?> + + + +Erreur : " . $error_message . ""; + } + else { + echo "

    Le fichier a été correctement envoyé !

    "; + } +}?> + +
    + + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    +
    + +
    + +

    Notes de synthèse soumises :

    + +fetch()) !== false) { + $file_id = $data["file_id"]; + $dest = $data["dest"]; + $version = $data["version"]; + echo "Note de synthèse pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . " (Version $version) : Télécharger
    "; +} +?> + + diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php new file mode 100644 index 0000000..348b6e6 --- /dev/null +++ b/server_files/syntheses_orga.php @@ -0,0 +1,30 @@ + + + + +query("SELECT `id`, `name` FROM `tournaments` WHERE " + . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") + . "`year` = $YEAR ORDER BY `name`;"); + +while (($data_tournament = $req->fetch()) !== false) { + echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; + $id = $data_tournament["id"]; + $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + while (($data_file = $files_req->fetch()) !== false) { + $file_id = $data_file["file_id"]; + $dest = $data_file["dest"]; + $version = $data_file["version"]; + $team_id = $data_file["team"]; + $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); + $team_name = $team_data["name"]; + $team_trigram = $team_data["trigram"]; + echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") + . ", version $version : Télécharger
    "; + } +} + +?> + + diff --git a/server_files/tournoi.php b/server_files/tournoi.php new file mode 100644 index 0000000..b0780eb --- /dev/null +++ b/server_files/tournoi.php @@ -0,0 +1,107 @@ +prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year` = $YEAR;"); +$response->execute([$tournament_name]); +$data = $response->fetch(); + +$orga_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $data["organizer"] . " AND `year` = $YEAR;")->fetch(); +$orga_name = $orga_data["first_name"] . " " . $orga_data["surname"]; + +$teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); + +?> + + + +

    Tournoi de

    + + Organisateur :
    + Nombre d'équipes maximal :
    + Lieu :
    + Prix par partipant :
    + Dates : Du au
    + Clôture des inscriptions :
    + Date limite d'envoi des solutions :
    + Date limite d'envoi des notes de synthèse :
    + Description : + +

    Équipes inscrites à ce tournoi :

    + + + + + + + + + + + + fetch()) != false) { + ?> + + + + + + + + + + + + + + + + +
    + Équipe + + Trigramme + + Date d'inscription + + État de validation de l'inscription +
    + " . $team_data["name"] . ""; + else + echo $team_data["name"]; + ?> + + +
    + Équipe + + Trigramme + + Date d'inscription + + État de validation de l'inscription +
    + + \ No newline at end of file diff --git a/server_files/tournois.php b/server_files/tournois.php new file mode 100644 index 0000000..a5b04fb --- /dev/null +++ b/server_files/tournois.php @@ -0,0 +1,50 @@ +query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` + WHERE `year` = '$YEAR' ORDER BY `date_start`, `name`;"); + +?> + + + +

    Liste des tournois

    + + + + + + + + + + + + + fetch()) !== FALSE) { + ?> + + + + + + + + + + + + + + + + + + +
    LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    ">Du au
    LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    + + \ No newline at end of file diff --git a/server_files/view_file.php b/server_files/view_file.php new file mode 100644 index 0000000..81c3432 --- /dev/null +++ b/server_files/view_file.php @@ -0,0 +1,67 @@ +query("SELECT * FROM `solutions` WHERE `file_id` = '$id';"); +if (($data = $req->fetch()) === false) { + $req = $DB->query("SELECT * FROM `syntheses` WHERE `file_id` = '$id';"); + $type = "SYNTHESE"; + + if (($data = $req->fetch()) === false) { + $req = $DB->query("SELECT * FROM `documents` WHERE `file_id` = '$id';"); + $type = "DOCUMENT"; + $data = $req->fetch(); + } +} +print_r($type); +if ($data !== false) { + $team_data = $DB->query("SELECT `trigram` FROM `teams` WHERE `id` = " . $data["team"] . ";")->fetch(); + $tournament_data = $DB->query("SELECT `name` FROM `tournaments` WHERE `id` = " . $data["tournament"] . ";")->fetch(); + $trigram = $team_data["trigram"]; + if ($type == "SOLUTION") { + $problem = $data["problem"]; + $name = "Problème $problem $trigram.pdf"; + } + else if ($type == "SYNTHESE") { + $dest = $data["dest"]; + $name = "Note de synthèse $trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"; + } + else if ($type == "DOCUMENT") { + $user_id = $data["user"]; + $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = 'user';")->fetch(); + $surname = $user_data["surname"]; + $first_name = $user_data["first_name"]; + switch ($data["type"]) { + case "PARENTAL_CONSENT": + $name = "Autorisation parentale"; + break; + case "PHOTO_CONSENT": + $name = "Autorisation de droit à l'image"; + break; + case "SANITARY_PLUG": + $name = "Fiche sanitaire"; + break; + } + $name .= " de $first_name $surname.pdf"; + } +} +else { + include_once "404.php"; + http_response_code(404); + exit(); +} + +header("Content-Type: application/pdf"); +header("Content-Disposition: inline; filename=\"$name\""); + +readfile("$URL_BASE/files/$id"); + +exit(); \ No newline at end of file From 4d3f6d18479deb95d58943b8c5804150b23de453 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 13:42:36 +0200 Subject: [PATCH 037/120] =?UTF-8?q?Utilisation=20d'un=20dispatcher=20pour?= =?UTF-8?q?=20g=C3=A9rer=20les=20redirections?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .htaccess | 29 ++------ favicon.ico => assets/favicon.ico | Bin logo.svg => assets/logo.svg | 0 style.css => assets/style.css | 0 dispatcher.php | 68 ++++++++++++++++++ index.html | 13 +++- server_files/classes/Team.php | 2 - server_files/classes/Tournament.php | 2 - server_files/classes/User.php | 2 - server_files/controllers/ajouter_equipe.php | 8 +-- .../controllers/ajouter_organisateur.php | 8 +-- server_files/controllers/ajouter_tournoi.php | 8 +-- server_files/controllers/confirmer_mail.php | 6 +- server_files/controllers/connexion.php | 6 +- server_files/controllers/deconnexion.php | 6 +- server_files/controllers/equipe.php | 10 +-- server_files/controllers/index.php | 5 +- server_files/controllers/informations.php | 12 ++-- server_files/controllers/inscription.php | 6 +- server_files/controllers/mon_compte.php | 8 +-- server_files/controllers/mon_equipe.php | 8 +-- server_files/controllers/rejoindre_equipe.php | 8 +-- server_files/controllers/solutions.php | 21 +++--- server_files/controllers/solutions_orga.php | 8 +-- server_files/controllers/syntheses.php | 21 +++--- server_files/controllers/syntheses_orga.php | 10 ++- server_files/controllers/tournoi.php | 12 ++-- server_files/controllers/tournois.php | 6 +- server_files/controllers/view_file.php | 10 ++- server_files/views/ajouter_equipe.php | 9 ++- server_files/views/ajouter_organisateur.php | 4 ++ server_files/views/ajouter_tournoi.php | 9 ++- server_files/views/connexion.php | 11 ++- server_files/views/equipe.php | 6 +- server_files/views/header.php | 10 +-- server_files/views/index.php | 6 +- server_files/views/informations.php | 6 +- server_files/views/inscription.php | 11 ++- server_files/views/mon_compte.php | 11 ++- server_files/views/mon_equipe.php | 10 ++- server_files/views/rejoindre_equipe.php | 9 ++- server_files/views/solutions.php | 10 ++- server_files/views/syntheses.php | 11 +-- server_files/views/tournoi.php | 4 ++ server_files/views/tournois.php | 6 +- 45 files changed, 246 insertions(+), 190 deletions(-) rename favicon.ico => assets/favicon.ico (100%) rename logo.svg => assets/logo.svg (100%) rename style.css => assets/style.css (100%) create mode 100644 dispatcher.php diff --git a/.htaccess b/.htaccess index 7f2d8b2..12806a1 100644 --- a/.htaccess +++ b/.htaccess @@ -1,28 +1,7 @@ -ErrorDocument 403 /tfjm/403.php -ErrorDocument 404 /tfjm/404.php +ErrorDocument 403 /tfjm/server_files/403.php +ErrorDocument 404 /tfjm/server_files/404.php Options +FollowSymlinks -# Options -Indexes +Options -Indexes RewriteEngine On -RewriteOptions Inherit -RewriteBase /tfjm -RewriteRule index.html accueil [L] -RewriteRule ^accueil$ server_files/index.php [L] -RewriteRule ^ajouter_equipe$ server_files/ajouter_equipe.php [L] -RewriteRule ^ajouter_organisateur$ server_files/ajouter_organisateur.php [L] -RewriteRule ^ajouter_tournoi$ server_files/ajouter_tournoi.php [L] -RewriteRule ^confirmer_mail/(.*?)$ server_files/confirmer_mail.php?token=$1 [L] -RewriteRule ^connexion$ server_files/connexion.php [L] -RewriteRule ^deconnexion$ server_files/deconnexion.php [L] -RewriteRule ^equipe/(.*?)$ server_files/equipe.php?trigram=$1 [L] -RewriteRule ^file/(.*?)$ server_files/view_file.php?file_id=$1 [L] -RewriteRule ^inscription$ server_files/inscription.php [L] -RewriteRule ^mon_compte$ server_files/mon_compte.php [L] -RewriteRule ^mon_equipe$ server_files/mon_equipe.php [L] -RewriteRule ^rejoindre_equipe$ server_files/rejoindre_equipe.php [L] -RewriteRule ^solutions$ server_files/solutions.php [L] -RewriteRule ^solutions_orga$ server_files/solutions_orga.php [L] -RewriteRule ^syntheses$ server_files/syntheses.php [L] -RewriteRule ^syntheses_orga$ server_files/syntheses_orga.php [L] -RewriteRule ^tournoi/(.*?)$ server_files/tournoi.php?nom=$1 [L] -RewriteRule ^tournois$ server_files/tournois.php [L] +RewriteRule ^(.*)$ dispatcher.php?path=$1 [QSA,L] diff --git a/favicon.ico b/assets/favicon.ico similarity index 100% rename from favicon.ico rename to assets/favicon.ico diff --git a/logo.svg b/assets/logo.svg similarity index 100% rename from logo.svg rename to assets/logo.svg diff --git a/style.css b/assets/style.css similarity index 100% rename from style.css rename to assets/style.css diff --git a/dispatcher.php b/dispatcher.php new file mode 100644 index 0000000..68f1947 --- /dev/null +++ b/dispatcher.php @@ -0,0 +1,68 @@ + $file) { + if (preg_match('#' . $route . '#', $path, $matches)) { + for ($i = 1; $i < sizeof($file); ++$i) + $_GET[$file[$i]] = $matches[$i]; + + if (!preg_match("#php$#", $file[0])) { + header("Content-Type: " . $matches[1]); + readfile($file[0]); + exit(); + } + + /** @noinspection PhpIncludeInspection */ + require $file[0]; + exit(); + } +} + +require_once "server_files/404.php"; diff --git a/index.html b/index.html index 57acf64..da8c197 100644 --- a/index.html +++ b/index.html @@ -1 +1,12 @@ -Le mod Rewrite n'est pas activé. \ No newline at end of file + + + + + + Erreur + + + +Le mode Rewrite n'est pas activé. + + \ No newline at end of file diff --git a/server_files/classes/Team.php b/server_files/classes/Team.php index 377c94e..53e29a1 100644 --- a/server_files/classes/Team.php +++ b/server_files/classes/Team.php @@ -1,7 +1,5 @@ query("SELECT `id`, `name` FROM `tournaments` WHERE `date_inscription` > CURRENT_DATE AND `year` = '$YEAR';"); @@ -62,6 +60,4 @@ function registerTeam() { return false; } -require_once "../views/header.php"; -require_once "../views/ajouter_equipe.php"; -require_once "../views/footer.php"; +require_once "server_files/views/ajouter_equipe.php"; diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index 3300334..ebf5cce 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -1,9 +1,7 @@ query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); @@ -109,6 +107,4 @@ function registerTournament() { return false; } -require_once "../views/header.php"; -require_once "../views/ajouter_tournoi.php"; -require_once "../views/footer.php"; +require_once "server_files/views/ajouter_tournoi.php"; diff --git a/server_files/controllers/confirmer_mail.php b/server_files/controllers/confirmer_mail.php index 484a024..abe2e58 100644 --- a/server_files/controllers/confirmer_mail.php +++ b/server_files/controllers/confirmer_mail.php @@ -1,7 +1,5 @@ $error_message"; -require_once "../views/footer.php"; +require_once "server_files/views/footer.php"; diff --git a/server_files/controllers/connexion.php b/server_files/controllers/connexion.php index dda3d3e..41f14f7 100644 --- a/server_files/controllers/connexion.php +++ b/server_files/controllers/connexion.php @@ -1,7 +1,5 @@ Déconnexion réussie !"; -require_once "../views/footer.php"; +require_once "server_files/views/footer.php"; diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 40364aa..3e584e0 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -1,16 +1,14 @@ setValidationStatus(ValidationStatus::VALIDATED); @@ -73,6 +71,4 @@ if ($team->isSelectedForFinal()) { $tournament = Tournament::fromId($team->getTournamentId()); -require_once "../views/header.php"; -require_once "../views/equipe.php"; -require_once "../views/footer.php"; +require_once "server_files/views/equipe.php"; diff --git a/server_files/controllers/index.php b/server_files/controllers/index.php index 254491b..a884dca 100644 --- a/server_files/controllers/index.php +++ b/server_files/controllers/index.php @@ -1,6 +1,3 @@ getId() != $_SESSION["user_id"] && ($user->getTeamId() == null || $user->getTeamId() != $_SESSION["user"]->getTeamId())) - require_once "../403.php"; + require_once "server_files/403.php"; } if ($user === null) { - require_once "../404.php"; + require_once "server_files/404.php"; } $team = Team::fromId($user->getTeamId()); @@ -22,6 +20,4 @@ $team = Team::fromId($user->getTeamId()); $documents_req = $DB->query("SELECT * FROM `documents` WHERE `user` = $id;"); $tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `date_start`, `name`;"); -require_once "../views/header.php"; -require_once "../views/informations.php"; -require_once "../views/footer.php"; +require_once "server_files/views/informations.php"; diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 54101e4..5b39e6a 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -1,7 +1,5 @@ execute([$_SESSION["user_id"], $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $tournament->getId()]]); } else - require_once "../403.php"; + require_once "server_files/403.php"; if (isset($_POST["team_edit"])) { $error_message = updateTeam(); @@ -158,6 +156,4 @@ function checkCanValidate() return $can_validate; } -require_once "../views/header.php"; -require_once "../views/mon_equipe.php"; -require_once "../views/footer.php"; +require_once "server_files/views/mon_equipe.php"; diff --git a/server_files/controllers/rejoindre_equipe.php b/server_files/controllers/rejoindre_equipe.php index bc41129..8ae550e 100644 --- a/server_files/controllers/rejoindre_equipe.php +++ b/server_files/controllers/rejoindre_equipe.php @@ -1,9 +1,7 @@ prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); -$solutions_req->execute([$_SESSION["team_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); +/** @var Team $team */ +$team = $_SESSION["team"]; -$tournament_req = $DB->prepare("SELECT `date_solutions` FROM `tournaments` WHERE `id` = ?;"); -$tournament_req->execute([$_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); -$tournament_data = $tournament_req->fetch(); +$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); +$solutions_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()]]); + +$tournament = Tournament::fromId($team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()); function saveSolution() { global $LOCAL_PATH, $DB; @@ -58,6 +57,4 @@ function saveSolution() { return false; } -require_once "../views/header.php"; -require_once "../views/solutions.php"; -require_once "../views/footer.php"; +require_once "server_files/views/solutions.php"; diff --git a/server_files/controllers/solutions_orga.php b/server_files/controllers/solutions_orga.php index b1054d8..c049dba 100644 --- a/server_files/controllers/solutions_orga.php +++ b/server_files/controllers/solutions_orga.php @@ -1,9 +1,7 @@ query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " @@ -47,7 +45,7 @@ if (isset($_POST["download_zip"])) { exit(); } -require_once "../views/header.php"; +require_once "server_files/views/header.php"; while (($data_tournament = $req->fetch()) !== false) { echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; @@ -72,4 +70,4 @@ while (($data_tournament = $req->fetch()) !== false) { echo "
    \n"; } -require_once "../views/footer.php"; +require_once "server_files/views/footer.php"; diff --git a/server_files/controllers/syntheses.php b/server_files/controllers/syntheses.php index 4c39972..06f78b0 100644 --- a/server_files/controllers/syntheses.php +++ b/server_files/controllers/syntheses.php @@ -1,20 +1,19 @@ prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); -$syntheses_req->execute([$_SESSION["team_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); +/** @var Team $team */ +$team = $_SESSION["team"]; -$tournament_req = $DB->prepare("SELECT `date_solutions`, `date_syntheses` FROM `tournaments` WHERE `id` = ?;"); -$tournament_req->execute([$_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"]]); -$tournament_data = $tournament_req->fetch(); +$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); +$syntheses_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()]]); + +$tournament = Tournament::fromId($team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()); function saveSynthese() { global $LOCAL_PATH, $DB; @@ -54,6 +53,4 @@ function saveSynthese() { return false; } -require_once "../views/header.php"; -require_once "../views/syntheses.php"; -require_once "../views/footer.php"; +require_once "server_files/views/syntheses.php"; diff --git a/server_files/controllers/syntheses_orga.php b/server_files/controllers/syntheses_orga.php index 6841076..f8f852b 100644 --- a/server_files/controllers/syntheses_orga.php +++ b/server_files/controllers/syntheses_orga.php @@ -1,7 +1,5 @@ -query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " . ($_SESSION["role"] == Role::ADMIN ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") @@ -69,4 +67,4 @@ while (($data_tournament = $req->fetch()) !== false) { echo "
    \n"; } -require_once '../views/footer.php'; +require_once "server_files/views/footer.php"; diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 7fbafce..43010f5 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -1,13 +1,11 @@ query("SELECT `users`.`id` AS `id` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $tournament->getId() . ";"); $orgas = []; @@ -18,7 +16,7 @@ while (($orga_data = $orgas_req->fetch()) !== false) { } if (isset($_GET["modifier"]) && $_SESSION["role"] != Role::ADMIN && !in_array($_SESSION["user_id"], $orgas_id)) - require_once "../403.php"; + require_once "server_files/403.php"; if (isset($_POST["edit_tournament"])) { $error_message = updateTournament(); @@ -123,6 +121,4 @@ function updateTournament() { exit(); } -require_once "../views/header.php"; -require_once "../views/tournoi.php"; -require_once "../views/footer.php"; +require_once "server_files/views/tournoi.php"; diff --git a/server_files/controllers/tournois.php b/server_files/controllers/tournois.php index a12ff7c..ce23d82 100644 --- a/server_files/controllers/tournois.php +++ b/server_files/controllers/tournois.php @@ -1,11 +1,7 @@ query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` WHERE `year` = '$YEAR' AND `final` = false ORDER BY `date_start`, `name`;"); $final_data = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_solutions`, `size` FROM `tournaments` WHERE `final` AND `year` = $YEAR;")->fetch(); -require_once "../views/header.php"; -require_once "../views/tournois.php"; -require_once "../views/footer.php"; +require_once "server_files/views/tournois.php"; diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index 0ce1807..5b14be0 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -1,14 +1,12 @@ getId() != $team->getId())) - require_once "../403.php"; + require_once "server_files/403.php"; // TODO Seuls les organisateurs concernés doivent pouvoir télécharger les fichiers } @@ -49,7 +47,7 @@ if ($data !== false) { $user = User::fromId($user_id); if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && $user_id != $_SESSION["user_id"]) - require_once "../403.php"; + require_once "server_files/403.php"; // TODO Seuls les organisateurs concernés doivent pouvoir télécharger les fichiers @@ -70,7 +68,7 @@ if ($data !== false) { } } else { - require_once "../404.php"; + require_once "server_files/404.php"; http_response_code(404); exit(); } diff --git a/server_files/views/ajouter_equipe.php b/server_files/views/ajouter_equipe.php index d63ec03..c74842b 100644 --- a/server_files/views/ajouter_equipe.php +++ b/server_files/views/ajouter_equipe.php @@ -1,4 +1,7 @@ - +

    Vous êtes déjà dans une équipe.

    Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : @@ -48,4 +51,6 @@
    - \ No newline at end of file + + + diff --git a/server_files/views/ajouter_organisateur.php b/server_files/views/ajouter_organisateur.php index f17603e..ea647eb 100644 --- a/server_files/views/ajouter_organisateur.php +++ b/server_files/views/ajouter_organisateur.php @@ -1,4 +1,6 @@ Erreur : " . $error_message . ""; @@ -51,3 +53,5 @@ if (isset($error_message)) { + + diff --git a/server_files/views/ajouter_tournoi.php b/server_files/views/ajouter_tournoi.php index cc8d84f..d62116a 100644 --- a/server_files/views/ajouter_tournoi.php +++ b/server_files/views/ajouter_tournoi.php @@ -1,4 +1,7 @@ -Erreur : " . $error_message . ""; } else { @@ -118,4 +121,6 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/server_files/views/connexion.php b/server_files/views/connexion.php index 647e99e..7ec97c4 100644 --- a/server_files/views/connexion.php +++ b/server_files/views/connexion.php @@ -1,6 +1,9 @@ -Erreur : " . $error_message . ""; ?> - Erreur : " . $error_message . ""; + if (isset($error_message) && $error_message === FALSE) { if (isset($_GET["mdp_oublie"])) echo "Le mail de récupération de mot de passe a bien été envoyé."; @@ -89,4 +92,6 @@ else if (isset($_SESSION["user_id"])) { ?> - \ No newline at end of file + + + \ No newline at end of file diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index a19b3f2..346f6f4 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -1,3 +1,5 @@ + +

    Informations sur l'équipe

    Nom de l'équipe : getName() ?>
    @@ -90,4 +92,6 @@ if (!$team->isSelectedForFinal() && isset($_SESSION["user_id"]) && $_SESSION["ro
    - \ No newline at end of file + + + \ No newline at end of file diff --git a/server_files/views/header.php b/server_files/views/header.php index 5917855..e8cabc2 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -22,7 +22,7 @@
    + + \ No newline at end of file diff --git a/server_files/views/informations.php b/server_files/views/informations.php index 4ba340a..0c7e211 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -1,3 +1,5 @@ + +

    getFirstName() . " " . $user->getSurname() ?>

    getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { ?> @@ -64,4 +66,6 @@ elseif ($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCAD } echo "$name de $first_name $surname : Télécharger
    "; } -} \ No newline at end of file +} + +require_once "footer.php"; \ No newline at end of file diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index 4ecff3c..1f34347 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -1,4 +1,9 @@ -Erreur : " . $error_message . ""; ?> +Erreur : " . $error_message . ""; +?> - \ No newline at end of file + + + \ No newline at end of file diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index dffbbe3..615f70c 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -1,4 +1,9 @@ -Erreur : " . $error_message . ""; ?> +Erreur : " . $error_message . ""; +?> - \ No newline at end of file + + + \ No newline at end of file diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index 71e7a65..150c77d 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -1,10 +1,14 @@ -Erreur : " . $error_message . ""; } else { echo "

    Le fichier a été correctement envoyé !

    "; } -} ?> +} +?>

    Informations sur l'équipe

    @@ -164,3 +168,5 @@ Code d'accès : getAccessCode() ?>
    + + \ No newline at end of file diff --git a/server_files/views/rejoindre_equipe.php b/server_files/views/rejoindre_equipe.php index b99154a..ce75669 100644 --- a/server_files/views/rejoindre_equipe.php +++ b/server_files/views/rejoindre_equipe.php @@ -1,4 +1,7 @@ - + Vous avez bien rejoint l'équipe getName() ?> ! @@ -25,4 +28,6 @@ - \ No newline at end of file + + + \ No newline at end of file diff --git a/server_files/views/solutions.php b/server_files/views/solutions.php index 6c1a36f..a44fcc3 100644 --- a/server_files/views/solutions.php +++ b/server_files/views/solutions.php @@ -1,4 +1,7 @@ -Erreur : " . $error_message . ""; } else { @@ -6,7 +9,7 @@ } }?> - +getSolutionsDate()) { ?>
    @@ -54,5 +57,6 @@ while (($data = $solutions_req->fetch()) !== false) { $version = $data["version"]; echo "Problème $problem (Version $version) : Télécharger
    "; } -?> + +require_once "footer.php"; diff --git a/server_files/views/syntheses.php b/server_files/views/syntheses.php index e05ed0b..e1daaf9 100644 --- a/server_files/views/syntheses.php +++ b/server_files/views/syntheses.php @@ -1,7 +1,9 @@ getSolutionsDate()) { echo "

    Il est trop tôt pour se préoccuper des notes de synthèse, attendez le tirage des poules.

    "; - require_once "../views/footer.php"; + require_once "server_files/views/footer.php"; } if (isset($error_message)) { @@ -13,7 +15,7 @@ if (isset($error_message)) { } }?> - +getSynthesesDate()) { ?>
    @@ -58,4 +60,5 @@ while (($data = $syntheses_req->fetch()) !== false) { $version = $data["version"]; echo "Note de synthèse pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . " (Version $version) : Télécharger
    "; } -?> \ No newline at end of file + +require_once "footer.php"; \ No newline at end of file diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 39c6426..ea99aea 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -1,3 +1,5 @@ + +

    Tournoi de getName() ?>

    Organisateur= 2 ? 's' : '' ?> : @@ -224,3 +226,5 @@ else { + + diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index b145b75..0acdcb7 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -1,3 +1,5 @@ + +

    Liste des tournois

    @@ -41,4 +43,6 @@ -
    Places disponibles
    \ No newline at end of file + + + From cb760cb0593736ef91359de0220abfd251b3fe60 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 13:46:36 +0200 Subject: [PATCH 038/120] =?UTF-8?q?Utilisation=20d'un=20dispatcher=20pour?= =?UTF-8?q?=20g=C3=A9rer=20les=20redirections?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/ajouter_equipe.php | 127 ---------- server_files/ajouter_organisateur.php | 124 ---------- server_files/ajouter_tournoi.php | 217 ----------------- server_files/confirmer_mail.php | 26 --- server_files/connexion.php | 76 ------ server_files/deconnexion.php | 14 -- server_files/equipe.php | 64 ----- server_files/footer.php | 5 - server_files/header.php | 143 ------------ server_files/index.php | 114 --------- server_files/inscription.php | 278 ---------------------- server_files/mon_compte.php | 323 -------------------------- server_files/mon_equipe.php | 200 ---------------- server_files/rejoindre_equipe.php | 93 -------- server_files/solutions.php | 115 --------- server_files/solutions_orga.php | 29 --- server_files/syntheses.php | 109 --------- server_files/syntheses_orga.php | 30 --- server_files/tournoi.php | 107 --------- server_files/tournois.php | 50 ---- server_files/view_file.php | 67 ------ 21 files changed, 2311 deletions(-) delete mode 100644 server_files/ajouter_equipe.php delete mode 100644 server_files/ajouter_organisateur.php delete mode 100644 server_files/ajouter_tournoi.php delete mode 100644 server_files/confirmer_mail.php delete mode 100644 server_files/connexion.php delete mode 100644 server_files/deconnexion.php delete mode 100644 server_files/equipe.php delete mode 100644 server_files/footer.php delete mode 100644 server_files/header.php delete mode 100644 server_files/index.php delete mode 100644 server_files/inscription.php delete mode 100644 server_files/mon_compte.php delete mode 100644 server_files/mon_equipe.php delete mode 100644 server_files/rejoindre_equipe.php delete mode 100644 server_files/solutions.php delete mode 100644 server_files/solutions_orga.php delete mode 100644 server_files/syntheses.php delete mode 100644 server_files/syntheses_orga.php delete mode 100644 server_files/tournoi.php delete mode 100644 server_files/tournois.php delete mode 100644 server_files/view_file.php diff --git a/server_files/ajouter_equipe.php b/server_files/ajouter_equipe.php deleted file mode 100644 index 9dd42ae..0000000 --- a/server_files/ajouter_equipe.php +++ /dev/null @@ -1,127 +0,0 @@ -query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); - -if (isset($_POST["submitted"])) { - $error_message = registerTournament(); -} - -function registerTournament() { - global $DB, $YEAR, $MAIL_ADDRESS, $access_code; - - if ($_SESSION["team_id"] != NULL) - return "Vous êtes déjà dans une équipe."; - - $name = htmlspecialchars($_POST["name"]); - - if (!isset($name) || $name == "") - return "Vous devez spécifier un nom d'équipe."; - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Une équipe existe déjà avec ce nom."; - - $trigram = htmlspecialchars($_POST["trigram"]); - - if (!preg_match("#[A-Z][A-Z][A-Z]#", $trigram)) - return "Le trigramme entré n'est pas valide."; - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Une équipe a déjà choisi ce trigramme."; - - $tournament_id = intval(htmlspecialchars($_POST["tournament"])); - - $result = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `id` = '" . $tournament_id . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) - return "Le tournoi spécifié n'existe pas."; - - $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; - $access_code = ""; - for ($i = 0; $i < 6; ++$i) - $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; - - $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?);"); - $result = $req->execute([$name, $trigram, $_SESSION["role"] == "ENCADRANT" ? $_SESSION["user_id"] : NULL, - $_SESSION["role"] == "PARTICIPANT" ? $_SESSION["user_id"] : NULL, "NOT_READY", $access_code, $YEAR]); - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - $data_team = $result->fetch(); - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data_team["id"]]); - - $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; - $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $data["name"] . " et nous vous en remercions. "; - $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; - $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; - mail($_SESSION["email"], "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; -} - -?> - - - - -

    Vous devez être participant ou encadrant pour pouvoir ajouter une équipe.

    - -

    Vous êtes déjà dans une équipe.

    - - Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : - - -Erreur : " . $error_message . ""; ?> - -
    - - - - - - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - - - -
    - -
    -
    - - - - diff --git a/server_files/ajouter_organisateur.php b/server_files/ajouter_organisateur.php deleted file mode 100644 index 1146426..0000000 --- a/server_files/ajouter_organisateur.php +++ /dev/null @@ -1,124 +0,0 @@ -prepare("SELECT `id` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); - $req->execute([$email]); - if ($req->fetch() !== FALSE) - return "Cette adresse e-mail est déjà utilisée."; - - $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - $password = ""; - for ($i = 0; $i < 16; ++$i) - $password .= $alphabet[rand(0, strlen($alphabet) - 1)]; - $hash = password_hash($password, PASSWORD_BCRYPT); - - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) - VALUES (?, ?, ?, ?, ?, ?);"); - $req->execute([$email, $hash, $surname, $first_name, $admin ? "ADMIN" : "ORGANIZER", $YEAR]); - - $msg = "Bonjour " . $first_name . " " . $surname . ",\r\n\r\n" - . "Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM². " - . "Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. " - . "Elles vous permettront de gérer les inscriptions des équipes de votre tournoi.\r\n\r\n" - . "Votre mot de passe est : $password\r\n\r\n" - . "Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer " - . "lors de votre prochaine connexion sur le site.\r\n\r\n" - . "Merci beaucoup pour votre aide !\r\n\r\n" - . "Les organisateurs du TFJM²"; - - mail($email, "Organisateur du TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; -} - -?> - - - - -

    Vous n'êtes pas autorisé à accéder à cette page.

    - - - Erreur : " . $error_message . ""; - } else { - echo "

    Organisateur ajouté avec succès ! Ses identifiants ont été transmis par mail.

    "; - } - }?> - -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - - - -
    - - - -
    - -
    -
    - - - - diff --git a/server_files/ajouter_tournoi.php b/server_files/ajouter_tournoi.php deleted file mode 100644 index 434897f..0000000 --- a/server_files/ajouter_tournoi.php +++ /dev/null @@ -1,217 +0,0 @@ -query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); - -if (isset($_POST["submitted"])) { - $error_message = registerTournament(); -} - -function registerTournament() { - global $DB, $YEAR, $MAIL_ADDRESS; - - $name = htmlspecialchars($_POST["name"]); - - $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Un tournoi existe déjà avec ce nom."; - - try { - $organizer_id = intval(htmlspecialchars($_POST["organizer"])); - } - catch (Exception $ex) { - return "Un problème a eu lieu concernant le choix de l'organisateur. Merci de ne pas formuler vous-même vos requêtes."; - } - - $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $organizer_id . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) - return "L'organisateur spécifié n'existe pas."; - if ($data["role"] != "ORGANIZER" && $data["role"] != "ADMIN") - return "L'organisateur indiqué ne peut pas organiser de tournoi."; - $organize_mail = $data["email"]; - - try { - $size = intval(htmlspecialchars($_POST["size"])); - } - catch (Exception $ex) { - return "Le nombre d'équipes indiqué n'est pas un entier valide."; - } - - if ($size < 3 || $size > 12) - return "Un tournoi doit comporter entre 3 et 12 équipes."; - - $place = htmlspecialchars($_POST["place"]); - - try { - $price = intval(htmlspecialchars($_POST["price"])); - } - catch (Throwable $t) { - return "Le tarif pour les participants n'est pas un nombre valide."; - } - - if ($price < 0) - return "Le TFJM² ne va pas payer les élèves pour venir."; - - if ($price > 50) - return "Soyons raisonnable sur le prix."; - - $date_start = htmlspecialchars($_POST["date_start"]); - $date_start_parsed = date_parse_from_format("yyyy-mm-dd", $date_start); - - $date_end = htmlspecialchars($_POST["date_end"]); - $date_end_parsed = date_parse_from_format("yyyy-mm-dd", $date_end); - - $date_inscription = htmlspecialchars($_POST["date_inscription"]); - $time_inscription = htmlspecialchars($_POST["time_inscription"]); - $date_inscription_parsed = date_parse_from_format("yyyy-mm-dd", $date_inscription . ' ' . $time_inscription); - - $date_solutions = htmlspecialchars($_POST["date_solutions"]); - $time_solutions = htmlspecialchars($_POST["time_solutions"]); - $date_solutions_parsed = date_parse_from_format("yyyy-mm-dd", $date_solutions . ' ' . $time_solutions); - - $date_syntheses = htmlspecialchars($_POST["date_syntheses"]); - $time_syntheses = htmlspecialchars($_POST["time_syntheses"]); - $date_syntheses_parsed = date_parse_from_format("yyyy-mm-dd", $date_syntheses . ' ' . $time_syntheses); - - if (!$date_start_parsed || !$date_end_parsed || !$date_inscription_parsed || !$date_solutions_parsed || !$date_syntheses_parsed) - return "Une date est mal formée."; - - $description = htmlspecialchars($_POST["description"]); - - $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `organizer`, `size`, `place`, `description`, - `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $result = $req->execute([$name, $organizer_id, $size, $place, $description, $date_start, $date_end, - "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $YEAR]); - - mail($organize_mail, "Organisateur TFJM² " . $name, "Vous venez d'être promu organisateur du tournoi " . $name . " pour le TFJM² $YEAR !", "From: $MAIL_ADDRESS"); - - return false; -} - -?> - - - - -

    Vous n'êtes pas autorisé à accéder à cette page.

    - - -Erreur : " . $error_message . ""; - } else { - echo "

    Tournoi de " . htmlspecialchars($_POST["name"]) . " ajouté avec succès !

    "; - } - }?> - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - - - -
    - - - -
    - - - -
    - - - Du au -
    - - - - -
    - - - - -
    - - - - -
    - - - -
    - -
    -
    - - - - diff --git a/server_files/confirmer_mail.php b/server_files/confirmer_mail.php deleted file mode 100644 index 951d5b4..0000000 --- a/server_files/confirmer_mail.php +++ /dev/null @@ -1,26 +0,0 @@ -query("SELECT `email` FROM `users` WHERE `confirm_email` = '$token' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - $error_message = "Le jeton est invalide. Votre compte est peut-être déjà validé ?"; - else { - $DB->exec("UPDATE `users` SET `confirm_email` = NULL WHERE `confirm_email` = '$token';"); - $error_message = "Votre adresse mail a été validée ! Vous pouvez désormais vous connecter."; - } -} -else { - $error_message = "Il n'y a pas de compte à valider !"; -} - -?> - - - -

    - - \ No newline at end of file diff --git a/server_files/connexion.php b/server_files/connexion.php deleted file mode 100644 index e6bcefc..0000000 --- a/server_files/connexion.php +++ /dev/null @@ -1,76 +0,0 @@ -query("SELECT `id`, `pwd_hash`, `email`, `surname`, `first_name`, `role`, `team_id` FROM `users` WHERE `email` = '" . $email . "';"); - if (($data = $result->fetch()) === FALSE) - return "Le compte n'existe pas."; - - if (!password_verify($password, $data["pwd_hash"])) - return "Le mot de passe est incorrect."; - - $_SESSION["user_id"] = $data["id"]; - $_SESSION["email"] = $data["email"]; - $_SESSION["surname"] = $data["surname"]; - $_SESSION["first_name"] = $data["first_name"]; - $_SESSION["role"] = $data["role"]; - $_SESSION["team_id"] = $data["team_id"]; - - $response = $DB->query("SELECT `tournament`, `validation_status` FROM `teams` WHERE `id` ='" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); - $data = $response->fetch(); - $_SESSION["tournament_id"] = $data["tournament"]; - $_SESSION["team_validation_status"] = $data["validation_status"]; - - return false; -} - -?> - - - -Erreur : " . $error_message . ""; ?> - - - Connexion réussie ! - - -

    Vous êtes déjà connecté !

    - - - -
    - - - - - - - - - - - - - -
    -
    - - - - diff --git a/server_files/deconnexion.php b/server_files/deconnexion.php deleted file mode 100644 index 31b50ac..0000000 --- a/server_files/deconnexion.php +++ /dev/null @@ -1,14 +0,0 @@ - - - - -

    Déconnexion réussie !

    - - diff --git a/server_files/equipe.php b/server_files/equipe.php deleted file mode 100644 index 4298a5f..0000000 --- a/server_files/equipe.php +++ /dev/null @@ -1,64 +0,0 @@ -query("SELECT * FROM `teams` WHERE `trigram` = '$trigram';")->fetch(); - -$tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); - -$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? GROUP BY `type` ORDER BY `user`, `type` ASC, `uploaded_at` DESC;"); -$documents_req->execute([$team_data["id"]]); - -?> - - - -

    Informations sur l'équipe

    - -Nom de l'équipe :
    -Trigramme :
    -Tournoi :
    -query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; -} -for ($i = 1; $i <= 6; ++$i) { - if ($team_data["participant_" . $i] == NULL) - continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; -} -?> - -

    Autorisations

    - -fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $user_id = $data["user"]; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); - $surname = $user_data["surname"]; - $first_name = $user_data["first_name"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name de $first_name $surname : Télécharger
    "; -} -?> - - diff --git a/server_files/footer.php b/server_files/footer.php deleted file mode 100644 index 0289fab..0000000 --- a/server_files/footer.php +++ /dev/null @@ -1,5 +0,0 @@ -
    -
    -
    - - \ No newline at end of file diff --git a/server_files/header.php b/server_files/header.php deleted file mode 100644 index 48a0933..0000000 --- a/server_files/header.php +++ /dev/null @@ -1,143 +0,0 @@ -exec("UPDATE `users` SET `role` = 'ADMIN' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_SESSION["user_id"]) && isset($_GET["be-organizer"])) { - $DB->exec("UPDATE `users` SET `role` = 'ORGANIZER' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_SESSION["user_id"]) && isset($_GET["be-participant"])) { - $DB->exec("UPDATE `users` SET `role` = 'PARTICIPANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_SESSION["user_id"]) && isset($_GET["be-encadrant"])) { - $DB->exec("UPDATE `users` SET `role` = 'ENCADRANT' WHERE `id` = '" . $_SESSION["user_id"] . "';"); - quitTeam(); - header("Location: $URL_BASE"); - exit(); -} - -function quitTeam() { - global $DB, $URL_BASE; - - if ($_SESSION["role"] == "ADMIN" || $_SESSION["role"] == "ORGANIZER") - return; - - for ($i = 1; $i <= ($_SESSION["role"] == "PARTICIPANT" ? 6 : 2); ++$i) - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); - for ($i = 1; $i <= 5; ++$i) { - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); - } - - $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - - if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { - $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); - - $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); - } - unset($_SESSION["team_id"]); - unset($_SESSION["team_validation_status"]); -} - -?> - - - - - - - Site d'inscription pour le TFJM² <?= $YEAR ?> - - - - - - - - - - - - - - - - - - -
    -
    - -
    \ No newline at end of file diff --git a/server_files/index.php b/server_files/index.php deleted file mode 100644 index 39fe89d..0000000 --- a/server_files/index.php +++ /dev/null @@ -1,114 +0,0 @@ - - - - -
    - - - - - -
    - - -
    - - -

    Vous souhaitez participer au tournoi ? Votre équipe est déjà formée ?

    -

    Créez un compte pour commencer la procédure d'inscription ou connectez-vous si votre équipe a déjà un compte.

    -
    - -
    - -
    -

    Bienvenue sur le site d'inscription du TFJM2 !

    -
    - -
    - Ce site a été conçu pour gérer les inscriptions au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens. -
    - Cliquez ici pour accéder au site de présentation du tournoi. -
    - -
    - - -

    - Attention aux échéances ! Chaque tournoi a une date limite pour les inscriptions et une date limite pour déposer vos solutions. Elles sont affichées avec les informations de chaque tournoi. Merci de vous y référer ! -
    - Une fois l'échéance passée, le site bloque tout accès aux inscriptions (et respectivement au dépôt des solutions).
    -

    - -

    - Attention, modification du règlement par rapport aux années précédentes : article 4.3 -
    - "l’équipe doit envoyer par mail à contact@tfjm.org, une lettre (au format pdf), répondant aux questions suivantes : -
    - -

      -
    • Comment l’équipe s’est-elle formée ?
    • -
    • Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres avec l’encadrant•e) ?
    • -
    - - Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non l’inscription des équipes concernées par cette lettre." -
    - - Pour plus de détail, voir le règlement : https://tfjm.org/infos-tournois/ -

    - - -
    -

    Comment ça marche ?

    -
    - -

    - Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer par la suite. -

    - -

    - Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : -

      -
    • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
    • -
    • enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière version enregistrée avant - la date limite sera prise en compte pour le tournoi).
    • -
    - - Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, votre inscription pourra être validée par les organisateurs locaux. -

    - - -

    ATTENTION ! Votre équipe ne sera considérée comme admissible à participer au tournoi que lorsque cette première étape aura été franchie.

    - -

    Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes seront placées en liste d'attente. -

    - -

    - Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers le site pour compléter votre inscription. -

    - - -

    ATTENTION ! Les équipes qui ne respecteront pas les délais pour rendre ces documents risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente.

    - -

    - NB : Ce site est récent et il est encore possible que certaines pages ne fonctionnent pas correctement. Si vous remarquez des bugs, merci de les signaler à l'adresse contact@tfjm.org. -

    - - - - - - - - - -
    - - \ No newline at end of file diff --git a/server_files/inscription.php b/server_files/inscription.php deleted file mode 100644 index a2e85b4..0000000 --- a/server_files/inscription.php +++ /dev/null @@ -1,278 +0,0 @@ -query("SELECT `email` FROM `users` WHERE `email` = '" . $email . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Un compte existe déjà avec cette adresse e-mail."; - - $password = htmlspecialchars($_POST["password"]); - if (strlen($password) < 8) - return "Le mot de passe doit comporter au moins 8 caractères."; - if ($password != $_POST["confirm_password"]) - return "Les deux mots de passe sont différents."; - - $password = password_hash($password, PASSWORD_BCRYPT); - - $surname = strtoupper(htmlspecialchars($_POST["surname"])); - if (!isset($surname) || $surname == "") - return "Le nom de famille est obligatoire."; - - $firstname = htmlspecialchars($_POST["firstname"]); - if (!isset($surname) || $surname == "") - return "Le prénom est obligatoire."; - - $birth_date = date_parse_from_format("yyyy-mm-dd", htmlspecialchars($_POST["birth_date"])); - - if ($birth_date === FALSE) - return "La date de naissance est invalide."; - - if (htmlspecialchars($_POST["birth_date"]) >= $YEAR . "-01-01") - return "Vous devez avoir un âge strictement positif. Date de naissance rentrée : " . htmlspecialchars($_POST["birth_date"]); - - $gender = htmlspecialchars($_POST["gender"]); - - if (!isset($gender) || ($gender != "M" && $gender != "F")) - return "Le sexe indiqué est invalide."; - - $address = htmlspecialchars($_POST["address"]); - - if (!isset($address)) - $address = ""; - - try { - $postal_code = intval($_POST["postal_code"]); - if ($postal_code < 1000 || $postal_code > 95999) - return "Le code postal est invalide."; - } - catch (Exception $ex) { - return "Le code postal n'est pas un nombre valide."; - } - - $city = htmlspecialchars($_POST["city"]); - - if (!isset($city)) - $city = ""; - - $country = htmlspecialchars($_POST["country"]); - - if (!isset($country)) - $country = "France"; - - $phone_number = htmlspecialchars($_POST["phone_number"]); - - if (!isset($phone_number) || $phone_number == "") - return "Vous devez renseigner un numéro de téléphone."; - - $role = htmlspecialchars($_POST["role"]); - - if (!isset($role) || ($role != "participant" && $role != "encadrant")) - return "Le rôle entré n'est pas valide."; - - $role = strtoupper($role); - - $school = htmlspecialchars($_POST["school"]); - $class = strtoupper(htmlspecialchars($_POST["class"])); - $responsible_name = htmlspecialchars($_POST["responsible_name"]); - $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); - $responsible_email = htmlspecialchars($_POST["responsible_email"]); - - if ($role == "ENCADRANT") { - $school = NULL; - $class = NULL; - $responsible_name = NULL; - $responsible_phone = NULL; - $responsible_email = NULL; - } - else { - if (!isset($class) && $class != "TERMINALE" && $class != "PREMIERE" && $class != "SECONDE") - return "La classe spécifiée est invalide. Merci de ne pas créer vos propres requêtes."; - - if ((!isset($responsible_name) || $responsible_name == "") && $birth_date > strval($YEAR - 18) . "-05-01") - return "Veuillez spécifier un nom de responsable légal."; - - if ((!isset($responsible_phone) || $responsible_phone == "") && (!isset($responsible_email) || !filter_var($responsible_email, FILTER_VALIDATE_EMAIL)) - && $birth_date > strval($YEAR - 18) . "-05-01") - return "Veuillez préciser au moins le numéro de téléphone ou l'addresse e-mail de votre responsable légal."; - } - - $description = $_POST["description"]; - - if ($role == "PARTICIPANT") - $description = NULL; - - $confirm_email_uid = uniqid(); - - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, - `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$email, $password, $confirm_email_uid, $surname, $firstname, $_POST["birth_date"], $gender, $address, $postal_code, - $city, $country, $phone_number, $school, $class, $role, $description, $YEAR]); - - $msg = "Merci pour votre inscription au TFJM² $YEAR ! Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; - mail($email, "Inscription au TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; -} - -?> - - - - Erreur : " . $error_message . ""; ?> - - - Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. - - -

    Vous êtes déjà connecté !

    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    " />
    -
    " />
    -
    - - - - - - diff --git a/server_files/mon_compte.php b/server_files/mon_compte.php deleted file mode 100644 index d4dba41..0000000 --- a/server_files/mon_compte.php +++ /dev/null @@ -1,323 +0,0 @@ -query("SELECT * FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "';"); - $user_data = $result->fetch(); -} - -function updateAccount() -{ - global $DB, $URL_BASE, $MAIL_ADDRESS; - - if (!isset($_SESSION["user_id"])) - return "Vous n'êtes pas connecté."; - - $ID = $_SESSION["user_id"]; - - $surname = htmlspecialchars($_POST["surname"]); - if (isset($surname) && $surname != "") - $DB->prepare("UPDATE `users` SET `surname` = ? WHERE `id` = ?;")->execute([$surname, $ID]); - - $first_name = htmlspecialchars($_POST["firstname"]); - if (isset($first_name) && $first_name != "") - $DB->prepare("UPDATE `users` SET `first_name` = ? WHERE `id` = ?;")->execute([$first_name, $ID]); - - $birth_date = htmlspecialchars($_POST["birth_date"]); - if (isset($birth_date) && $birth_date != "") - $DB->prepare("UPDATE `users` SET `birth_date` = ? WHERE `id` = ?;")->execute([$birth_date, $ID]); - - if (isset($_POST["gender"])) { - $gender = htmlspecialchars($_POST["gender"]); - if (isset($gender) && ($gender == "M" || $gender == "F")) - $DB->prepare("UPDATE `users` SET `gender` = ? WHERE `id` = ?;")->execute([$gender, $ID]); - } - - $address = htmlspecialchars($_POST["address"]); - if (isset($address) && $address != "") - $DB->prepare("UPDATE `users` SET `address` = ? WHERE `id` = ?;")->execute([$address, $ID]); - - $postal_code = htmlspecialchars($_POST["postal_code"]); - if (isset($postal_code) && $postal_code != "") - $DB->prepare("UPDATE `users` SET `postal_code` = ? WHERE `id` = ?;")->execute([$postal_code, $ID]); - - $city = htmlspecialchars($_POST["city"]); - if (isset($city) && $city != "") - $DB->prepare("UPDATE `users` SET `city` = ? WHERE `id` = ?;")->execute([$city, $ID]); - - $country = htmlspecialchars($_POST["country"]); - if (isset($country) && $country != "") - $DB->prepare("UPDATE `users` SET `country` = ? WHERE `id` = ?;")->execute([$country, $ID]); - - $phone_number = htmlspecialchars($_POST["phone_number"]); - if (isset($phone_number) && $phone_number != "") - $DB->prepare("UPDATE `users` SET `phone_number` = ? WHERE `id` = ?;")->execute([$phone_number, $ID]); - - if (isset($_POST["school"])) { - $school = htmlspecialchars($_POST["school"]); - if (isset($school) && $school != "") - $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $ID]); - } - - if (isset($_POST["class"])) { - $class = htmlspecialchars($_POST["class"]); - if (isset($class) && ($class == "terminale" || $class == "premiere" || $class == "seconde")) - $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([strtoupper($class), $ID]); - } - - if (isset($_POST["responsible_name"])) { - $responsible_name = htmlspecialchars($_POST["responsible_name"]); - if (isset($responsible_name) && $responsible_name != "") - $DB->prepare("UPDATE `users` SET `responsible_name` = ? WHERE `id` = ?;")->execute([$responsible_name, $ID]); - } - - if (isset($_POST["responsible_phone"])) { - $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); - if (isset($responsible_phone) && $responsible_phone != "") - $DB->prepare("UPDATE `users` SET `responsible_phone` = ? WHERE `id` = ?;")->execute([$responsible_phone, $ID]); - } - - if (isset($_POST["responsible_email"])) { - $responsible_email = htmlspecialchars($_POST["responsible_email"]); - if (isset($responsible_email) && $responsible_email != "") - $DB->prepare("UPDATE `users` SET `responsible_email` = ? WHERE `id` = ?;")->execute([$responsible_email, $ID]); - } - - if (isset($_POST["description"])) { - $description = htmlspecialchars($_POST["description"]); - if (isset($description) && $description != "") - $DB->prepare("UPDATE `users` SET `description` = ? WHERE `id` = ?;")->execute([$description, $ID]); - } - - $email = htmlspecialchars($_POST["email"]); - if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { - $confirm_email_uid = uniqid(); - $DB->prepare("UPDATE `users` SET `email` = ?, `confirm_email` = ? WHERE `id` = ?;")->execute([$email, $confirm_email_uid, $ID]); - - $msg = "Vous venez de changer votre adresse mail. Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; - mail($email, "Changement d'adresse mail - TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); - } - - return false; -} - -function updatePassword() -{ - global $DB, $YEAR; - - $old = htmlspecialchars($_POST["old_password"]); - $new = htmlspecialchars($_POST["new_password"]); - $confirm = htmlspecialchars($_POST["confirm_password"]); - - $result = $DB->query("SELECT `pwd_hash` FROM `users` WHERE `id` = '" . $_SESSION["user_id"] . "' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - return "Le compte n'existe pas."; - - if (!password_verify($old, $data["pwd_hash"])) - return "L'ancien mot de passe est incorrect."; - - if (strlen($new) < 8) - return "Le mot de passe doit comporter au moins 8 caractères."; - - if ($new != $confirm) - return "Les deux mots de passe sont différents."; - - $hash = password_hash($new, PASSWORD_BCRYPT); - - $DB->prepare("UPDATE `users` SET `pwd_hash` = ? WHERE `id` = ?;")->execute([$hash, $_SESSION["user_id"]]); - - return false; -} - -?> - - - -Vous devez être connecté pour afficher cette page."; - include "footer.php"; - return; -} ?> - -Erreur : " . $error_message . ""; ?> - - -

    Votre compte a bien été mis à jour !

    - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    /> - />
    - - - -
    - -
    - - - -
    - -
    - - - -
    - -
    -
    - -
    - -
    - - - - - - - - - - - - - - - - - -
    -
    - - diff --git a/server_files/mon_equipe.php b/server_files/mon_equipe.php deleted file mode 100644 index c29fd22..0000000 --- a/server_files/mon_equipe.php +++ /dev/null @@ -1,200 +0,0 @@ -exec("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_$i` = NULL WHERE `" . strtolower($_SESSION["role"]) . "_$i` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `users` SET `team_id` = NULL WHERE `id` = " . $_SESSION["user_id"] . ";"); - $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); - for ($i = 1; $i <= 5; ++$i) { - /** @noinspection SqlResolve */ - $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); - } - - $req = $DB->query("SELECT `file_id` FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `documents` WHERE `user` = '" . $_SESSION["user_id"] . "';"); - - if ($DB->exec("DELETE FROM `teams` WHERE `encadrant_1` IS NULL AND `participant_1` IS NULL;") > 0) { - $req = $DB->query("SELECT `file_id` FROM `solutions` WHERE `team` = '" . $_SESSION["team_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `solutions` WHERE `team` = " . $_SESSION["team_id"] . ";"); - - $req = $DB->query("SELECT `file_id` FROM `syntheses` WHERE `team` = '" . $_SESSION["team_id"] . "';"); - while (($data = $req->fetch()) !== false) - unlink("$URL_BASE/files/" . $data["file_id"]); - $DB->exec("DELETE FROM `syntheses` WHERE `team` = " . $_SESSION["team_id"] . ";"); - } - unset($_SESSION["team_id"]); - unset($_SESSION["team_validation_status"]); - header("Location: $URL_BASE"); - exit(); -} - -if (isset($_POST["send_document"])) { - sendDocument(); -} - -if (isset($_POST["request_validation"])) { - $DB->exec("UPDATE `teams` SET `validation_status` = 'WAITING' WHERE `id` = " . $_SESSION["team_id"] . ";"); - $_SESSION["team_validation_status"] = "WAITING"; -} - -if (isset($_SESSION["user_id"]) && isset($_SESSION["team_id"])) { - $result = $DB->query("SELECT * FROM `teams` WHERE `id` = '" . $_SESSION["team_id"] . "' AND `year` = '$YEAR';"); - $team_data = $result->fetch(); - - $tournament_data = $DB->query("SELECT `name`, `date_start` FROM `tournaments` WHERE `id` = '" . $team_data["tournament"] . "' AND `year` = '$YEAR';")->fetch(); - - $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? GROUP BY `type` ORDER BY `type` ASC, `uploaded_at` DESC;"); - $documents_req->execute([$_SESSION["user_id"]]); -} - -function sendDocument() { - global $LOCAL_PATH, $DB; - - $type = strtoupper(htmlspecialchars($_POST["type"])); - if (!isset($type) || ($type != "PARENTAL_CONSENT" && $type != "PHOTO_CONSENT" && $type != "SANITARY_PLUG")) - return "Le type de document est invalide. Merci de ne pas formuler vos propres requêtes."; - - $file = $_FILES["document"]; - - if ($file["size"] > 5000000 || $file["error"]) - return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; - - if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') - return "Le fichier doit être au format PDF."; - - if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) - return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } - while (file_exists("$LOCAL_PATH/files/$id")); - - if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) - return "Une erreur est survenue lors de l'envoi du fichier."; - - $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `tournament`, `type`) - VALUES (?, ?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION["tournament_id"], $type]); - - return false; -} - -?> - - - -Vous devez être dans une équipe pour afficher cette page."; - include "footer.php"; - return; -} ?> - -Erreur : " . $error_message . ""; - } - else { - echo "

    Le fichier a été correctement envoyé !

    "; - } -}?> - -

    Informations sur l'équipe

    - -Nom de l'équipe :
    -Trigramme :
    -Tournoi :
    -query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["encadrant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Encadrant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; -} -for ($i = 1; $i <= 6; ++$i) { - if ($team_data["participant_" . $i] == NULL) - continue; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $team_data["participant_" . $i] . " AND `year` = '$YEAR';")->fetch(); - echo "Participant $i : " . $user_data["first_name"] . " " . $user_data["surname"] . "
    "; -} -?> -Code d'accès : - - -
    -

    Mes autorisations

    - fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name : Télécharger
    "; - } - ?> - -
    - - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - -
    -
    -
    - -
    -
    - -
    - - - diff --git a/server_files/rejoindre_equipe.php b/server_files/rejoindre_equipe.php deleted file mode 100644 index 0463f5a..0000000 --- a/server_files/rejoindre_equipe.php +++ /dev/null @@ -1,93 +0,0 @@ -query("SELECT * FROM `teams` WHERE `access_code` = '" . $access_code . "' AND `year` = '$YEAR';"); - if (($data = $result->fetch()) === FALSE) - return "Ce code d'accès est invalide."; - - if ($_SESSION["role"] != "PARTICIPANT" && $_SESSION["role"] != "ENCADRANT") - return "Seuls les participants et les encadrants peuvent rejoindre une équipe."; - - if ($data["validation_status"] != "NOT_READY") - return "Cette équipe est déjà en cours de validation ou validée, vous ne pouvez pas la rejoindre."; - - for ($i = 1; $i <= $_SESSION["role"] == "PARTICIPANT" ? 6 : 2; ++$i) { - if ($data[strtolower($_SESSION["role"]) . "_" . strval($i)] == NULL) - break; - } - - if ($_SESSION["role"] == "PARTICIPANT" && $i == 7 || $_SESSION["role"] == "ENCADRANT" && $i == 3) - return "Il n'y a plus de place pour vous dans l'équipe."; - - $DB->prepare("UPDATE `users` SET `team_id` = ? WHERE `id` = " . $_SESSION["user_id"] . ";")->execute([$data["id"]]); - /** @noinspection SqlResolve */ - $DB->prepare("UPDATE `teams` SET `" . strtolower($_SESSION["role"]) . "_" . strval($i) . "` = ? WHERE `id` = " . $data["id"] . ";")->execute([$_SESSION["user_id"]]); - - $_SESSION["team_id"] = $data["id"]; - $_SESSION["team_validation_status"] = $data["validation_status"]; - - $msg = "Bonjour " . $_SESSION["first_name"] . " " . $_SESSION["surname"] . ",\r\n\r\n"; - $msg .= "Vous venez de rejoindre l'équipe « " . $data["name"] . " » (" . $data["trigram"] . ") pour le TFJM² de " . $data["name"] . " et nous vous en remercions.\r\n\r\n"; - $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; - mail($_SESSION["email"], "Équipe rejointe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; -} - -?> - - - - -

    Vous devez être participant ou encadrant pour pouvoir rejoindre une équipe.

    - - Vous avez bien rejoint l'équipe ! - -

    Vous êtes déjà dans une équipe.

    - - -Erreur : " . $error_message . ""; ?> - -
    - - - - - - - - - - - -
    - - - -
    - -
    -
    - - - - diff --git a/server_files/solutions.php b/server_files/solutions.php deleted file mode 100644 index d243f31..0000000 --- a/server_files/solutions.php +++ /dev/null @@ -1,115 +0,0 @@ -prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? GROUP BY `problem` ORDER BY `problem` ASC, `uploaded_at` DESC;"); -$solutions_req->execute([$_SESSION["team_id"]]); - -function saveSolution() { - global $LOCAL_PATH, $DB; - - try { - $problem = $_POST["problem"]; - if ($problem < 1 || $problem > 9) - return "Le numéro de problème est invalide."; - } - catch (Throwable $t) { - return "Le numéro de problème n'est pas valide. Merci de ne pas créer vos propres requêtes."; - } - - $file = $_FILES["solution"]; - - if ($file["size"] > 5000000 || $file["error"]) - return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; - - if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') - return "Le fichier doit être au format PDF."; - - if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) - return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } - while (file_exists("$LOCAL_PATH/files/$id")); - - if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) - return "Une erreur est survenue lors de l'envoi du fichier."; - - $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) - VALUES (?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $problem]); - - return false; -} - -?> - - - -Erreur : " . $error_message . ""; - } else { - echo "

    Le fichier a été correctement envoyé !

    "; - } -}?> - -
    - - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - -
    -
    - -
    - -

    Solutions soumises :

    - -fetch()) !== false) { - $file_id = $data["file_id"]; - $problem = $data["problem"]; - $version = $data["version"]; - echo "Problème $problem (Version $version) : Télécharger
    "; -} -?> - - diff --git a/server_files/solutions_orga.php b/server_files/solutions_orga.php deleted file mode 100644 index 58b67df..0000000 --- a/server_files/solutions_orga.php +++ /dev/null @@ -1,29 +0,0 @@ - - - - -query("SELECT `id`, `name` FROM `tournaments` WHERE " - . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR ORDER BY `name`;"); - -while (($data_tournament = $req->fetch()) !== false) { - echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; - $id = $data_tournament["id"]; - $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); - while (($data_file = $files_req->fetch()) !== false) { - $file_id = $data_file["file_id"]; - $problem = $data_file["problem"]; - $version = $data_file["version"]; - $team_id = $data_file["team"]; - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); - $team_name = $team_data["name"]; - $team_trigram = $team_data["trigram"]; - echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
    "; - } -} - -?> - - diff --git a/server_files/syntheses.php b/server_files/syntheses.php deleted file mode 100644 index 377825f..0000000 --- a/server_files/syntheses.php +++ /dev/null @@ -1,109 +0,0 @@ -prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? GROUP BY `dest` ORDER BY `dest` ASC, `uploaded_at` DESC;"); -$syntheses_req->execute([$_SESSION["team_id"]]); - -function saveSynthese() { - global $LOCAL_PATH, $DB; - - $dest = strtoupper(htmlspecialchars($_POST["dest"])); - - if (!isset($dest) || ($dest != "OPPOSANT" && $dest != "RAPPORTEUR")) - return "Le destinataire est invalide."; - - $file = $_FILES["synthese"]; - - if ($file["size"] > 5000000 || $file["error"]) - return "Une erreur est survenue. Merci de vérifier que le fichier pèse moins que 5 Mo."; - - if (finfo_file(finfo_open(FILEINFO_MIME_TYPE), $file["tmp_name"]) != 'application/pdf') - return "Le fichier doit être au destmat PDF."; - - if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) - return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } - while (file_exists("$LOCAL_PATH/files/$id")); - - if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) - return "Une erreur est survenue lors de l'envoi du fichier."; - - $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) - VALUES (?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $dest]); - - return false; -} - -?> - - - -Erreur : " . $error_message . ""; - } - else { - echo "

    Le fichier a été correctement envoyé !

    "; - } -}?> - -
    - - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - -
    -
    - -
    - -

    Notes de synthèse soumises :

    - -fetch()) !== false) { - $file_id = $data["file_id"]; - $dest = $data["dest"]; - $version = $data["version"]; - echo "Note de synthèse pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . " (Version $version) : Télécharger
    "; -} -?> - - diff --git a/server_files/syntheses_orga.php b/server_files/syntheses_orga.php deleted file mode 100644 index 348b6e6..0000000 --- a/server_files/syntheses_orga.php +++ /dev/null @@ -1,30 +0,0 @@ - - - - -query("SELECT `id`, `name` FROM `tournaments` WHERE " - . ($_SESSION["role"] == "ADMIN" ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR ORDER BY `name`;"); - -while (($data_tournament = $req->fetch()) !== false) { - echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; - $id = $data_tournament["id"]; - $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); - while (($data_file = $files_req->fetch()) !== false) { - $file_id = $data_file["file_id"]; - $dest = $data_file["dest"]; - $version = $data_file["version"]; - $team_id = $data_file["team"]; - $team_data = $DB->query("SELECT `name`, `trigram` FROM `teams` WHERE `id` = '$team_id' AND `year` = $YEAR;")->fetch(); - $team_name = $team_data["name"]; - $team_trigram = $team_data["trigram"]; - echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") - . ", version $version : Télécharger
    "; - } -} - -?> - - diff --git a/server_files/tournoi.php b/server_files/tournoi.php deleted file mode 100644 index b0780eb..0000000 --- a/server_files/tournoi.php +++ /dev/null @@ -1,107 +0,0 @@ -prepare("SELECT * FROM `tournaments` WHERE `name` = ? AND `year` = $YEAR;"); -$response->execute([$tournament_name]); -$data = $response->fetch(); - -$orga_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = " . $data["organizer"] . " AND `year` = $YEAR;")->fetch(); -$orga_name = $orga_data["first_name"] . " " . $orga_data["surname"]; - -$teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $data["id"] . " AND `year` = $YEAR;"); - -?> - - - -

    Tournoi de

    - - Organisateur :
    - Nombre d'équipes maximal :
    - Lieu :
    - Prix par partipant :
    - Dates : Du au
    - Clôture des inscriptions :
    - Date limite d'envoi des solutions :
    - Date limite d'envoi des notes de synthèse :
    - Description : - -

    Équipes inscrites à ce tournoi :

    - - - - - - - - - - - - fetch()) != false) { - ?> - - - - - - - - - - - - - - - - -
    - Équipe - - Trigramme - - Date d'inscription - - État de validation de l'inscription -
    - " . $team_data["name"] . ""; - else - echo $team_data["name"]; - ?> - - -
    - Équipe - - Trigramme - - Date d'inscription - - État de validation de l'inscription -
    - - \ No newline at end of file diff --git a/server_files/tournois.php b/server_files/tournois.php deleted file mode 100644 index a5b04fb..0000000 --- a/server_files/tournois.php +++ /dev/null @@ -1,50 +0,0 @@ -query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` - WHERE `year` = '$YEAR' ORDER BY `date_start`, `name`;"); - -?> - - - -

    Liste des tournois

    - - - - - - - - - - - - - fetch()) !== FALSE) { - ?> - - - - - - - - - - - - - - - - - - -
    LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    ">Du au
    LieuDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    - - \ No newline at end of file diff --git a/server_files/view_file.php b/server_files/view_file.php deleted file mode 100644 index 81c3432..0000000 --- a/server_files/view_file.php +++ /dev/null @@ -1,67 +0,0 @@ -query("SELECT * FROM `solutions` WHERE `file_id` = '$id';"); -if (($data = $req->fetch()) === false) { - $req = $DB->query("SELECT * FROM `syntheses` WHERE `file_id` = '$id';"); - $type = "SYNTHESE"; - - if (($data = $req->fetch()) === false) { - $req = $DB->query("SELECT * FROM `documents` WHERE `file_id` = '$id';"); - $type = "DOCUMENT"; - $data = $req->fetch(); - } -} -print_r($type); -if ($data !== false) { - $team_data = $DB->query("SELECT `trigram` FROM `teams` WHERE `id` = " . $data["team"] . ";")->fetch(); - $tournament_data = $DB->query("SELECT `name` FROM `tournaments` WHERE `id` = " . $data["tournament"] . ";")->fetch(); - $trigram = $team_data["trigram"]; - if ($type == "SOLUTION") { - $problem = $data["problem"]; - $name = "Problème $problem $trigram.pdf"; - } - else if ($type == "SYNTHESE") { - $dest = $data["dest"]; - $name = "Note de synthèse $trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"; - } - else if ($type == "DOCUMENT") { - $user_id = $data["user"]; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = 'user';")->fetch(); - $surname = $user_data["surname"]; - $first_name = $user_data["first_name"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - $name .= " de $first_name $surname.pdf"; - } -} -else { - include_once "404.php"; - http_response_code(404); - exit(); -} - -header("Content-Type: application/pdf"); -header("Content-Disposition: inline; filename=\"$name\""); - -readfile("$URL_BASE/files/$id"); - -exit(); \ No newline at end of file From 25a31b7f40ae565fa2e148c2be0837b93c5622fd Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 14:31:28 +0200 Subject: [PATCH 039/120] =?UTF-8?q?Le=20tournoi=20de=20la=20finale=20natio?= =?UTF-8?q?nale=20est=20d=C3=A9sormais=20une=20variable=20globale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/equipe.php | 10 +++++----- server_files/controllers/mon_equipe.php | 2 +- server_files/controllers/solutions.php | 4 ++-- server_files/controllers/syntheses.php | 4 ++-- server_files/model.php | 4 ++-- server_files/views/equipe.php | 2 +- server_files/views/mon_equipe.php | 4 ++-- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 3e584e0..629b6dd 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -17,9 +17,9 @@ if (isset($_POST["validate"])) { if (isset($_POST["select"])) { $team->selectForFinal(true); $team->setValidationStatus(ValidationStatus::NOT_READY); - $_SESSION["final"] = Tournament::getFinalTournament(); - - $sols_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); + + /** @noinspection SqlAggregates */ + $sols_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem` ORDER BY `problem`, `uploaded_at` DESC;"); $sols_req->execute([$team->getId(), $team->getTournamentId()]); while (($sol_data = $sols_req->fetch()) !== false) { $old_id = $sol_data["file_id"]; @@ -57,7 +57,7 @@ if (isset($_POST["select"])) { copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team->getId(), $_SESSION["final"]->getId(), $synthese_data["dest"]]); + $req->execute([$id, $team->getId(), $FINAL->getId(), $synthese_data["dest"]]); } } @@ -66,7 +66,7 @@ $documents_req->execute([$team->getId(), $team->getId()]); if ($team->isSelectedForFinal()) { $documents_final_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` != ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); - $documents_final_req->execute([$team->getId(), $_SESSION["final"]->getId()]); + $documents_final_req->execute([$team->getId(), $FINAL->getId()]); } $tournament = Tournament::fromId($team->getTournamentId()); diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php index c03c540..5af190f 100644 --- a/server_files/controllers/mon_equipe.php +++ b/server_files/controllers/mon_equipe.php @@ -25,7 +25,7 @@ if (isset($_SESSION["user_id"]) && isset($_SESSION["team"]) && $_SESSION["team"] $tournament = Tournament::fromId($team->getTournamentId()); $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? GROUP BY `type`, `uploaded_at` ORDER BY `type`, `uploaded_at` DESC;"); - $documents_req->execute([$_SESSION["user_id"], $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $tournament->getId()]]); + $documents_req->execute([$_SESSION["user_id"], $_SESSION[$team->isSelectedForFinal() ? $FINAL->getId() : $tournament->getId()]]); } else require_once "server_files/403.php"; diff --git a/server_files/controllers/solutions.php b/server_files/controllers/solutions.php index 1e8f53c..0357130 100644 --- a/server_files/controllers/solutions.php +++ b/server_files/controllers/solutions.php @@ -11,9 +11,9 @@ if (isset($_POST["send_solution"])) { $team = $_SESSION["team"]; $solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); -$solutions_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()]]); +$solutions_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()]]); -$tournament = Tournament::fromId($team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()); +$tournament = Tournament::fromId($team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()); function saveSolution() { global $LOCAL_PATH, $DB; diff --git a/server_files/controllers/syntheses.php b/server_files/controllers/syntheses.php index 06f78b0..05886ee 100644 --- a/server_files/controllers/syntheses.php +++ b/server_files/controllers/syntheses.php @@ -11,9 +11,9 @@ if (isset($_POST["send_synthese"])) { $team = $_SESSION["team"]; $syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); -$syntheses_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()]]); +$syntheses_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()]]); -$tournament = Tournament::fromId($team->isSelectedForFinal() ? $_SESSION["final"]->getId() : $team->getTournamentId()); +$tournament = Tournament::fromId($team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()); function saveSynthese() { global $LOCAL_PATH, $DB; diff --git a/server_files/model.php b/server_files/model.php index 79390e7..717b938 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -1,8 +1,8 @@ getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
    "; } if ($team->isSelectedForFinal()) { - $final_name = $_SESSION["final"]->getName(); + $final_name = $FINAL->getName(); echo "Équipe sélectionnée pour la finale nationale."; } ?> diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index 150c77d..4ff5259 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -33,7 +33,7 @@ for ($i = 1; $i <= 6; ++$i) { ?> Code d'accès : getAccessCode() ?>
    isSelectedForFinal()) { - $final_name = $_SESSION["final"]->getName(); + $final_name = $FINAL->getName(); echo "Équipe sélectionnée pour la finale nationale.
    "; } ?> @@ -120,7 +120,7 @@ Code d'accès : getAccessCode() ?>
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    " required />
    " required />
    " required />
    " required />
    /> - />
    " />
    " min="1000" max="95999" required />
    " />
    " required />
    " />
    " />
    " />
    " />
    " />
    - +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    /> + />
    " required/>
    +
    + +
    + +
    +
    +
    - + selectRole(); + diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index 615f70c..872d46d 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -98,9 +98,9 @@ if (isset($error_message) && $error_message === FALSE) { From b8dfe1a6076cd3db3c6c7fe3ee82ac6604c9bc0e Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 15:51:16 +0200 Subject: [PATCH 041/120] Restructuration de la page d'inscription --- dispatcher.php | 3 +- server_files/classes/SchoolClass.php | 41 ++++ server_files/classes/User.php | 4 +- server_files/controllers/inscription.php | 185 ++++++-------- server_files/model.php | 5 + server_files/views/inscription.php | 294 +++++++++++++---------- server_files/views/mon_compte.php | 6 +- 7 files changed, 291 insertions(+), 247 deletions(-) create mode 100644 server_files/classes/SchoolClass.php diff --git a/dispatcher.php b/dispatcher.php index 68f1947..9ad9e69 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -2,12 +2,13 @@ require_once "server_files/config.php"; -require_once "server_files/model.php"; require_once "server_files/classes/Role.php"; +require_once "server_files/classes/SchoolClass.php"; require_once "server_files/classes/Team.php"; require_once "server_files/classes/Tournament.php"; require_once "server_files/classes/User.php"; require_once "server_files/classes/ValidationStatus.php"; +require_once "server_files/model.php"; loadUserValues(); diff --git a/server_files/classes/SchoolClass.php b/server_files/classes/SchoolClass.php new file mode 100644 index 0000000..cde1604 --- /dev/null +++ b/server_files/classes/SchoolClass.php @@ -0,0 +1,41 @@ +country = $data["country"]; $this->phone_number = $data["phone_number"]; $this->school = $data["school"]; - $this->class = $data["class"]; + $this->class = SchoolClass::fromName($data["class"]); $this->responsible_name = $data["responsible_name"]; $this->responsible_phone = $data["responsible_phone"]; $this->responsible_email = $data["responsible_email"]; @@ -250,7 +250,7 @@ class User { global $DB; $this->class = $class; - $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([$class, $this->getId()]); + $DB->prepare("UPDATE `users` SET `class` = ? WHERE `id` = ?;")->execute([SchoolClass::getName($class), $this->getId()]); } public function getResponsibleName() diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 5b39e6a..aba712f 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -1,129 +1,98 @@ makeVerifications(); + $user->register(); + } catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } } -function register() { - global $DB, $YEAR, $URL_BASE, $MAIL_ADDRESS; - global $email, $firstname, $surname, $birth_date, $gender, $address, $postal_code, $city, $country, $phone_number, $role, $school, $class, $responsible_name, $responsible_phone, $responsible_email; +class NewUser +{ + public $email = null; + public $first_name = null; + public $surname = null; + public $birth_date = null; + public $gender = null; + public $address = ""; + public $postal_code = null; + public $city = ""; + public $country = null; + public $phone_number = null; + public $role = null; + public $school = null; + public $class = null; + public $responsible_name = null; + public $responsible_phone = null; + public $responsible_email = null; + public $description = null; + public $confirm_email_token = null; + private $password = null; + private $confirm_password = null; - $email = strtolower(htmlspecialchars($_POST["email"])); + public function __construct($data) + { - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) - return "L'email entrée est invalide."; + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + } - $result = $DB->query("SELECT `email` FROM `users` WHERE `email` = '" . $email . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Un compte existe déjà avec cette adresse e-mail."; + public function makeVerifications() + { + global $DB, $YEAR; - $password = htmlspecialchars($_POST["password"]); - if (strlen($password) < 8) - return "Le mot de passe doit comporter au moins 8 caractères."; - if ($password != $_POST["confirm_password"]) - return "Les deux mots de passe sont différents."; + ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); + ensure(!$DB->query("SELECT `email` FROM `users` WHERE `email` = '" . $this->email . "' AND `year` = '$YEAR';")->fetch(), "Un compte existe déjà avec cette adresse e-mail."); + ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); + ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); + ensure($this->surname != "", "Le nom de famille est obligatoire."); + ensure($this->first_name != "", "Le prénom est obligatoire."); + ensure(date_parse_from_format("yyyy-mm-dd", $this->birth_date) !== false, "La date de naissance est invalide."); + ensure($this->birth_date < $YEAR . "-01-01", "Vous devez être né."); + ensure($this->gender == "M" || $this->gender == "F", "Le sexe indiqué est invalide."); + ensure(preg_match("#^[0-9]{4}[0-9]?$#", $this->postal_code) && intval($this->postal_code) >= 01000 && intval($this->postal_code) <= 95999, "Le code postal est invalide."); + if ($this->country == "") + $this->country = "France"; + ensure(strlen($this->phone_number) >= 10, "Le numéro de téléphone est invalide."); + $this->role = Role::fromName(strtoupper($this->role)); - $password = password_hash($password, PASSWORD_BCRYPT); + if ($this->role == Role::PARTICIPANT) { + $this->class = SchoolClass::fromName(strtoupper($this->class)); + if ($this->birth_date > strval($YEAR - 18) . "04-01") { + ensure($this->responsible_name != "", "Veuillez spécifier un responsable légal."); + ensure(strlen($this->responsible_phone) >= 10, "Veuillez rentrer le numéro de téléphone de votre responsable légal."); + ensure(filter_var($this->responsible_email, FILTER_VALIDATE_EMAIL), "Veuillez spécifier un responsable légal."); + } + } - $surname = strtoupper(htmlspecialchars($_POST["surname"])); - if (!isset($surname) || $surname == "") - return "Le nom de famille est obligatoire."; + $this->confirm_email_token = uniqid(); - $firstname = htmlspecialchars($_POST["firstname"]); - if (!isset($surname) || $surname == "") - return "Le prénom est obligatoire."; + throw new AssertionError("erreur"); + } - $birth_date = date_parse_from_format("yyyy-mm-dd", htmlspecialchars($_POST["birth_date"])); + public function register() + { + global $DB, $YEAR, $URL_BASE, $MAIL_ADDRESS; - if ($birth_date === FALSE) - return "La date de naissance est invalide."; - - if (htmlspecialchars($_POST["birth_date"]) >= $YEAR . "-01-01") - return "Vous devez avoir un âge strictement positif. Date de naissance rentrée : " . htmlspecialchars($_POST["birth_date"]); - - $gender = htmlspecialchars($_POST["gender"]); - - if (!isset($gender) || ($gender != "M" && $gender != "F")) - return "Le sexe indiqué est invalide."; - - $address = htmlspecialchars($_POST["address"]); - - if (!isset($address)) - $address = ""; - - try { - $postal_code = intval($_POST["postal_code"]); - if ($postal_code < 1000 || $postal_code > 95999) - return "Le code postal est invalide."; - } - catch (Exception $ex) { - return "Le code postal n'est pas un nombre valide."; - } - - $city = htmlspecialchars($_POST["city"]); - - if (!isset($city)) - $city = ""; - - $country = htmlspecialchars($_POST["country"]); - - if (!isset($country)) - $country = "France"; - - $phone_number = htmlspecialchars($_POST["phone_number"]); - - if (!isset($phone_number) || $phone_number == "") - return "Vous devez renseigner un numéro de téléphone."; - - $role = htmlspecialchars($_POST["role"]); - - if (!isset($role) || ($role != "participant" && $role != "encadrant")) - return "Le rôle entré n'est pas valide."; - - $role = strtoupper($role); - - $school = htmlspecialchars($_POST["school"]); - $class = strtoupper(htmlspecialchars($_POST["class"])); - $responsible_name = htmlspecialchars($_POST["responsible_name"]); - $responsible_phone = htmlspecialchars($_POST["responsible_phone"]); - $responsible_email = htmlspecialchars($_POST["responsible_email"]); - - if ($role == "ENCADRANT") { - $school = NULL; - $class = NULL; - $responsible_name = NULL; - $responsible_phone = NULL; - $responsible_email = NULL; - } - else { - if (!isset($class) && $class != "TERMINALE" && $class != "PREMIERE" && $class != "SECONDE") - return "La classe spécifiée est invalide. Merci de ne pas créer vos propres requêtes."; - - if ((!isset($responsible_name) || $responsible_name == "") && $birth_date > strval($YEAR - 18) . "-05-01") - return "Veuillez spécifier un nom de responsable légal."; - - if ((!isset($responsible_phone) || $responsible_phone == "") && (!isset($responsible_email) || !filter_var($responsible_email, FILTER_VALIDATE_EMAIL)) - && $birth_date > strval($YEAR - 18) . "-05-01") - return "Veuillez préciser au moins le numéro de téléphone ou l'addresse e-mail de votre responsable légal."; - } - - $description = $_POST["description"]; - - if ($role == "PARTICIPANT") - $description = NULL; - - $confirm_email_uid = uniqid(); - - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `year`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$email, $password, $confirm_email_uid, $surname, $firstname, $_POST["birth_date"], $gender, $address, $postal_code, - $city, $country, $phone_number, $school, $class, $role, $description, $YEAR]); + $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->confirm_email_token, $this->surname, $this->first_name, $this->birth_date, $this->gender, $this->address, + $this->postal_code, $this->city, $this->country, $this->phone_number, $this->school, SchoolClass::getName($this->class), Role::getName($this->role), $this->description, $YEAR]); - $msg = "Merci pour votre inscription au TFJM² $YEAR ! Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/$confirm_email_uid"; - mail($email, "Inscription au TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + // TODO Mieux gérer l'envoi des mails avec une classe à part - return false; + $msg = "Merci pour votre inscription au TFJM² $YEAR ! Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/" . $this->confirm_email_token; + mail($this->email, "Inscription au TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + } } require_once "server_files/views/inscription.php"; diff --git a/server_files/model.php b/server_files/model.php index 717b938..6e5eef3 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -94,4 +94,9 @@ function quitTeam() { $_SESSION["team"] = null; unset($_SESSION["team"]); +} + +function ensure($bool, $error_msg = "") { + if (!$bool) + throw new AssertionError($error_msg); } \ No newline at end of file diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index 1f34347..7abb639 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -1,149 +1,177 @@ Erreur : " . $error_message . ""; +if ($has_error) + echo "

    Erreur : " . $error_message . "

    "; ?> - Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. + Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. -

    Vous êtes déjà connecté !

    +

    Vous êtes déjà connecté !

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    " required />
    " required />
    " required />
    " required />
    /> - />
    " />
    " min="1000" max="95999" required />
    " />
    " required />
    " />
    " />
    " />
    " />
    " />
    -
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    /> + />
    " required/>
    +
    + +
    + +
    +
    +
    - + selectRole(); + diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index 615f70c..872d46d 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -98,9 +98,9 @@ if (isset($error_message) && $error_message === FALSE) { From e5e197dd38f95b34ea46e9b95759c26dbd68e696 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 16:37:00 +0200 Subject: [PATCH 042/120] =?UTF-8?q?D=C3=A9but=20de=20gestion=20des=20mails?= =?UTF-8?q?=20et=20quelques=20modifications?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatcher.php | 2 + server_files/config.php | 4 +- server_files/controllers/inscription.php | 51 +++++++++---------- server_files/model.php | 16 +++--- server_files/services/mail.php | 30 +++++++++++ .../services/mail_templates/register.html | 15 ++++++ server_files/utils.php | 17 +++++++ server_files/views/informations.php | 2 +- server_files/views/mon_compte.php | 2 +- server_files/views/tournoi.php | 10 ++-- server_files/views/tournois.php | 12 ++--- 11 files changed, 109 insertions(+), 52 deletions(-) create mode 100644 server_files/services/mail.php create mode 100644 server_files/services/mail_templates/register.html create mode 100644 server_files/utils.php diff --git a/dispatcher.php b/dispatcher.php index 9ad9e69..ec52e4e 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -8,6 +8,8 @@ require_once "server_files/classes/Team.php"; require_once "server_files/classes/Tournament.php"; require_once "server_files/classes/User.php"; require_once "server_files/classes/ValidationStatus.php"; +require_once "server_files/services/mail.php"; +require_once "server_files/utils.php"; require_once "server_files/model.php"; loadUserValues(); diff --git a/server_files/config.php b/server_files/config.php index b973cdf..a57349b 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -6,7 +6,9 @@ $YEAR = $_ENV["TFJM_YEAR"]; $URL_BASE = $_ENV["TFJM_URL_BASE"]; $LOCAL_PATH = $_ENV["TFJM_LOCAL_PATH"]; -$MAIL_ADDRESS = $_ENV["TFJM_MAIL_ADDRESS"]; +$MAIL_DOMAIN = $_ENV["TFJM_MAIL_DOMAIN"]; +// TODO Remove +$MAIL_ADDRESS = "contact@" . $MAIL_DOMAIN; /** * DB infos diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 8cb136d..417576b 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -17,26 +17,26 @@ if (isset($_POST["submitted"])) { class NewUser { - public $email = null; - public $first_name = null; - public $surname = null; - public $birth_date = null; - public $gender = null; + public $email; + public $first_name; + public $surname; + public $birth_date; + public $gender; public $address = ""; - public $postal_code = null; + public $postal_code; public $city = ""; - public $country = null; - public $phone_number = null; - public $role = null; - public $school = null; - public $class = null; - public $responsible_name = null; - public $responsible_phone = null; - public $responsible_email = null; - public $description = null; - public $confirm_email_token = null; - private $password = null; - private $confirm_password = null; + public $country; + public $phone_number; + public $role; + public $school; + public $class; + public $responsible_name; + public $responsible_phone; + public $responsible_email; + public $description; + public $confirm_email_token; + private $password; + private $confirm_password; public function __construct($data) { @@ -46,15 +46,15 @@ class NewUser public function makeVerifications() { - global $DB, $YEAR; + global $YEAR; ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); - ensure(!$DB->query("SELECT `email` FROM `users` WHERE `email` = '" . $this->email . "' AND `year` = '$YEAR';")->fetch(), "Un compte existe déjà avec cette adresse e-mail."); + ensure(userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); ensure($this->surname != "", "Le nom de famille est obligatoire."); ensure($this->first_name != "", "Le prénom est obligatoire."); - ensure(date_parse_from_format("yyyy-mm-dd", $this->birth_date) !== false, "La date de naissance est invalide."); + ensure(dateWellFormed($this->birth_date), "La date de naissance est invalide."); ensure($this->birth_date < $YEAR . "-01-01", "Vous devez être né."); ensure($this->gender == "M" || $this->gender == "F", "Le sexe indiqué est invalide."); ensure(preg_match("#^[0-9]{4}[0-9]?$#", $this->postal_code) && intval($this->postal_code) >= 01000 && intval($this->postal_code) <= 95999, "Le code postal est invalide."); @@ -73,13 +73,11 @@ class NewUser } $this->confirm_email_token = uniqid(); - - throw new AssertionError("erreur"); } public function register() { - global $DB, $YEAR, $URL_BASE, $MAIL_ADDRESS; + global $DB, $YEAR; $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `year`) @@ -87,10 +85,7 @@ class NewUser $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->confirm_email_token, $this->surname, $this->first_name, $this->birth_date, $this->gender, $this->address, $this->postal_code, $this->city, $this->country, $this->phone_number, $this->school, SchoolClass::getName($this->class), Role::getName($this->role), $this->description, $YEAR]); - // TODO Mieux gérer l'envoi des mails avec une classe à part - - $msg = "Merci pour votre inscription au TFJM² $YEAR ! Veuillez désormais confirmer votre adresse mail en cliquant ici : $URL_BASE/confirmer_mail/" . $this->confirm_email_token; - mail($this->email, "Inscription au TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); + sendRegisterMail($this); } } diff --git a/server_files/model.php b/server_files/model.php index 6e5eef3..bcb9db6 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -44,13 +44,6 @@ function loadUserValues() { } } -function echoDate($date = NULL, $with_time = false) { - if ($date == NULL) - $date = date("yyyy-mm-dd"); - - return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); -} - function quitTeam() { global $DB, $URL_BASE; @@ -96,7 +89,10 @@ function quitTeam() { unset($_SESSION["team"]); } -function ensure($bool, $error_msg = "") { - if (!$bool) - throw new AssertionError($error_msg); +function userExists($email) { + global $DB, $YEAR; + + $req = $DB->prepare("SELECT `email` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); + $req->execute([$email]); + return !$req->fetch(); } \ No newline at end of file diff --git a/server_files/services/mail.php b/server_files/services/mail.php new file mode 100644 index 0000000..48fc5d8 --- /dev/null +++ b/server_files/services/mail.php @@ -0,0 +1,30 @@ +first_name, $content); + $content = preg_replace("#{SURNAME}#", $new_user->surname, $content); + $content = preg_replace("#{TOKEN}#", $new_user->confirm_email_token, $content); + + sendMail($new_user->email, "Inscription au TFJM² $YEAR", $content); +} \ No newline at end of file diff --git a/server_files/services/mail_templates/register.html b/server_files/services/mail_templates/register.html new file mode 100644 index 0000000..42bfe87 --- /dev/null +++ b/server_files/services/mail_templates/register.html @@ -0,0 +1,15 @@ + + + + + Inscription au TFJM² {YEAR} + + +Bonjour {FIRST_NAME} {SURNAME},
    +
    +Vous venez de vous inscrire au TFJM2 {YEAR} et nous vous en remercions.
    +Pour valider votre adresse e-mail, veuillez cliquer sur le lien : {URL_BASE}/confirmer_mail/{TOKEN}
    +
    +Le comité national d'organisation du TFJM2 + + \ No newline at end of file diff --git a/server_files/utils.php b/server_files/utils.php new file mode 100644 index 0000000..12671cb --- /dev/null +++ b/server_files/utils.php @@ -0,0 +1,17 @@ +getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { ?> Équipe : getTrigram() . "\">" . $team->getName() . " (" . $team->getTrigram() . ")" ?>
    -Date de naissance : getBirthDate()) ?>
    +Date de naissance : getBirthDate()) ?>
    Sexe : getGender() == "M" ? "Masculin" : "Féminin" ?>
    Adresse : getAddress() . ", " . $user->getPostalCode() . " " . $user->getCity() . ($user->getCountry() == "France" ? "" : ", " . $user->getCountry()) ?>
    Adresse e-mail : getEmail() ?>
    diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index 872d46d..c96e1be 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -42,7 +42,7 @@ if (isset($error_message) && $error_message === FALSE) { - getBirthDate()) ?> + getBirthDate()) ?> diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index ea99aea..1e5ec28 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -21,10 +21,10 @@ echo substr($s, 0, -2); Nombre d'équipes maximal : getSize() ?>
    Lieu : getPlace() ?>
    Prix par partipant : getPrice() == 0 ? "Gratuit" : $tournament->getPrice() . " €" ?>
    -Dates : Du getStartDate()) ?> au getEndDate()) ?>
    -Clôture des inscriptions : getInscriptionDate(), true) ?>
    -Date limite d'envoi des solutions : getSolutionsDate(), true) ?>
    -Date limite d'envoi des notes de synthèse : getSynthesesDate(), true) ?>
    +Dates : Du getStartDate()) ?> au getEndDate()) ?>
    +Clôture des inscriptions : getInscriptionDate(), true) ?>
    +Date limite d'envoi des solutions : getSolutionsDate(), true) ?>
    +Date limite d'envoi des notes de synthèse : getSynthesesDate(), true) ?>
    Description : getDescription() ?>
    isFinal()) @@ -73,7 +73,7 @@ if ($tournament->isFinal()) ?> - + "> - Du au - - + Du au + + "> - Du au - - + Du au + + From 70cece8694cdf0831e92080c2db34686703b4088 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 16:58:23 +0200 Subject: [PATCH 043/120] =?UTF-8?q?Am=C3=A9lioration=20de=20la=20classe=20?= =?UTF-8?q?d'ajout=20d'=C3=A9quipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/ajouter_equipe.php | 87 ++++++++++--------- server_files/model.php | 20 ++++- server_files/services/mail.php | 18 ++++ .../services/mail_templates/add_team.html | 15 ++++ server_files/views/ajouter_equipe.php | 10 +-- 5 files changed, 101 insertions(+), 49 deletions(-) create mode 100644 server_files/services/mail_templates/add_team.html diff --git a/server_files/controllers/ajouter_equipe.php b/server_files/controllers/ajouter_equipe.php index 70d62db..f200932 100644 --- a/server_files/controllers/ajouter_equipe.php +++ b/server_files/controllers/ajouter_equipe.php @@ -5,59 +5,62 @@ if (!isset($_SESSION["role"]) || ($_SESSION["role"] != Role::PARTICIPANT && $_SE $tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `date_inscription` > CURRENT_DATE AND `year` = '$YEAR';"); +$has_error = false; +$error_message = null; + if (isset($_POST["submitted"])) { - $error_message = registerTeam(); + $new_team = new NewTeam($_POST); + try { + $new_team->makeVerifications(); + $new_team->register(); + } + catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } } -function registerTeam() { - global $DB, $YEAR, $MAIL_ADDRESS, $access_code; +class NewTeam { + public $name; + public $trigram; + public $tournament_id; + public $tournament; + public $access_code; - if ($_SESSION["team"] != NULL) - return "Vous êtes déjà dans une équipe."; + public function __construct($data) + { + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + } - $name = htmlspecialchars($_POST["name"]); + public function makeVerifications() { + ensure($_SESSION["team"] == null, "Vous êtes déjà dans une équipe."); + ensure($this->name != null && $this->name != "", "Vous devez spécifier un nom d'équipe."); + ensure(preg_match("#^[A-Z]{3}$#", $this->trigram), "Le trigramme entré n'est pas valide."); + ensure(!teamExists($this->name), "Une équipe existe déjà avec ce nom."); + ensure(!trigramExists($this->trigram), "Une équipe a déjà choisi ce trigramme."); + $this->tournament = Tournament::fromId($this->tournament_id); + ensure($this->tournament != null, "Le tournoi spécifié n'existe pas."); + } - if (!isset($name) || $name == "") - return "Vous devez spécifier un nom d'équipe."; + public function register() { + global $DB, $YEAR; - $result = $DB->query("SELECT `id` FROM `teams` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Une équipe existe déjà avec ce nom."; + $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; + $this->access_code = ""; + for ($i = 0; $i < 6; ++$i) + $this->access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; - $trigram = strtoupper(htmlspecialchars($_POST["trigram"])); - - if (!preg_match("#^[A-Z][A-Z][A-Z]$#", $trigram)) - return "Le trigramme entré n'est pas valide."; - - $result = $DB->query("SELECT `id` FROM `teams` WHERE `trigram` = '" . $trigram . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Une équipe a déjà choisi ce trigramme."; - - $tournament_id = intval(htmlspecialchars($_POST["tournament"])); - $tournament = Tournament::fromId($tournament_id); - if ($tournament === null) - return "Le tournoi spécifié n'existe pas."; - - $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; - $access_code = ""; - for ($i = 0; $i < 6; ++$i) - $access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; - - $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) + $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$name, $trigram, $tournament_id, $_SESSION["role"] == Role::ENCADRANT ? $_SESSION["user_id"] : NULL, - $_SESSION["role"] == Role::PARTICIPANT ? $_SESSION["user_id"] : NULL, ValidationStatus::NOT_READY, $access_code, $YEAR]); + $req->execute([$this->name, $this->trigram, $this->tournament_id, $_SESSION["role"] == Role::ENCADRANT ? $_SESSION["user_id"] : NULL, + $_SESSION["role"] == Role::PARTICIPANT ? $_SESSION["user_id"] : NULL, ValidationStatus::NOT_READY, $this->access_code, $YEAR]); - $_SESSION["team"] = Team::fromTrigram($trigram); - $_SESSION["user"]->setTeamId($_SESSION["team"]->getId()); + $_SESSION["team"] = Team::fromTrigram($this->trigram); + $_SESSION["user"]->setTeamId($_SESSION["team"]->getId()); - $msg = "Bonjour " . $_SESSION["user"]->getFirstName() . " " . $_SESSION["user"]->getSurname() . ",\r\n\r\n"; - $msg .= "Vous venez de créer l'équipe « $name » ($trigram) pour le TFJM² de " . $tournament->getName() . " et nous vous en remercions. "; - $msg .= "Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : " . $access_code . "\r\n\r\n"; - $msg .= "Cordialement,\r\n\r\nL'organisation du TFJM² $YEAR"; - mail($_SESSION["user"]->getEmail(), "Nouvelle équipe TFJM² $YEAR", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; + sendAddTeam($_SESSION["user"], $_SESSION["team"], $this->tournament); + } } require_once "server_files/views/ajouter_equipe.php"; diff --git a/server_files/model.php b/server_files/model.php index bcb9db6..61548c6 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -92,7 +92,23 @@ function quitTeam() { function userExists($email) { global $DB, $YEAR; - $req = $DB->prepare("SELECT `email` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); + $req = $DB->prepare("SELECT `id` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); $req->execute([$email]); - return !$req->fetch(); + return $req->fetch(); +} + +function teamExists($name) { + global $DB, $YEAR; + + $req = $DB->prepare("SELECT `id` FROM `teams` WHERE `name` = ? AND `year` = '$YEAR';"); + $req->execute([$name]); + return $req->fetch(); +} + +function trigramExists($trigram) { + global $DB, $YEAR; + + $req = $DB->prepare("SELECT `id` FROM `teams` WHERE `trigram` = ? AND `year` = '$YEAR';"); + $req->execute([$trigram]); + return $req->fetch(); } \ No newline at end of file diff --git a/server_files/services/mail.php b/server_files/services/mail.php index 48fc5d8..9408ca1 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -27,4 +27,22 @@ function sendRegisterMail($new_user) $content = preg_replace("#{TOKEN}#", $new_user->confirm_email_token, $content); sendMail($new_user->email, "Inscription au TFJM² $YEAR", $content); +} + +/** + * @param $user User + * @param $team Team + * @param $tournament Tournament + */ +function sendAddTeam($user, $team, $tournament) +{ + global $LOCAL_PATH, $YEAR; + + $content = file_get_contents("$LOCAL_PATH/server_files/services/mail_templates/add_team.html"); + $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); + $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); + $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); + $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); + $content = preg_replace("#{TOURNAMENT_NAME}#", $tournament->getName(), $content); + $content = preg_replace("#{ACCESS_CODE}#", $team->getAccessCode(), $content); } \ No newline at end of file diff --git a/server_files/services/mail_templates/add_team.html b/server_files/services/mail_templates/add_team.html new file mode 100644 index 0000000..ada9e56 --- /dev/null +++ b/server_files/services/mail_templates/add_team.html @@ -0,0 +1,15 @@ + + + + + Nouvelle équipe TFJM² {YEAR} + + +Bonjour {FIRST_NAME} {SURNAME},
    +
    +Vous venez de créer l'équipe « {TEAM_NAME} » ({TRIGRAM}) pour le TFJM2 de {TOURNAMENT_NAME} et nous vous en remercions.
    +"Afin de permettre aux autres membres de votre équipe de vous rejoindre, veuillez leur transmettre le code d'accès : {ACCESS_CODE}
    +
    +Le comité national d'organisation du TFJM2 + + \ No newline at end of file diff --git a/server_files/views/ajouter_equipe.php b/server_files/views/ajouter_equipe.php index c74842b..bee55b2 100644 --- a/server_files/views/ajouter_equipe.php +++ b/server_files/views/ajouter_equipe.php @@ -1,10 +1,10 @@ +if (isset($new_team) && !$has_error) { ?> + Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : access_code ?> +

    Vous êtes déjà dans une équipe.

    - - Votre équipe a bien été créée ! Voici le code d'accès à transmettre aux autres membres de votre équipe : Erreur : " . $error_message . ""; ?> @@ -31,10 +31,10 @@ if ($_SESSION["team"] != NULL) { ?> - + - fetch()) !== FALSE) { echo "\n"; From 945e1105b80af21f144a29cde83a938f698aa9bd Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 17:26:30 +0200 Subject: [PATCH 044/120] Quelques modifications --- server_files/controllers/ajouter_equipe.php | 2 +- server_files/controllers/inscription.php | 1 + server_files/controllers/mon_compte.php | 12 ++++++------ server_files/services/mail.php | 21 +++++++++++++++++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/server_files/controllers/ajouter_equipe.php b/server_files/controllers/ajouter_equipe.php index f200932..013720b 100644 --- a/server_files/controllers/ajouter_equipe.php +++ b/server_files/controllers/ajouter_equipe.php @@ -59,7 +59,7 @@ class NewTeam { $_SESSION["team"] = Team::fromTrigram($this->trigram); $_SESSION["user"]->setTeamId($_SESSION["team"]->getId()); - sendAddTeam($_SESSION["user"], $_SESSION["team"], $this->tournament); + sendAddTeamMail($_SESSION["user"], $_SESSION["team"], $this->tournament); } } diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 417576b..245aead 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -49,6 +49,7 @@ class NewUser global $YEAR; ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); + $this->email = strtolower($this->email); ensure(userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index 915fafa..f09b3d8 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -1,17 +1,17 @@ getTrigram(), $content); $content = preg_replace("#{TOURNAMENT_NAME}#", $tournament->getName(), $content); $content = preg_replace("#{ACCESS_CODE}#", $team->getAccessCode(), $content); -} \ No newline at end of file + + sendMail($user->getEmail(), "Ajout d'une équipe TFJM² $YEAR", $content); +} + +/** + * @param NewUser + */ +function sendAddOrganizerMail($new_orga) +{ + global $LOCAL_PATH, $YEAR; + + $content = file_get_contents("$LOCAL_PATH/server_files/services/mail_templates/add_organizer.html"); + $content = preg_replace("#{FIRST_NAME}#", $new_orga->first_name, $content); + $content = preg_replace("#{SURNAME}#", $new_orga->surname, $content); + $content = preg_replace("#{PASSWORD}#", $new_orga->password, $content); + + sendMail($new_orga->email, "Inscription au TFJM² $YEAR", $content); +} From 0f0c08243774dadd6283661d4e0e6abe18ed4559 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 17:26:49 +0200 Subject: [PATCH 045/120] =?UTF-8?q?Am=C3=A9lioration=20des=20fichiers=20d'?= =?UTF-8?q?ajout=20d'organisateur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controllers/ajouter_organisateur.php | 84 +++++++++---------- .../mail_templates/add_organizer.html | 21 +++++ server_files/views/ajouter_organisateur.php | 4 +- 3 files changed, 65 insertions(+), 44 deletions(-) create mode 100644 server_files/services/mail_templates/add_organizer.html diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index ebf5cce..35c8f9c 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -3,58 +3,58 @@ if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) require_once "server_files/403.php"; +$has_error = false; +$error_message = null; + if (isset($_POST["submitted"])) { - $error_message = addOrganizer(); + $orga = new NewOrganizer($_POST); + try { + $orga->makeVerifications(); + $orga->register(); + } + catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } } -function addOrganizer() -{ - global $DB, $YEAR, $MAIL_ADDRESS; +class NewOrganizer { + public $surname; + public $first_name; + public $email; + public $admin; + public $password; - $surname = htmlspecialchars($_POST["surname"]); + public function __construct($data) + { + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + } - if (!isset($surname) || $surname == "") - return "Le nom est invalide."; + public function makeVerifications() + { + ensure($this->surname != null && $this->surname != "", "Le nom est invalide."); + ensure($this->first_name != null && $this->first_name != "", "Le prénom est invalide."); + ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail est invalide."); + $this->email = strtolower($this->email); + ensure(!userExists($this->email), "Cette adresse e-mail est déjà utilisée."); + $this->admin = $this->admin == "on" ? true : false; + } - $first_name = htmlspecialchars($_POST["first_name"]); + public function register() { + global $DB, $YEAR; - if (!isset($first_name) || $first_name == "") - return "Le prénom est invalide."; + $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + $this->password = ""; + for ($i = 0; $i < 16; ++$i) + $this->password .= $alphabet[rand(0, strlen($alphabet) - 1)]; - $email = strtolower(htmlspecialchars($_POST["email"])); - if (!isset($email) || $email == "" || !filter_var($email, FILTER_VALIDATE_EMAIL)) - return "L'adresse e-mail est invalide."; - - $admin = isset($_POST["admin"]) && $_POST["admin"] == "on"; - - $req = $DB->prepare("SELECT `id` FROM `users` WHERE `email` = ? AND `year` = '$YEAR';"); - $req->execute([$email]); - if ($req->fetch() !== FALSE) - return "Cette adresse e-mail est déjà utilisée."; - - $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - $password = ""; - for ($i = 0; $i < 16; ++$i) - $password .= $alphabet[rand(0, strlen($alphabet) - 1)]; - $hash = password_hash($password, PASSWORD_BCRYPT); - - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) VALUES (?, ?, ?, ?, ?, ?);"); - $req->execute([$email, $hash, $surname, $first_name, $admin ? "ADMIN" : "ORGANIZER", $YEAR]); + $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->surname, $this->first_name, $this->admin ? "ADMIN" : "ORGANIZER", $YEAR]); - $msg = "Bonjour " . $first_name . " " . $surname . ",\r\n\r\n" - . "Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM². " - . "Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. " - . "Elles vous permettront de gérer les inscriptions des équipes de votre tournoi.\r\n\r\n" - . "Votre mot de passe est : $password\r\n\r\n" - . "Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer " - . "lors de votre prochaine connexion sur le site.\r\n\r\n" - . "Merci beaucoup pour votre aide !\r\n\r\n" - . "Les organisateurs du TFJM²"; - - mail($email, "Organisateur du TFJM²", $msg, "From: $MAIL_ADDRESS\r\n"); - - return false; + sendAddOrganizerMail($this); + } } require_once "server_files/views/ajouter_organisateur.php"; \ No newline at end of file diff --git a/server_files/services/mail_templates/add_organizer.html b/server_files/services/mail_templates/add_organizer.html new file mode 100644 index 0000000..d0331e1 --- /dev/null +++ b/server_files/services/mail_templates/add_organizer.html @@ -0,0 +1,21 @@ + + + + + Organisateur du TFJM² + + +Bonjour {FIRST_NAME} {SURNAME},
    +
    +Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM2. +Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. Elles vous permettront de gérer les inscriptions des équipes de votre tournoi.
    +
    +Votre mot de passe est : {PASSWORD}
    +
    +Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer lors de votre prochaine connexion sur le site.
    +
    +Merci beaucoup pour votre aide !
    +
    +Le comité national d'organisation du TFJM2 + + \ No newline at end of file diff --git a/server_files/views/ajouter_organisateur.php b/server_files/views/ajouter_organisateur.php index ea647eb..9709b93 100644 --- a/server_files/views/ajouter_organisateur.php +++ b/server_files/views/ajouter_organisateur.php @@ -1,8 +1,8 @@ Erreur : " . $error_message . ""; } else { echo "

    Organisateur ajouté avec succès ! Ses identifiants ont été transmis par mail.

    "; From 8606ae7b957d42df4f87b51cce3e6fa52ebe6ca9 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 18:08:40 +0200 Subject: [PATCH 046/120] =?UTF-8?q?Am=C3=A9lioration=20des=20fichiers=20d'?= =?UTF-8?q?ajout=20de=20tournoi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatcher.php | 1 + server_files/controllers/ajouter_tournoi.php | 156 +++++++++--------- server_files/controllers/tournoi.php | 8 +- server_files/model.php | 8 + server_files/services/mail.php | 18 +- .../add_organizer_for_tournament.html | 16 ++ server_files/utils.php | 4 +- server_files/views/ajouter_tournoi.php | 11 +- 8 files changed, 129 insertions(+), 93 deletions(-) create mode 100644 server_files/services/mail_templates/add_organizer_for_tournament.html diff --git a/dispatcher.php b/dispatcher.php index ec52e4e..96f405d 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -42,6 +42,7 @@ $ROUTES["^solutions/?$"] = ["server_files/controllers/solutions.php"]; $ROUTES["^solutions_orga/?$"] = ["server_files/controllers/solutions_orga.php"]; $ROUTES["^syntheses/?$"] = ["server_files/controllers/syntheses.php"]; $ROUTES["^syntheses_orga/?$"] = ["server_files/controllers/syntheses_orga.php"]; +$ROUTES["^tournoi/(.*)/(modifier)/?$"] = ["server_files/controllers/tournoi.php", "name", "modifier"]; $ROUTES["^tournoi/(.*)/?$"] = ["server_files/controllers/tournoi.php", "name"]; $ROUTES["^tournois/?$"] = ["server_files/controllers/tournois.php"]; diff --git a/server_files/controllers/ajouter_tournoi.php b/server_files/controllers/ajouter_tournoi.php index 9670e3f..d6a9998 100644 --- a/server_files/controllers/ajouter_tournoi.php +++ b/server_files/controllers/ajouter_tournoi.php @@ -5,106 +5,100 @@ if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) $orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); +$has_error = false; +$error_message = null; + if (isset($_POST["submitted"])) { - $error_message = registerTournament(); + $tournament = new NewTournament($_POST); + try { + $tournament->makeVerifications(); + $tournament->register(); + } + catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } } -function registerTournament() { - global $DB, $YEAR, $MAIL_ADDRESS; +class NewTournament { + public $name; + public $organizers; + public $size; + public $place; + public $price; + public $date_start; + public $date_end; + public $date_inscription; + public $time_inscription; + public $date_solutions; + public $time_solutions; + public $date_syntheses; + public $time_syntheses; + public $description; + public $final; + public $tournament; - $name = htmlspecialchars($_POST["name"]); - - $result = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '" . $name . "' AND `year` = '$YEAR';"); - if ($result->fetch()) - return "Un tournoi existe déjà avec ce nom."; - - if (!isset($_POST["organizer"]) || sizeof($_POST["organizer"]) == 0) - return "Aucun organisateur n'a été choisi."; - - $organizers = $_POST["organizer"]; - $orga_mails = []; - - foreach ($organizers as $orga) { - $result = $DB->query("SELECT `role`, `email` FROM `users` WHERE `id` = '" . $orga . "' AND `year` = '$YEAR';"); - $data = $result->fetch(); - if ($data === FALSE) - return "L'organisateur spécifié n'existe pas."; - if ($data["role"] != Role::ORGANIZER && $data["role"] != Role::ADMIN) - return "L'organisateur indiqué ne peut pas organiser de tournoi."; - $orga_mails[] = $data["email"]; + public function __construct($data) + { + foreach ($data as $key => $value) + $this->$key = ($key == "organizers" ? $value : htmlspecialchars($value)); } - try { - $size = intval(htmlspecialchars($_POST["size"])); - } - catch (Exception $ex) { - return "Le nombre d'équipes indiqué n'est pas un entier valide."; - } + public function makeVerifications() + { + global $FINAL; - if ($size < 3 || $size > 12) - return "Un tournoi doit comporter entre 3 et 12 équipes."; + ensure($this->name != null && $this->name != "", "Le nom est invalide."); + ensure(!tournamentExists($this->name), "Un tournoi existe déjà avec ce nom."); + ensure(sizeof($this->organizers) > 0, "Aucun organisateur n'a été choisi."); - $place = htmlspecialchars($_POST["place"]); + $orgas = []; + foreach ($this->organizers as $orga_id) { + $orga = User::fromId($orga_id); + ensure($orga != null, "Un organisateur spécifié n'existe pas."); + ensure($orga->getRole() == Role::ORGANIZER || $orga->getRole() == Role::ADMIN, "Une personne indiquée ne peut pas organiser de tournoi."); + $orgas[] = $orga; + } + $this->organizers = $orgas; - try { - $price = intval(htmlspecialchars($_POST["price"])); - } - catch (Throwable $t) { - return "Le tarif pour les participants n'est pas un nombre valide."; - } + ensure(preg_match("#[0-9]*#", $this->size), "Le nombre d'équipes indiqué n'est pas un nombre valide."); + $this->size = intval($this->size); + ensure($this->size >= 3 && $this->size <= 15, "Un tournoi doit avoir au moins 3 et au plus 15 équipes."); - if ($price < 0) - return "Le TFJM² ne va pas payer les élèves pour venir."; + ensure(preg_match("#[0-9]*#", $this->price), "Le tarif pour les participants n'est pas un entier valide."); + $this->price = intval($this->price); + ensure($this->size >= 0, "Le TFJM² ne va pas payer les élèves pour venir."); + ensure($this->size <= 50, "Soyons raisonnable sur le prix."); - if ($price > 50) - return "Soyons raisonnable sur le prix."; + ensure(dateWellFormed($this->date_start), "La date de début n'est pas valide."); + ensure(dateWellFormed($this->date_end), "La date de fin n'est pas valide."); + ensure(dateWellFormed($this->date_inscription . " " . $this->time_inscription), "La date de clôture des inscriptions n'est pas valide."); + ensure(dateWellFormed($this->date_solutions . " " . $this->time_solutions), "La date limite de remise des solutions n'est pas valide."); + ensure(dateWellFormed($this->date_syntheses . " " . $this->time_syntheses), "La date limite de remise des notes de synthèse n'est pas valide."); - $date_start = htmlspecialchars($_POST["date_start"]); - $date_start_parsed = date_parse_from_format("yyyy-mm-dd", $date_start); + $this->final = $this->final ? 1 : 0; - $date_end = htmlspecialchars($_POST["date_end"]); - $date_end_parsed = date_parse_from_format("yyyy-mm-dd", $date_end); + ensure(!$this->final || $FINAL == NULL, "Une finale nationale est déjà enregistrée."); + } - $date_inscription = htmlspecialchars($_POST["date_inscription"]); - $time_inscription = htmlspecialchars($_POST["time_inscription"]); - $date_inscription_parsed = date_parse_from_format("yyyy-mm-dd", $date_inscription . ' ' . $time_inscription); + public function register() + { + global $DB, $YEAR; - $date_solutions = htmlspecialchars($_POST["date_solutions"]); - $time_solutions = htmlspecialchars($_POST["time_solutions"]); - $date_solutions_parsed = date_parse_from_format("yyyy-mm-dd", $date_solutions . ' ' . $time_solutions); - - $date_syntheses = htmlspecialchars($_POST["date_syntheses"]); - $time_syntheses = htmlspecialchars($_POST["time_syntheses"]); - $date_syntheses_parsed = date_parse_from_format("yyyy-mm-dd", $date_syntheses . ' ' . $time_syntheses); - - if (!$date_start_parsed || !$date_end_parsed || !$date_inscription_parsed || !$date_solutions_parsed || !$date_syntheses_parsed) - return "Une date est mal formée."; - - $description = htmlspecialchars($_POST["description"]); - - $final = isset($_POST["final"]) && $_POST["final"]; - - if ($final && $DB->query("SELECT `id` FROM `tournaments` WHERE `final` = true AND `year` = $YEAR;")->fetch() !== false) - return "Une finale est déjà enregistrée."; - - $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `size`, `place`, `price`, `description`, + $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `size`, `place`, `price`, `description`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `final`, `year`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); - $req->execute([$name, $size, $place, $price, $description, $date_start, $date_end, - "$date_inscription $time_inscription", "$date_solutions $time_solutions", "$date_syntheses $time_syntheses", $final, $YEAR]); + $req->execute([$this->name, $this->size, $this->place, $this->price, $this->description, $this->date_start, $this->date_end, + "$this->date_inscription $this->time_inscription", "$this->date_solutions $this->time_solutions", "$this->date_syntheses $this->time_syntheses", $this->final ? 1 : 0, $YEAR]); - $req = $DB->query("SELECT `id` FROM `tournaments` WHERE `name` = '$name' AND `year` = $YEAR;"); - $tournament_id = $req->fetch()["id"]; + $this->tournament = Tournament::fromName($this->name); - foreach ($organizers as $orga) { - $req = $DB->prepare("INSERT INTO `organizers`(`organizer`, `tournament`) VALUES(?, ?);"); - $req->execute([$orga, $tournament_id]); - } - - foreach ($orga_mails as $orga_mail) - mail($orga_mail, "Organisateur TFJM² " . $name, "Vous venez d'être promu organisateur du tournoi " . $name . " pour le TFJM² $YEAR !", "From: $MAIL_ADDRESS"); - - return false; + foreach ($this->organizers as $organizer) { + $req = $DB->prepare("INSERT INTO `organizers`(`organizer`, `tournament`) VALUES(?, ?);"); + $req->execute([$organizer->getId(), $this->tournament->getId()]); + sendAddOrganizerForTournamentMail($organizer, $this->tournament); + } + } } require_once "server_files/views/ajouter_tournoi.php"; diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 43010f5..84f9fb7 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -30,7 +30,7 @@ else $orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); function updateTournament() { - global $DB, $URL_BASE, $YEAR, $tournament; + global $DB, $URL_BASE, $YEAR, $tournament, $orgas; $name = htmlspecialchars($_POST["name"]); @@ -43,7 +43,7 @@ function updateTournament() { if ($_SESSION["role"] == Role::ADMIN) { $organizers = $_POST["organizer"]; - $orga_mails = []; + $orgas = []; foreach ($organizers as $orga_id) { $orga = User::fromId($orga_id); @@ -51,7 +51,7 @@ function updateTournament() { return "L'organisateur spécifié n'existe pas."; if ($orga->getRole() != Role::ORGANIZER && $orga->getRole() != Role::ADMIN) return "L'organisateur indiqué ne peut pas organiser de tournoi."; - $orga_mails[] = $orga->getEmail(); + $orgas[] = $orga; } } @@ -111,7 +111,7 @@ function updateTournament() { if ($_SESSION["role"] == Role::ADMIN) { $DB->exec("DELETE FROM `organizers` WHERE `tournament` = " . $tournament->getId() . ";"); - foreach ($organizers as $orga) { + foreach ($orgas as $orga) { $req = $DB->prepare("INSERT INTO `organizers`(`organizer`, `tournament`) VALUES(?, ?);"); $req->execute([$orga->getId(), $tournament->getId()]); } diff --git a/server_files/model.php b/server_files/model.php index 61548c6..afe6503 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -111,4 +111,12 @@ function trigramExists($trigram) { $req = $DB->prepare("SELECT `id` FROM `teams` WHERE `trigram` = ? AND `year` = '$YEAR';"); $req->execute([$trigram]); return $req->fetch(); +} + +function tournamentExists($name) { + global $DB, $YEAR; + + $req = $DB->prepare("SELECT `id` FROM `tournaments` WHERE `name` = ? AND `year` = '$YEAR';"); + $req->execute([$name]); + return $req->fetch(); } \ No newline at end of file diff --git a/server_files/services/mail.php b/server_files/services/mail.php index 32b09f4..cc45bec 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -61,5 +61,21 @@ function sendAddOrganizerMail($new_orga) $content = preg_replace("#{SURNAME}#", $new_orga->surname, $content); $content = preg_replace("#{PASSWORD}#", $new_orga->password, $content); - sendMail($new_orga->email, "Inscription au TFJM² $YEAR", $content); + sendMail($new_orga->email, "Ajout d'un organisateur -- TFJM² $YEAR", $content); +} + +/** + * @param $organizer User + * @param $tournament Tournament + */ +function sendAddOrganizerForTournamentMail($organizer, $tournament) +{ + global $LOCAL_PATH, $YEAR; + + $content = file_get_contents("$LOCAL_PATH/server_files/services/mail_templates/add_organizer_for_tournament.html"); + $content = preg_replace("#{FIRST_NAME}#", $organizer->getFirstName(), $content); + $content = preg_replace("#{SURNAME}#", $organizer->getSurname(), $content); + $content = preg_replace("#{TOURNAMENT_NAME}#", $tournament->getName(), $content); + + sendMail($organizer->getEmail(), "Ajout d'un organisateur pour le tournoi " . $tournament->getName() . "-- TFJM² $YEAR", $content); } diff --git a/server_files/services/mail_templates/add_organizer_for_tournament.html b/server_files/services/mail_templates/add_organizer_for_tournament.html new file mode 100644 index 0000000..bbc6e03 --- /dev/null +++ b/server_files/services/mail_templates/add_organizer_for_tournament.html @@ -0,0 +1,16 @@ + + + + + Organisateur du tournoi de {TOURNAMENT_NAME} -- TFJM² + + +Bonjour {FIRST_NAME} {SURNAME},
    +
    +Vous venez d'être promu organisateur du tournoi {TOURNAMENT_NAME} du TFJM2 {YEAR}.
    +
    +Cordialement,
    +
    +Le comité national d'organisation du TFJM2 + + \ No newline at end of file diff --git a/server_files/utils.php b/server_files/utils.php index 12671cb..342a268 100644 --- a/server_files/utils.php +++ b/server_files/utils.php @@ -12,6 +12,6 @@ function formatDate($date = NULL, $with_time = false) { return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); } -function dateWellFormed($date, $format = "yyyy-mm-dd") { - return date_parse_from_format($format, $date) !== false; +function dateWellFormed($date, $with_time = false) { + return date_parse_from_format($with_time ? "yyyy-mm-dd HH-MM:ss" : "yy-mm-dd", $date) !== false; } \ No newline at end of file diff --git a/server_files/views/ajouter_tournoi.php b/server_files/views/ajouter_tournoi.php index d62116a..309752e 100644 --- a/server_files/views/ajouter_tournoi.php +++ b/server_files/views/ajouter_tournoi.php @@ -1,10 +1,11 @@ Erreur : " . $error_message . ""; - } else { + } + else { echo "

    Tournoi de " . htmlspecialchars($_POST["name"]) . " ajouté avec succès !

    "; } }?> @@ -23,10 +24,10 @@ if (isset($error_message)) { - + - fetch()) !== FALSE) { echo "\n"; From 44e91a1f8bd5ded03f93e2eb4ad15b0b4b6d30c2 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 18:43:51 +0200 Subject: [PATCH 047/120] =?UTF-8?q?Ajout=20d'une=20classe=20pour=20les=20f?= =?UTF-8?q?ichiers=20=C3=A0=20t=C3=A9l=C3=A9charger,=20meilleur=20support?= =?UTF-8?q?=20des=20organisateurs=20d'un=20tournoi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatcher.php | 1 + server_files/classes/Document.php | 282 +++++++++++++++++++++++++ server_files/classes/Tournament.php | 23 ++ server_files/controllers/tournoi.php | 11 +- server_files/controllers/view_file.php | 60 +++--- 5 files changed, 338 insertions(+), 39 deletions(-) create mode 100644 server_files/classes/Document.php diff --git a/dispatcher.php b/dispatcher.php index 96f405d..c14079f 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -2,6 +2,7 @@ require_once "server_files/config.php"; +require_once "server_files/classes/Document.php"; require_once "server_files/classes/Role.php"; require_once "server_files/classes/SchoolClass.php"; require_once "server_files/classes/Team.php"; diff --git a/server_files/classes/Document.php b/server_files/classes/Document.php new file mode 100644 index 0000000..32710e6 --- /dev/null +++ b/server_files/classes/Document.php @@ -0,0 +1,282 @@ +prepare("SELECT * FROM `documents` WHERE `file_id` = ?;"); + $req->execute([htmlspecialchars($id)]); + $data = $req->fetch(); + + if ($data === false) + return null; + + $user = new Document(); + $user->fill($data); + return $user; + } + + private function fill($data) + { + $this->file_id = $data["file_id"]; + $this->user_id = $data["user"]; + $this->team_id = $data["team"]; + $this->tournament_id = $data["tournament"]; + $this->type = DocumentType::fromName($data["type"]); + $this->uploaded_at = $data["uploaded_at"]; + } + + public function getFileId() + { + return $this->file_id; + } + + public function getUserId() + { + return $this->user_id; + } + + public function getTeamId() + { + return $this->team_id; + } + + public function getTournamentId() + { + return $this->tournament_id; + } + + public function getType() + { + return $this->type; + } + + public function getUploadedAt() + { + return $this->uploaded_at; + } +} + +class Solution +{ + private $file_id; + private $team_id; + private $tournament_id; + private $problem; + private $uploaded_at; + + private function __construct() {} + + public static function fromId($id) + { + global $DB; + $req = $DB->prepare("SELECT * FROM `documents` WHERE `file_id` = ?;"); + $req->execute([htmlspecialchars($id)]); + $data = $req->fetch(); + + if ($data === false) + return null; + + $user = new Solution(); + $user->fill($data); + return $user; + } + + private function fill($data) + { + $this->file_id = $data["file_id"]; + $this->team_id = $data["team_id"]; + $this->tournament_id = $data["tournament_id"]; + $this->problem = $data["problem"]; + $this->uploaded_at = $data["uploaded_at"]; + } + + public function getFileId() + { + return $this->file_id; + } + + public function getTeamId() + { + return $this->team_id; + } + + public function getTournamentId() + { + return $this->tournament_id; + } + + public function getProblem() + { + return $this->problem; + } + + public function getUploadedAt() + { + return $this->uploaded_at; + } +} + +class Synthese +{ + private $file_id; + private $team_id; + private $tournament_id; + private $dest; + private $uploaded_at; + + private function __construct() {} + + public static function fromId($id) + { + global $DB; + $req = $DB->prepare("SELECT * FROM `documents` WHERE `file_id` = ?;"); + $req->execute([htmlspecialchars($id)]); + $data = $req->fetch(); + + if ($data === false) + return null; + + $user = new Synthese(); + $user->fill($data); + return $user; + } + + private function fill($data) + { + $this->file_id = $data["file_id"]; + $this->team_id = $data["team"]; + $this->tournament_id = $data["tournament"]; + $this->dest = DestType::fromName($data["dest"]); + $this->uploaded_at = $data["uploaded_at"]; + } + + public function getFileId() + { + return $this->file_id; + } + + public function getTeamId() + { + return $this->team_id; + } + + public function getTournamentId() + { + return $this->tournament_id; + } + + public function getDest() + { + return $this->dest; + } + + public function getUploadedAt() + { + return $this->uploaded_at; + } +} + +class DestType +{ + const DEFENSEUR = 0; + const OPPOSANT = 1; + const RAPPORTEUR = 2; + + public static function getTranslatedName($status) { + switch ($status) { + case self::DEFENSEUR: + return "Défenseur"; + case self::OPPOSANT: + return "Opposant"; + default: + return "Rapporteur"; + } + } + + public static function getName($status) { + switch ($status) { + case self::DEFENSEUR: + return "DEFENSEUR"; + case self::OPPOSANT: + return "OPPOSANT"; + default: + return "RAPPORTEUR"; + } + } + + public static function fromName($name) { + switch ($name) { + case "DEFENSEUR": + return self::DEFENSEUR; + case "OPPOSANT": + return self::OPPOSANT; + default: + return self::RAPPORTEUR; + } + } +} + +class DocumentType +{ + const PARENTAL_CONSENT = 0; + const PHOTO_CONSENT = 1; + const SANITARY_PLUG = 2; + const SOLUTION = 3; + const SYNTHESE = 4; + + public static function getTranslatedName($type) { + switch ($type) { + case self::PARENTAL_CONSENT: + return "Autorisation parentale"; + case self::PHOTO_CONSENT: + return "Autorisation de droit à l'image"; + case self::SANITARY_PLUG: + return "Fiche sanitaire"; + case self::SOLUTION: + return "Solution"; + default: + return "Note de synthèse"; + } + } + + public static function getName($type) { + switch ($type) { + case self::PARENTAL_CONSENT: + return "PARENTAL_CONSENT"; + case self::PHOTO_CONSENT: + return "PHOTO_CONSENT"; + case self::SANITARY_PLUG: + return "SANITARY_PLUG"; + case self::SOLUTION: + return "SOLUTION"; + default: + return "SYNTHESE"; + } + } + + public static function fromName($name) { + switch ($name) { + case "PARENTAL_CONSENT": + return self::PARENTAL_CONSENT; + case "PHOTO_CONSENT": + return self::PHOTO_CONSENT; + case "SANITARY_PLUG": + return self::SANITARY_PLUG; + case "SOLUTION": + return self::SOLUTION; + default: + return self::SYNTHESE; + } + } +} \ No newline at end of file diff --git a/server_files/classes/Tournament.php b/server_files/classes/Tournament.php index f5fca77..2461b3f 100644 --- a/server_files/classes/Tournament.php +++ b/server_files/classes/Tournament.php @@ -13,6 +13,7 @@ class Tournament private $date_solutions; private $date_syntheses; private $final; + private $organizers = []; private $year; private function __construct() {} @@ -76,6 +77,13 @@ class Tournament $this->date_syntheses = $data["date_syntheses"]; $this->final = $data["final"] == true; $this->year = $data["year"]; + + global $DB; + $req = $DB->prepare("SELECT `organizer` FROM `organizers` WHERE `tournament` = ?;"); + $req->execute([$this->id]); + + while (($data = $req->fetch()) !== false) + $this->organizers[] = User::fromId($data["organizer"]); } public function getId() @@ -215,6 +223,21 @@ class Tournament $DB->prepare("UPDATE `tournaments` SET `final` = ? WHERE `id` = ?;")->execute([$final, $this->id]); } + public function getOrganizers() + { + return $this->organizers; + } + + public function organize($user_id) + { + foreach ($this->organizers as $organizer) { + if ($organizer->getId() == $user_id) + return true; + } + + return false; + } + public function getYear() { return $this->year; diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 84f9fb7..e478229 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -3,19 +3,12 @@ $tournament_name = htmlspecialchars($_GET["name"]); $tournament = Tournament::fromName($tournament_name); +$orgas = $tournament->getOrganizers(); if ($tournament === null) require_once "server_files/404.php"; -$orgas_req = $DB->query("SELECT `users`.`id` AS `id` FROM `users` JOIN `organizers` ON `users`.`id` = `organizer` WHERE `tournament` = " . $tournament->getId() . ";"); -$orgas = []; -$orgas_id = []; -while (($orga_data = $orgas_req->fetch()) !== false) { - $orgas[] = User::fromId($orga_data["id"]); - $orgas_id[] = $orga_data["id"]; -} - -if (isset($_GET["modifier"]) && $_SESSION["role"] != Role::ADMIN && !in_array($_SESSION["user_id"], $orgas_id)) +if (isset($_GET["modifier"]) && $_SESSION["role"] != Role::ADMIN && !$tournament->organize($_SESSION["user_id"])) require_once "server_files/403.php"; if (isset($_POST["edit_tournament"])) { diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index 5b14be0..a20f6af 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -9,58 +9,58 @@ if (!isset($_SESSION["user_id"])) require_once "server_files/403.php"; $id = htmlspecialchars($_GET["file_id"]); -$type = "SOLUTION"; -$req = $DB->query("SELECT * FROM `solutions` WHERE `file_id` = '$id';"); -if (($data = $req->fetch()) === false) { - $req = $DB->query("SELECT * FROM `syntheses` WHERE `file_id` = '$id';"); - $type = "SYNTHESE"; +$type = DocumentType::SOLUTION; +$file = Solution::fromId($id); +if ($file === null) { + $type = DocumentType::SYNTHESE; + $file = Synthese::fromId($id); - if (($data = $req->fetch()) === false) { - $req = $DB->query("SELECT * FROM `documents` WHERE `file_id` = '$id';"); - $type = "DOCUMENT"; - $data = $req->fetch(); + if ($file === null) { + $file = Document::fromId($id); + $type = DocumentType::PARENTAL_CONSENT; } } -if ($data !== false) { - $team = Team::fromId($data["team"]); - $tournament = Tournament::fromId($data["tournament"]); +if ($file !== null) { + $team = Team::fromId($file->getTeamId()); + $tournament = Tournament::fromId($file->getTournamentId()); $trigram = $team->getTrigram(); - if ($type == "SOLUTION") { - $problem = $data["problem"]; + + if ($_SESSION["role"] == Role::ORGANIZER && !$tournament->organize($_SESSION["user_id"])) + require_once "server_files/403.php"; + + if ($type == DocumentType::SOLUTION) { + $problem = $file->getProblem(); $name = "Problème $problem $trigram.pdf"; if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; - - // TODO Seuls les organisateurs concernés doivent pouvoir télécharger les fichiers } else if ($type == "SYNTHESE") { - $dest = $data["dest"]; - $name = "Note de synthèse $trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"; + $dest = $file->getDest(); + $name = "Note de synthèse $trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . ".pdf"; - // TODO Seuls les organisateurs, défenseurs, opposants et rapporteurs doivent pouvoir télécharger les fichiers - } - else if ($type == "DOCUMENT") { - $user_id = $data["user"]; - $user = User::fromId($user_id); - - if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && $user_id != $_SESSION["user_id"]) + if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; + } + else { + $user = User::fromId($file->getUserId()); + $type = $file->getType(); - // TODO Seuls les organisateurs concernés doivent pouvoir télécharger les fichiers + if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && $user->getId() != $_SESSION["user_id"]) + require_once "server_files/403.php"; $surname = $user->getSurname(); $first_name = $user->getFirstName(); - switch ($data["type"]) { - case "PARENTAL_CONSENT": + switch ($type) { + case DocumentType::PARENTAL_CONSENT: $name = "Autorisation parentale"; break; - case "PHOTO_CONSENT": + case DocumentType::PHOTO_CONSENT: $name = "Autorisation de droit à l'image"; break; - case "SANITARY_PLUG": + case DocumentType::SANITARY_PLUG: $name = "Fiche sanitaire"; break; } From 5a93a0a754fa28ee85380f3607493fedcadeac09 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 19:01:23 +0200 Subject: [PATCH 048/120] =?UTF-8?q?Correction=20de=20probl=C3=A8mes=20vis-?= =?UTF-8?q?=C3=A0-vis=20de=20l'envoi=20et=20le=20t=C3=A9l=C3=A9chargement?= =?UTF-8?q?=20de=20fichiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatcher.php | 2 +- server_files/classes/Document.php | 8 +++---- server_files/controllers/solutions.php | 25 ++++++++++++--------- server_files/controllers/syntheses.php | 25 ++++++++++++--------- server_files/controllers/syntheses_orga.php | 2 +- server_files/controllers/view_file.php | 9 +++----- 6 files changed, 37 insertions(+), 34 deletions(-) diff --git a/dispatcher.php b/dispatcher.php index c14079f..3a9dfb4 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -32,7 +32,7 @@ $ROUTES["^confirmer_mail/([a-z0-9]*)/?$"] = ["server_files/controllers/confirmer $ROUTES["^connexion/?$"] = ["server_files/controllers/connexion.php"]; $ROUTES["^deconnexion/?$"] = ["server_files/controllers/deconnexion.php"]; $ROUTES["^equipe/([A-Z]{3})/?$"] = ["server_files/controllers/equipe.php", "trigram"]; -$ROUTES["^file/[a-z0-9]{64}/?$"] = ["server_files/controllers/view_file.php", "file_id"]; +$ROUTES["^file/([a-z0-9]{64})/?$"] = ["server_files/controllers/view_file.php", "file_id"]; $ROUTES["^informations/([0-9]*)/.*?$"] = ["server_files/controllers/informations.php", "id"]; $ROUTES["^inscription/?$"] = ["server_files/controllers/inscription.php"]; $ROUTES["^mon_compte/?$"] = ["server_files/controllers/mon_compte.php"]; diff --git a/server_files/classes/Document.php b/server_files/classes/Document.php index 32710e6..cfac1b9 100644 --- a/server_files/classes/Document.php +++ b/server_files/classes/Document.php @@ -80,7 +80,7 @@ class Solution public static function fromId($id) { global $DB; - $req = $DB->prepare("SELECT * FROM `documents` WHERE `file_id` = ?;"); + $req = $DB->prepare("SELECT * FROM `solutions` WHERE `file_id` = ?;"); $req->execute([htmlspecialchars($id)]); $data = $req->fetch(); @@ -95,8 +95,8 @@ class Solution private function fill($data) { $this->file_id = $data["file_id"]; - $this->team_id = $data["team_id"]; - $this->tournament_id = $data["tournament_id"]; + $this->team_id = $data["team"]; + $this->tournament_id = $data["tournament"]; $this->problem = $data["problem"]; $this->uploaded_at = $data["uploaded_at"]; } @@ -140,7 +140,7 @@ class Synthese public static function fromId($id) { global $DB; - $req = $DB->prepare("SELECT * FROM `documents` WHERE `file_id` = ?;"); + $req = $DB->prepare("SELECT * FROM `syntheses` WHERE `file_id` = ?;"); $req->execute([htmlspecialchars($id)]); $data = $req->fetch(); diff --git a/server_files/controllers/solutions.php b/server_files/controllers/solutions.php index 0357130..45bbb7d 100644 --- a/server_files/controllers/solutions.php +++ b/server_files/controllers/solutions.php @@ -3,20 +3,23 @@ if (!isset($_SESSION["team"])) require_once "server_files/403.php"; -if (isset($_POST["send_solution"])) { - $error_message = saveSolution(); -} - -/** @var Team $team */ +/** + * @var Team $team + * @var Tournament $tournament + */ $team = $_SESSION["team"]; - -$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem`, `uploaded_at` ORDER BY `problem`, `uploaded_at` DESC;"); -$solutions_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()]]); - $tournament = Tournament::fromId($team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()); +if (isset($_POST["send_solution"])) { + $error_message = saveSolution(); +} + +/** @noinspection SqlAggregates */ +$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem` ORDER BY `problem`, `uploaded_at` DESC;"); +$solutions_req->execute([$team->getId(), $tournament->getId()]); + function saveSolution() { - global $LOCAL_PATH, $DB; + global $LOCAL_PATH, $DB, $team, $tournament; try { $problem = $_POST["problem"]; @@ -52,7 +55,7 @@ function saveSolution() { return "Une erreur est survenue lors de l'envoi du fichier."; $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $problem]); + $req->execute([$id, $team->getId(), $tournament->getId(), $problem]); return false; } diff --git a/server_files/controllers/syntheses.php b/server_files/controllers/syntheses.php index 05886ee..1e3520f 100644 --- a/server_files/controllers/syntheses.php +++ b/server_files/controllers/syntheses.php @@ -3,20 +3,23 @@ if (!isset($_SESSION["team"])) require_once "server_files/403.php"; -if (isset($_POST["send_synthese"])) { - $error_message = saveSynthese(); -} - -/** @var Team $team */ +/** + * @var Team $team + * @var Tournament $tournament + */ $team = $_SESSION["team"]; - -$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); -$syntheses_req->execute([$team->getId(), $_SESSION[$team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()]]); - $tournament = Tournament::fromId($team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()); +if (isset($_POST["send_synthese"])) { + $error_message = saveSynthese(); +} + +/** @noinspection SqlAggregates */ +$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest` ORDER BY `dest`, `uploaded_at` DESC;"); +$syntheses_req->execute([$team->getId(), $tournament->getId()]); + function saveSynthese() { - global $LOCAL_PATH, $DB; + global $LOCAL_PATH, $DB, $team, $tournament; $dest = strtoupper(htmlspecialchars($_POST["dest"])); @@ -48,7 +51,7 @@ function saveSynthese() { return "Une erreur est survenue lors de l'envoi du fichier."; $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["team_id"], $_SESSION["tournament_id"], $dest]); + $req->execute([$id, $team->getId(), $tournament->getId(), $dest]); return false; } diff --git a/server_files/controllers/syntheses_orga.php b/server_files/controllers/syntheses_orga.php index f8f852b..16b1b77 100644 --- a/server_files/controllers/syntheses_orga.php +++ b/server_files/controllers/syntheses_orga.php @@ -31,7 +31,7 @@ if (isset($_POST["download_zip"])) { header("Content-Type: application/zip"); header("Content-Disposition: attachment; filename=\"Notes de syntèses du tournoi de $tournament_name.zip\""); - header("Content-Length: " . strval(filesize($temp) + 1)); + header("Content-Length: " . filesize($temp)); readfile($temp); diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index a20f6af..ed480a0 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -37,7 +37,7 @@ if ($file !== null) { if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; } - else if ($type == "SYNTHESE") { + else if ($type == DocumentType::SYNTHESE) { $dest = $file->getDest(); $name = "Note de synthèse $trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . ".pdf"; @@ -67,15 +67,12 @@ if ($file !== null) { $name .= " de $first_name $surname.pdf"; } } -else { +else require_once "server_files/404.php"; - http_response_code(404); - exit(); -} header("Content-Type: application/pdf"); header("Content-Disposition: inline; filename=\"$name\""); -readfile("$URL_BASE/files/$id"); +readfile("$LOCAL_PATH/files/$id"); exit(); \ No newline at end of file From 3cc66ef7839e89199900fd64ed911b64d8b09a4d Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sat, 7 Sep 2019 21:06:49 +0200 Subject: [PATCH 049/120] =?UTF-8?q?Les=20notes=20de=20synth=C3=A8ses=20n'o?= =?UTF-8?q?nt=20pas=20=C3=A0=20=C3=AAtre=20copi=C3=A9es=20pour=20la=20fina?= =?UTF-8?q?le?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/equipe.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 629b6dd..02d2462 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -39,26 +39,6 @@ if (isset($_POST["select"])) { VALUES (?, ?, ?, ?);"); $req->execute([$id, $team->getId(), $_SESSION["final_id"], $sol_data["problem"]]); } - - $syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest`, `uploaded_at` ORDER BY `dest`, `uploaded_at` DESC;"); - $syntheses_req->execute([$team->getId(), $team->getTournamentId()]); - while (($synthese_data = $syntheses_req->fetch()) !== false) { - $old_id = $synthese_data["file_id"]; - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } - while (file_exists("$LOCAL_PATH/files/$id")); - - copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); - - $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team->getId(), $FINAL->getId(), $synthese_data["dest"]]); - } } $documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); From a25ec69ae9edef7ece412aa533fbdbae876c1641 Mon Sep 17 00:00:00 2001 From: Yohann Date: Sun, 8 Sep 2019 01:35:05 +0200 Subject: [PATCH 050/120] =?UTF-8?q?Am=C3=A9liorations=20du=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/classes/Document.php | 62 ++++-- server_files/classes/Tournament.php | 122 +++++++++-- server_files/classes/User.php | 29 +++ server_files/controllers/equipe.php | 16 +- server_files/controllers/informations.php | 11 +- server_files/controllers/mon_equipe.php | 18 +- server_files/controllers/solutions.php | 13 +- server_files/controllers/solutions_orga.php | 52 ++--- server_files/controllers/syntheses.php | 19 +- server_files/controllers/syntheses_orga.php | 53 ++--- server_files/controllers/tournoi.php | 11 +- server_files/controllers/tournois.php | 4 +- server_files/controllers/view_file.php | 6 +- server_files/model.php | 14 ++ server_files/views/equipe.php | 89 +++----- server_files/views/informations.php | 51 ++--- server_files/views/mon_equipe.php | 220 ++++++++++---------- server_files/views/solutions.php | 86 ++++---- server_files/views/solutions_orga.php | 25 +++ server_files/views/syntheses.php | 27 ++- server_files/views/syntheses_orga.php | 27 +++ server_files/views/tournoi.php | 37 +--- server_files/views/tournois.php | 23 +- 23 files changed, 558 insertions(+), 457 deletions(-) create mode 100644 server_files/views/solutions_orga.php create mode 100644 server_files/views/syntheses_orga.php diff --git a/server_files/classes/Document.php b/server_files/classes/Document.php index cfac1b9..575daa6 100644 --- a/server_files/classes/Document.php +++ b/server_files/classes/Document.php @@ -8,6 +8,7 @@ class Document private $tournament_id; private $type; private $uploaded_at; + private $version; private function __construct() {} @@ -21,9 +22,14 @@ class Document if ($data === false) return null; - $user = new Document(); - $user->fill($data); - return $user; + return self::fromData($data); + } + + public static function fromData($data) + { + $doc = new Document(); + $doc->fill($data); + return $doc; } private function fill($data) @@ -34,6 +40,7 @@ class Document $this->tournament_id = $data["tournament"]; $this->type = DocumentType::fromName($data["type"]); $this->uploaded_at = $data["uploaded_at"]; + $this->version = isset($data["version"]) ? $data["version"] : 1; } public function getFileId() @@ -65,6 +72,11 @@ class Document { return $this->uploaded_at; } + + public function getVersion() + { + return $this->version; + } } class Solution @@ -74,6 +86,7 @@ class Solution private $tournament_id; private $problem; private $uploaded_at; + private $version; private function __construct() {} @@ -87,9 +100,14 @@ class Solution if ($data === false) return null; - $user = new Solution(); - $user->fill($data); - return $user; + return self::fromData($data); + } + + public static function fromData($data) + { + $sol = new Solution(); + $sol->fill($data); + return $sol; } private function fill($data) @@ -99,6 +117,7 @@ class Solution $this->tournament_id = $data["tournament"]; $this->problem = $data["problem"]; $this->uploaded_at = $data["uploaded_at"]; + $this->version = isset($data["version"]) ? $data["version"] : 1; } public function getFileId() @@ -125,15 +144,21 @@ class Solution { return $this->uploaded_at; } + + public function getVersion() + { + return $this->version; + } } -class Synthese +class Synthesis { private $file_id; private $team_id; private $tournament_id; private $dest; private $uploaded_at; + private $version; private function __construct() {} @@ -147,9 +172,14 @@ class Synthese if ($data === false) return null; - $user = new Synthese(); - $user->fill($data); - return $user; + return self::fromData($data); + } + + public static function fromData($data) + { + $synthese = new Synthesis(); + $synthese->fill($data); + return $synthese; } private function fill($data) @@ -159,6 +189,7 @@ class Synthese $this->tournament_id = $data["tournament"]; $this->dest = DestType::fromName($data["dest"]); $this->uploaded_at = $data["uploaded_at"]; + $this->version = isset($data["version"]) ? $data["version"] : 1; } public function getFileId() @@ -185,6 +216,11 @@ class Synthese { return $this->uploaded_at; } + + public function getVersion() + { + return $this->version; + } } class DestType @@ -233,7 +269,7 @@ class DocumentType const PHOTO_CONSENT = 1; const SANITARY_PLUG = 2; const SOLUTION = 3; - const SYNTHESE = 4; + const SYNTHESIS = 4; public static function getTranslatedName($type) { switch ($type) { @@ -261,7 +297,7 @@ class DocumentType case self::SOLUTION: return "SOLUTION"; default: - return "SYNTHESE"; + return "SYNTHESIS"; } } @@ -276,7 +312,7 @@ class DocumentType case "SOLUTION": return self::SOLUTION; default: - return self::SYNTHESE; + return self::SYNTHESIS; } } } \ No newline at end of file diff --git a/server_files/classes/Tournament.php b/server_files/classes/Tournament.php index 2461b3f..8b2cff0 100644 --- a/server_files/classes/Tournament.php +++ b/server_files/classes/Tournament.php @@ -1,22 +1,25 @@ CURRENT_DATE AND "; + $sql .= "`year` = $YEAR ORDER BY `date_start`, `name`;"; + $req = $DB->query($sql); + + $tournaments = []; + + while (($data = $req->fetch()) !== false) { + $tournament = new Tournament(); + $tournament->fill($data); + $tournaments[] = $tournament; + } + + return $tournaments; + } + + private function fill($data) { $this->id = $data["id"]; $this->name = $data["name"]; @@ -223,6 +248,22 @@ class Tournament $DB->prepare("UPDATE `tournaments` SET `final` = ? WHERE `id` = ?;")->execute([$final, $this->id]); } + public function getAllTeams() + { + global $DB, $YEAR; + if ($this->final) + $req = $DB->query("SELECT `id` FROM `teams` WHERE `final_selection` AND `year` = $YEAR;"); + else + $req = $DB->query("SELECT `id` FROM `teams` WHERE `tournament` = $this->id AND `year` = $YEAR;"); + + $teams = []; + + while (($data = $req->fetch()) !== false) + $teams[] = Team::fromId($data["id"]); + + return $teams; + } + public function getOrganizers() { return $this->organizers; @@ -242,4 +283,55 @@ class Tournament { return $this->year; } + + public function getAllDocuments($team_id = -1) + { + global $DB; + + $req = $DB->query("SELECT * FROM `documents` AS `t1` " + . "INNER JOIN (SELECT `user`, `type`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `tournament`, `team`, `type`) `t2` " + . "ON `t1`.`user` = `t2`.`user` AND `t1`.`type` = `t2`.`type` AND `t1`.`tournament` = `t2`.`tournament` " + . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $this->id " . ($team_id == -1 ? "" : "AND `t1`.`team` = $team_id") . " ORDER BY `t1`.`team`, `t1`.`type`;"); + + $docs = []; + + while (($data = $req->fetch()) !== false) + $docs[] = Document::fromData($data); + + return $docs; + } + + public function getAllSolutions($team_id = -1) + { + global $DB; + + $req = $DB->query("SELECT * FROM `solutions` AS `t1` " + . "INNER JOIN (SELECT `team`, `problem`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `solutions` GROUP BY `tournament`, `team`, `problem`) `t2` " + . "ON `t1`.`team` = `t2`.`team` AND `t1`.`problem` = `t2`.`problem` AND `t1`.`tournament` = `t2`.`tournament` " + . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $this->id " . ($team_id == -1 ? "" : "AND `t1`.`team` = $team_id") . " ORDER BY `t1`.`team`, `t1`.`problem`;"); + + $sols = []; + + while (($data = $req->fetch()) !== false) + $sols[] = Solution::fromData($data); + + return $sols; + } + + public function getAllSyntheses($team_id = -1) + { + global $DB; + + $req = $DB->query("SELECT * FROM `syntheses` AS `t1` " + . "INNER JOIN (SELECT `team`, `dest`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `syntheses` GROUP BY `tournament`, `team`, `dest`) `t2` " + . "ON `t1`.`team` = `t2`.`team` AND `t1`.`dest` = `t2`.`dest` AND `t1`.`tournament` = `t2`.`tournament` " + . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $this->id " . ($team_id == -1 ? "" : "AND `t1`.`team` = $team_id") . " ORDER BY `t1`.`team`, `t1`.`dest`;"); + + $syntheses = []; + + while (($data = $req->fetch()) !== false) + $syntheses[] = Synthesis::fromData($data); + + return $syntheses; + } } \ No newline at end of file diff --git a/server_files/classes/User.php b/server_files/classes/User.php index a694170..1852ea7 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -359,4 +359,33 @@ class User { return $this->inscription_date; } + + public function getAllDocuments($tournament_id) + { + global $DB; + $req = $DB->query("SELECT * FROM `documents` AS `t1` " + . "INNER JOIN (SELECT `user`, `type`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `tournament`, `type`) `t2` " + . "ON `t1`.`user` = `t2`.`user` AND `t1`.`type` = `t2`.`type` AND `t1`.`tournament` = `t2`.`tournament` " + . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $tournament_id AND `t1`.`user` = $this->id ORDER BY `t1`.`type`;"); + + $docs = []; + + while (($data = $req->fetch()) !== false) + $docs[] = Document::fromData($data); + + return $docs; + } + + public function getOrganizedTournaments() + { + global $DB; + $req = $DB->query("SELECT `tournament` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $this->id ORDER BY `date_start`, `name`;"); + + $tournaments = []; + + while (($data = $req->fetch()) !== false) + $tournaments[] = Tournament::fromId($data["tournament"]); + + return $tournaments; + } } \ No newline at end of file diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 02d2462..1f52f94 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -6,6 +6,7 @@ if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ORGANIZER && $_SE $trigram = htmlspecialchars($_GET["trigram"]); $team = Team::fromTrigram($trigram); +$tournament = Tournament::fromId($team->getTournamentId()); if ($team === null) require_once "server_files/404.php"; @@ -35,20 +36,17 @@ if (isset($_POST["select"])) { copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); - $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) - VALUES (?, ?, ?, ?);"); + $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) VALUES (?, ?, ?, ?);"); $req->execute([$id, $team->getId(), $_SESSION["final_id"], $sol_data["problem"]]); } } -$documents_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` = ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); -$documents_req->execute([$team->getId(), $team->getId()]); +// TODO Télécharger en zip les documents personnels -if ($team->isSelectedForFinal()) { - $documents_final_req = $DB->prepare("SELECT `file_id`, `user`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` != ? GROUP BY `user`, `type` ORDER BY `user`, `type` ASC, MAX(`uploaded_at`) DESC;"); - $documents_final_req->execute([$team->getId(), $FINAL->getId()]); -} +$documents = $tournament->getAllDocuments($team->getId()); +$documents_final = null; -$tournament = Tournament::fromId($team->getTournamentId()); +if ($team->isSelectedForFinal()) + $documents_final = $FINAL->getAllDocuments($team->getId()); require_once "server_files/views/equipe.php"; diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index ff34005..9b076e2 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -11,13 +11,16 @@ if ($_SESSION["role"] != Role::ORGANIZER && $_SESSION["role"] != Role::ADMIN) { require_once "server_files/403.php"; } -if ($user === null) { +if ($user === null) require_once "server_files/404.php"; -} $team = Team::fromId($user->getTeamId()); +$tournaments = $user->getOrganizedTournaments(); -$documents_req = $DB->query("SELECT * FROM `documents` WHERE `user` = $id;"); -$tournaments_req = $DB->query("SELECT `tournament`, `name` FROM `organizers` JOIN `tournaments` ON `tournaments`.`id` = `tournament` WHERE `organizer` = $id ORDER BY `date_start`, `name`;"); +if ($team != null) { + $documents = $user->getAllDocuments($team->getTournamentId()); + if ($team->isSelectedForFinal()) + $documents_final = $user->getAllDocuments($FINAL->getId()); +} require_once "server_files/views/informations.php"; diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php index 5af190f..8dd4d8c 100644 --- a/server_files/controllers/mon_equipe.php +++ b/server_files/controllers/mon_equipe.php @@ -5,7 +5,7 @@ if (isset($_POST["leave_team"])) { exit(); } -$tournaments_response = $DB->query("SELECT `id`, `name` FROM `tournaments` WHERE `year` = '$YEAR';"); +$tournaments = Tournament::getAllTournaments(false, true); if (isset($_POST["send_document"])) { $error_message = sendDocument(); @@ -19,13 +19,17 @@ if (isset($_POST["request_validation"])) { } if (isset($_SESSION["user_id"]) && isset($_SESSION["team"]) && $_SESSION["team"] !== null) { - /** @var Team $team */ + /** + * @var User $user + * @var Team $team + */ + $user = $_SESSION["user"]; $team = $_SESSION["team"]; $tournament = Tournament::fromId($team->getTournamentId()); - - $documents_req = $DB->prepare("SELECT `file_id`, `type`, COUNT(`type`) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? GROUP BY `type`, `uploaded_at` ORDER BY `type`, `uploaded_at` DESC;"); - $documents_req->execute([$_SESSION["user_id"], $_SESSION[$team->isSelectedForFinal() ? $FINAL->getId() : $tournament->getId()]]); + $documents = $user->getAllDocuments($team->getTournamentId()); + if ($team->isSelectedForFinal()) + $documents_final = $user->getAllDocuments($FINAL->getId()); } else require_once "server_files/403.php"; @@ -36,7 +40,7 @@ if (isset($_POST["team_edit"])) { function sendDocument() { - global $LOCAL_PATH, $DB; + global $LOCAL_PATH, $DB, $FINAL; $type = strtoupper(htmlspecialchars($_POST["type"])); if (!isset($type) || ($type != "PARENTAL_CONSENT" && $type != "PHOTO_CONSENT" && $type != "SANITARY_PLUG")) @@ -67,7 +71,7 @@ function sendDocument() $req = $DB->prepare("INSERT INTO `documents`(`file_id`, `user`, `team`, `tournament`, `type`) VALUES (?, ?, ?, ?, ?);"); - $req->execute([$id, $_SESSION["user_id"], $_SESSION["team_id"], $_SESSION[isset($_SESSION["final_id"]) ? "final_id" : "tournament_id"], $type]); + $req->execute([$id, $_SESSION["user_id"], $_SESSION["team"]->getId(), $_SESSION["team"]->isSelectedForFinal() ? $FINAL->getId() : $_SESSION["team"]->getTournamentId(), $type]); return false; } diff --git a/server_files/controllers/solutions.php b/server_files/controllers/solutions.php index 45bbb7d..34f471d 100644 --- a/server_files/controllers/solutions.php +++ b/server_files/controllers/solutions.php @@ -8,18 +8,19 @@ if (!isset($_SESSION["team"])) * @var Tournament $tournament */ $team = $_SESSION["team"]; -$tournament = Tournament::fromId($team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()); +$tournament = Tournament::fromId($team->getTournamentId()); if (isset($_POST["send_solution"])) { $error_message = saveSolution(); } -/** @noinspection SqlAggregates */ -$solutions_req = $DB->prepare("SELECT `file_id`, `problem`, COUNT(`problem`) AS `version` FROM `solutions` WHERE `team` = ? AND `tournament` = ? GROUP BY `problem` ORDER BY `problem`, `uploaded_at` DESC;"); -$solutions_req->execute([$team->getId(), $tournament->getId()]); +$solutions = $tournament->getAllSolutions($team->getId()); +$solutions_final = null; +if ($team->isSelectedForFinal()) + $solutions_final = $FINAL->getAllSolutions($team->getId()); function saveSolution() { - global $LOCAL_PATH, $DB, $team, $tournament; + global $LOCAL_PATH, $DB, $team, $tournament, $FINAL; try { $problem = $_POST["problem"]; @@ -55,7 +56,7 @@ function saveSolution() { return "Une erreur est survenue lors de l'envoi du fichier."; $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team->getId(), $tournament->getId(), $problem]); + $req->execute([$id, $team->getId(), $team->isSelectedForFinal() ? $FINAL->getId() : $tournament->getId(), $problem]); return false; } diff --git a/server_files/controllers/solutions_orga.php b/server_files/controllers/solutions_orga.php index c049dba..69c9445 100644 --- a/server_files/controllers/solutions_orga.php +++ b/server_files/controllers/solutions_orga.php @@ -3,16 +3,10 @@ if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN && $_SESSION["role"] != Role::ORGANIZER) require_once "server_files/403.php"; -/** @noinspection SqlAggregates */ -$req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " - . ($_SESSION["role"] == Role::ADMIN ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR GROUP BY `tournament` ORDER BY `name`;"); - if (isset($_POST["download_zip"])) { $id = $_POST["tournament"]; - $tournament_name = $_POST["tournament_name"]; - /** @noinspection SqlAggregates */ - $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team`, `problem` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); + $tournament = Tournament::fromId($id); + $sols = $tournament->getAllSolutions(); $zip = new ZipArchive(); @@ -22,12 +16,12 @@ if (isset($_POST["download_zip"])) { die("Impossible de créer le fichier zip."); } - while (($data_file = $files_req->fetch()) !== false) { - $file_id = $data_file["file_id"]; - $problem = $data_file["problem"]; - $version = $data_file["version"]; - $team_id = $data_file["team"]; - $team = Team::fromId($team_id); + /** @var Solution $sol */ + foreach ($sols as $sol) { + $file_id = $sol->getFileId(); + $problem = $sol->getProblem(); + $version = $sol->getVersion(); + $team = Team::fromId($sol->getTeamId()); $team_name = $team->getName(); $team_trigram = $team->getTrigram(); @@ -37,7 +31,7 @@ if (isset($_POST["download_zip"])) { $zip->close(); header("Content-Type: application/zip"); - header("Content-Disposition: attachment; filename=\"Solutions du tournoi de $tournament_name.zip\""); + header("Content-Disposition: attachment; filename=\"Solutions du tournoi de " . $tournament->getName() . ".zip\""); header("Content-Length: " . strval(filesize($temp))); readfile($temp); @@ -45,29 +39,7 @@ if (isset($_POST["download_zip"])) { exit(); } -require_once "server_files/views/header.php"; +$user = $_SESSION["user"]; +$tournaments = $_SESSION["role"] == Role::ADMIN ? Tournament::getAllTournaments() : $user->getOrganizedTournaments(); -while (($data_tournament = $req->fetch()) !== false) { - echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; - $id = $data_tournament["id"]; - /** @noinspection SqlAggregates */ - $files_req = $DB->query("SELECT *, COUNT(`problem`) AS `version` FROM `solutions` WHERE `tournament` = '$id' GROUP BY `team` ORDER BY `team`, `problem`, `uploaded_at` DESC;"); - while (($data_file = $files_req->fetch()) !== false) { - $file_id = $data_file["file_id"]; - $problem = $data_file["problem"]; - $version = $data_file["version"]; - $team_id = $data_file["team"]; - $team = Team::fromId($team_id); - $team_name = $team->getName(); - $team_trigram = $team->getTrigram(); - echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
    "; - } - - echo "
    \n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "

    \n"; -} - -require_once "server_files/views/footer.php"; +require_once "server_files/views/solutions_orga.php"; diff --git a/server_files/controllers/syntheses.php b/server_files/controllers/syntheses.php index 1e3520f..65a2327 100644 --- a/server_files/controllers/syntheses.php +++ b/server_files/controllers/syntheses.php @@ -8,18 +8,19 @@ if (!isset($_SESSION["team"])) * @var Tournament $tournament */ $team = $_SESSION["team"]; -$tournament = Tournament::fromId($team->isSelectedForFinal() ? $FINAL->getId() : $team->getTournamentId()); +$tournament = Tournament::fromId($team->getTournamentId()); -if (isset($_POST["send_synthese"])) { - $error_message = saveSynthese(); +if (isset($_POST["send_synthesis"])) { + $error_message = saveSynthesis(); } -/** @noinspection SqlAggregates */ -$syntheses_req = $DB->prepare("SELECT `file_id`, `dest`, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `team` = ? AND `tournament` = ? GROUP BY `dest` ORDER BY `dest`, `uploaded_at` DESC;"); -$syntheses_req->execute([$team->getId(), $tournament->getId()]); +$syntheses = $tournament->getAllSyntheses($team->getId()); +$syntheses_final = null; +if ($team->isSelectedForFinal()) + $syntheses_final = $FINAL->getAllSyntheses($team->getId()); -function saveSynthese() { - global $LOCAL_PATH, $DB, $team, $tournament; +function saveSynthesis() { + global $LOCAL_PATH, $DB, $team, $tournament, $FINAL; $dest = strtoupper(htmlspecialchars($_POST["dest"])); @@ -51,7 +52,7 @@ function saveSynthese() { return "Une erreur est survenue lors de l'envoi du fichier."; $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team->getId(), $tournament->getId(), $dest]); + $req->execute([$id, $team->getId(), $team->isSelectedForFinal() ? $FINAL->getId() : $tournament->getId(), $dest]); return false; } diff --git a/server_files/controllers/syntheses_orga.php b/server_files/controllers/syntheses_orga.php index 16b1b77..6973c30 100644 --- a/server_files/controllers/syntheses_orga.php +++ b/server_files/controllers/syntheses_orga.php @@ -3,9 +3,8 @@ if (isset($_POST["download_zip"])) { $id = $_POST["tournament"]; - $tournament_name = $_POST["tournament_name"]; - /** @noinspection SqlAggregates */ - $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); + $tournament = Tournament::fromId($id); + $syntheses = $tournament->getAllSyntheses(); $zip = new ZipArchive(); @@ -15,22 +14,22 @@ if (isset($_POST["download_zip"])) { die("Impossible de créer le fichier zip."); } - while (($data_file = $files_req->fetch()) !== false) { - $file_id = $data_file["file_id"]; - $dest = $data_file["dest"]; - $version = $data_file["version"]; - $team_id = $data_file["team"]; - $team = Team::fromId($team_id); + /** @var Synthesis $synthesis */ + foreach ($syntheses as $synthesis) { + $file_id = $synthesis->getFileId(); + $dest = $synthesis->getDest(); + $version = $synthesis->getVersion(); + $team = Team::fromId($synthesis->getTeamId()); $team_name = $team->getName(); $team_trigram = $team->getTrigram(); - $zip->addFile("$LOCAL_PATH/files/$file_id", "Note de synthèse $team_trigram pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . ".pdf"); + $zip->addFile("$LOCAL_PATH/files/$file_id", "Note de synthèse $team_trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . ".pdf"); } $zip->close(); header("Content-Type: application/zip"); - header("Content-Disposition: attachment; filename=\"Notes de syntèses du tournoi de $tournament_name.zip\""); + header("Content-Disposition: attachment; filename=\"Notes de syntèses du tournoi de " . $tournament->getName() . ".zip\""); header("Content-Length: " . filesize($temp)); readfile($temp); @@ -38,33 +37,7 @@ if (isset($_POST["download_zip"])) { exit(); } -require_once "server_files/views/header.php"; +$user = $_SESSION["user"]; +$tournaments = $_SESSION["role"] == Role::ADMIN ? Tournament::getAllTournaments() : $user->getOrganizedTournaments(); -$req = $DB->query("SELECT `tournaments`.`id`, `name` FROM `tournaments` JOIN `organizers` ON `tournament` = `tournaments`.`id` WHERE " - . ($_SESSION["role"] == Role::ADMIN ? "" : "`organizer` = '" . $_SESSION["user_id"] . "' AND ") - . "`year` = $YEAR GROUP BY `tournament`, `name` ORDER BY `name`;"); - -while (($data_tournament = $req->fetch()) !== false) { - echo "

    Tournoi de " . $data_tournament["name"] . "

    \n"; - $id = $data_tournament["id"]; - $files_req = $DB->query("SELECT *, COUNT(`dest`) AS `version` FROM `syntheses` WHERE `tournament` = '$id' GROUP BY `team`, `dest`, `uploaded_at` ORDER BY `team`, `dest`, `uploaded_at` DESC;"); - while (($data_file = $files_req->fetch()) !== false) { - $file_id = $data_file["file_id"]; - $dest = $data_file["dest"]; - $version = $data_file["version"]; - $team_id = $data_file["team"]; - $team = Team::fromId($team_id); - $team_name = $team->getName(); - $team_trigram = $team->getTrigram(); - echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") - . ", version $version : Télécharger
    "; - } - - echo "
    \n"; - echo "\n"; - echo "\n"; - echo "\n"; - echo "

    \n"; -} - -require_once "server_files/views/footer.php"; +require_once "server_files/views/syntheses_orga.php"; \ No newline at end of file diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index e478229..36d9e46 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -1,9 +1,7 @@ getOrganizers(); if ($tournament === null) require_once "server_files/404.php"; @@ -14,13 +12,8 @@ if (isset($_GET["modifier"]) && $_SESSION["role"] != Role::ADMIN && !$tournament if (isset($_POST["edit_tournament"])) { $error_message = updateTournament(); } - -if ($tournament->isFinal()) - $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `final_selection` AND `year` = $YEAR;"); -else - $teams_response = $DB->query("SELECT `id`, `name`, `trigram`, `inscription_date`, `validation_status` FROM `teams` WHERE `tournament` = " . $tournament->getId() . " AND `year` = $YEAR;"); - -$orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); +$orgas = $tournament->getOrganizers(); +$teams = $tournament->getAllTeams(); function updateTournament() { global $DB, $URL_BASE, $YEAR, $tournament, $orgas; diff --git a/server_files/controllers/tournois.php b/server_files/controllers/tournois.php index ce23d82..db4c402 100644 --- a/server_files/controllers/tournois.php +++ b/server_files/controllers/tournois.php @@ -1,7 +1,5 @@ query("SELECT `name`, `date_start`, `date_end`, `date_inscription`, `date_solutions`, `size` FROM `tournaments` - WHERE `year` = '$YEAR' AND `final` = false ORDER BY `date_start`, `name`;"); -$final_data = $DB->query("SELECT `name`, `date_start`, `date_end`, `date_solutions`, `size` FROM `tournaments` WHERE `final` AND `year` = $YEAR;")->fetch(); +$tournaments = Tournament::getAllTournaments(); require_once "server_files/views/tournois.php"; diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index ed480a0..14aa853 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -13,8 +13,8 @@ $id = htmlspecialchars($_GET["file_id"]); $type = DocumentType::SOLUTION; $file = Solution::fromId($id); if ($file === null) { - $type = DocumentType::SYNTHESE; - $file = Synthese::fromId($id); + $type = DocumentType::SYNTHESIS; + $file = Synthesis::fromId($id); if ($file === null) { $file = Document::fromId($id); @@ -37,7 +37,7 @@ if ($file !== null) { if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; } - else if ($type == DocumentType::SYNTHESE) { + else if ($type == DocumentType::SYNTHESIS) { $dest = $file->getDest(); $name = "Note de synthèse $trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . ".pdf"; diff --git a/server_files/model.php b/server_files/model.php index afe6503..ed0005d 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -119,4 +119,18 @@ function tournamentExists($name) { $req = $DB->prepare("SELECT `id` FROM `tournaments` WHERE `name` = ? AND `year` = '$YEAR';"); $req->execute([$name]); return $req->fetch(); +} + +function printDocuments($documents) { + global $URL_BASE; + + foreach ($documents as $document) { + $file_id = $document->getFileId(); + $user = User::fromId($document->getUserId()); + $surname = $user->getSurname(); + $first_name = $user->getFirstName(); + $name = DocumentType::getTranslatedName($document->getType()); + $version = $document->getVersion(); + echo "$name de $first_name $surname (version $version) : Télécharger
    "; + } } \ No newline at end of file diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index e3b2f1e..a1ddb8f 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -1,10 +1,10 @@ -

    Informations sur l'équipe

    +

    Informations sur l'équipe

    -Nom de l'équipe : getName() ?>
    -Trigramme : getTrigram() ?>
    -Tournoi : getName() ?>">getName() ?>
    + Nom de l'équipe : getName() ?>
    + Trigramme : getTrigram() ?>
    + Tournoi : getName() ?>">getName() ?>
    getEncadrants()[$i] == NULL) @@ -26,72 +26,37 @@ if ($team->isSelectedForFinal()) { } ?> -
    +
    -

    Autorisations

    +

    Autorisations

    -fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $user_id = $data["user"]; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); - $surname = $user_data["surname"]; - $first_name = $user_data["first_name"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name de $first_name $surname : Télécharger
    "; -} -?> + + +
    + +
    isSelectedForFinal()) { ?> -
    -

    Autorisations pour la finale

    - fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $user_id = $data["user"]; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); - $surname = $user_data["surname"]; - $first_name = $user_data["first_name"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name de $first_name $surname : Télécharger
    "; - } -} +
    +

    Autorisations pour la finale

    + +
    + +
    + -if ($team->getValidationStatus() == ValidationStatus::WAITING && $_SESSION["role"] == Role::ADMIN) { ?> -
    - -
    +getValidationStatus() == ValidationStatus::WAITING && $_SESSION["role"] == Role::ADMIN) { ?> +
    + +
    isSelectedForFinal() && isset($_SESSION["user_id"]) && $_SESSION["role"] == Role::ADMIN) { ?> -
    - -
    +if (!$team->isSelectedForFinal() && $_SESSION["role"] == Role::ADMIN) { ?> +
    +
    + +
    \ No newline at end of file diff --git a/server_files/views/informations.php b/server_files/views/informations.php index 1a332f4..275f868 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -13,21 +13,7 @@ Numéro de téléphone : getPhoneNumber() ?>
    getRole() == Role::PARTICIPANT) { ?> Lycée : getSchool() ?>
    - Classe : getClass()) { - case "TERMINALE": - echo "Terminale"; - break; - case "PREMIERE": - echo "Première"; - break; - case "SECONDE": - echo "Seconde ou avant"; - break; - default: - echo "A hacké le site"; - break; - } - ?>
    + Classe : getClass()) ?>
    Nom du responsable légal : getResponsibleName() ?>
    Numéro de téléphone du responsable légal : getResponsiblePhone() ?>
    Adresse e-mail du responsable légal : getResponsibleEmail() ?> @@ -38,34 +24,21 @@ Numéro de téléphone : getPhoneNumber() ?>
    echo "
    "; if ($user->getRole() == Role::ADMIN || $user->getRole() == Role::ORGANIZER) { - while (($tournament_data = $tournaments_req->fetch()) !== false) { - echo "Organise le tournoi " . $tournament_data["name"] . "
    "; + foreach ($tournaments as $tournament) { + echo "Organise le tournoi getName(). "\">" . $tournament->getName() . "
    "; } } elseif ($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { ?>

    Autorisations

    - fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $user_id = $data["user"]; - $user_data = $DB->query("SELECT `surname`, `first_name` FROM `users` WHERE `id` = '$user_id';")->fetch(); - $surname = $user_data["surname"]; - $first_name = $user_data["first_name"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name de $first_name $surname : Télécharger
    "; - } + isSelectedForFinal()) { ?> +
    +

    Autorisations pour la finale

    + -

    Informations sur l'équipe

    +

    Informations sur l'équipe

    -Nom de l'équipe : getName() ?>
    -Trigramme : getTrigram() ?>
    -Tournoi : getName() ?>
    + Nom de l'équipe : getName() ?>
    + Trigramme : getTrigram() ?>
    + Tournoi : getName() ?>
    getEncadrants()[$i] == NULL) @@ -31,7 +31,7 @@ for ($i = 1; $i <= 6; ++$i) { echo "Participant $i : getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
    "; } ?> -Code d'accès : getAccessCode() ?>
    + Code d'accès : getAccessCode() ?>
    isSelectedForFinal()) { $final_name = $FINAL->getName(); echo "Équipe sélectionnée pour la finale nationale.
    "; @@ -39,133 +39,125 @@ Code d'accès : getAccessCode() ?>
    -
    - - - - - - - - - - - - - - + + + + + +
    - - - -
    - - - -
    - - - + + + + + + + + + + + + + - - - - - -
    + + + +
    + + + +
    + + + -
    - -
    - + +
    + +
    + - - Modifier mon équipe + + Modifier mon équipe -
    -

    Mes autorisations

    +
    +

    Mes autorisations

    fetch()) !== false) { - $file_id = $data["file_id"]; - $type = $data["type"]; - $version = $data["version"]; - switch ($data["type"]) { - case "PARENTAL_CONSENT": - $name = "Autorisation parentale"; - break; - case "PHOTO_CONSENT": - $name = "Autorisation de droit à l'image"; - break; - case "SANITARY_PLUG": - $name = "Fiche sanitaire"; - break; - } - echo "$name : Télécharger
    "; + printDocuments($documents); + + if ($team->isSelectedForFinal()) { ?> +
    +

    Mes autorisations pour la finale

    + getValidationStatus() == ValidationStatus::NOT_READY) { ?> -
    - - - - - - + + + + + + + + + +
    - - - + + + + + - - - - - - - - - -
    + + + -
    - - - -
    - -
    - + + + +
    + + + +
    + +
    + -
    getValidationStatus() == ValidationStatus::NOT_READY) { ?> - - - +
    +
    -
    - -
    -
    + + - + - -
    +
    + +
    +
    -
    - -
    -
    +
    + +
    +
    + + diff --git a/server_files/views/solutions.php b/server_files/views/solutions.php index a44fcc3..4312d55 100644 --- a/server_files/views/solutions.php +++ b/server_files/views/solutions.php @@ -7,56 +7,70 @@ if (isset($error_message)) { } else { echo "

    Le fichier a été correctement envoyé !

    "; } -}?> +} ?> getSolutionsDate()) { ?> -
    - - - - - - + + + + + + + + + +
    - - - + + + + + - - - - - - - - - -
    + + + -
    - - - -
    - -
    - + +
    + + + +
    + +
    + -
    +
    -

    Solutions soumises :

    +

    Solutions soumises :

    fetch()) !== false) { - $file_id = $data["file_id"]; - $problem = $data["problem"]; - $version = $data["version"]; +/** @var Solution $sol */ +foreach ($solutions as $sol) { + $file_id = $sol->getFileId(); + $problem = $sol->getProblem(); + $version = $sol->getVersion(); echo "Problème $problem (Version $version) : Télécharger
    "; } +if ($team->isSelectedForFinal()) { ?> +
    + +

    Solutions soumises pour la finale :

    + getFileId(); + $problem = $sol->getProblem(); + $version = $sol->getVersion(); + echo "Problème $problem (Version $version) : Télécharger
    "; + } +} require_once "footer.php"; diff --git a/server_files/views/solutions_orga.php b/server_files/views/solutions_orga.php new file mode 100644 index 0000000..989d719 --- /dev/null +++ b/server_files/views/solutions_orga.php @@ -0,0 +1,25 @@ +Tournoi de " . $tournament->getName() . "\n"; + $sols = $tournament->getAllSolutions(); + /** @var Solution $sol */ + foreach ($sols as $sol) { + $file_id = $sol->getFileId(); + $problem = $sol->getProblem(); + $version = $sol->getVersion(); + $team = Team::fromId($sol->getTeamId()); + $team_name = $team->getName(); + $team_trigram = $team->getTrigram(); + echo "Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
    "; + } + + echo "
    \n"; + echo "getId() . "\" />\n"; + echo "\n"; + echo "

    \n"; +} + +require_once "server_files/views/footer.php"; \ No newline at end of file diff --git a/server_files/views/syntheses.php b/server_files/views/syntheses.php index e1daaf9..fe9edf1 100644 --- a/server_files/views/syntheses.php +++ b/server_files/views/syntheses.php @@ -41,7 +41,7 @@ if (isset($error_message)) { - + @@ -54,11 +54,26 @@ if (isset($error_message)) {

    Notes de synthèse soumises :

    fetch()) !== false) { - $file_id = $data["file_id"]; - $dest = $data["dest"]; - $version = $data["version"]; - echo "Note de synthèse pour " . ($dest == "OPPOSANT" ? "l'opposant" : "le rapporteur") . " (Version $version) : Télécharger
    "; +/** @var Synthesis $synthesis */ +foreach ($syntheses as $synthesis) { + $file_id = $synthesis->getFileId(); + $dest = $synthesis->getDest(); + $version = $synthesis->getVersion(); + echo "Note de synthèse pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . " (version $version) : Télécharger
    "; +} + +if ($team->isSelectedForFinal()) { ?> +
    + +

    Notes de synthèse soumises pour la finale :

    + getFileId(); + $dest = $synthesis->getDest(); + $version = $synthesis->getVersion(); + echo "Note de synthèse pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . " (version $version) : Télécharger
    "; + } } require_once "footer.php"; \ No newline at end of file diff --git a/server_files/views/syntheses_orga.php b/server_files/views/syntheses_orga.php new file mode 100644 index 0000000..2912be6 --- /dev/null +++ b/server_files/views/syntheses_orga.php @@ -0,0 +1,27 @@ +Tournoi de " . $tournament->getName() . "\n"; + $syntheses = $tournament->getAllSyntheses(); + /** @var Synthesis $synthesis */ + foreach ($syntheses as $synthesis) { + $file_id = $synthesis->getFileId(); + $dest = $synthesis->getDest(); + $version = $synthesis->getVersion(); + $team = Team::fromId($synthesis->getTeamId()); + $team_name = $team->getName(); + $team_trigram = $team->getTrigram(); + echo "Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") + . ", version $version : Télécharger
    "; + } + + echo "
    \n"; + echo "getId() . "\" />\n"; + echo "\n"; + echo "

    \n"; +} + +require_once "server_files/views/footer.php"; diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 1e5ec28..904f671 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -31,7 +31,7 @@ if ($tournament->isFinal()) echo "Ce tournoi est la finale nationale du TFJM² 2020.
    "; ?> - +organize($_SESSION["user_id"]))) { ?> Éditer le tournoi @@ -60,38 +60,21 @@ if ($tournament->isFinal()) fetch()) != false) { + /** @var Team $team */ + foreach ($teams as $team) { ?> " . $team_data["name"] . ""; + if (isset($_SESSION["role"]) && ($_SESSION["role"] == Role::ADMIN || ($_SESSION["role"] == Role::ORGANIZER && $tournament->organize($_SESSION["user_id"])))) + echo "getTrigram() . "\">" . $team->getName(). ""; else - echo $team_data["name"]; - ?> - - - - - getName(); ?> + getTrigram() ?> + getInscriptionDate()) ?> + getValidationStatus()) ?> fetch()) !== FALSE) { - echo "\n"; } ?> diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index 13fffae..e631025 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -5,7 +5,7 @@ - + @@ -14,29 +14,22 @@ fetch()) !== FALSE) { + foreach ($tournaments as $tournament) { ?> - - - - - + + + + + - - - - - - - - + From 228c683dc822f364967a25ef269157fd41241b5a Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sun, 8 Sep 2019 01:42:47 +0200 Subject: [PATCH 051/120] =?UTF-8?q?Am=C3=A9liorations=20du=20code?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 403.php | 14 --- 404.php | 14 --- server_files/views/index.php | 210 +++++++++++++++++++---------------- 3 files changed, 114 insertions(+), 124 deletions(-) delete mode 100644 403.php delete mode 100644 404.php diff --git a/403.php b/403.php deleted file mode 100644 index fab537f..0000000 --- a/403.php +++ /dev/null @@ -1,14 +0,0 @@ - - -

    Vous n'êtes pas autorisé à accéder à cette page.

    - - \ No newline at end of file diff --git a/404.php b/404.php deleted file mode 100644 index 54ac204..0000000 --- a/404.php +++ /dev/null @@ -1,14 +0,0 @@ - - -

    Cette page n'existe pas.

    - - \ No newline at end of file diff --git a/server_files/views/index.php b/server_files/views/index.php index b41734a..e2170c3 100644 --- a/server_files/views/index.php +++ b/server_files/views/index.php @@ -1,108 +1,126 @@ -
    +
    + + + +
    + +
    +

    Vous souhaitez participer au tournoi ? Votre équipe est déjà formée ?

    +

    Créez un compte pour commencer la procédure d'inscription ou + connectez-vous si votre équipe a déjà un compte.

    +
    + +
    + +
    +

    Bienvenue sur le site d'inscription du TFJM2 !

    +
    + +
    + Ce site a été conçu pour gérer les inscriptions au Tournoi Français des Jeunes Mathématiciennes et + Mathématiciens. +
    + Cliquez ici pour accéder au site de présentation du tournoi. +
    + +
    + +

    + Attention aux échéances ! Chaque tournoi a une date limite pour les inscriptions et une date limite pour + déposer vos solutions. Elles sont affichées avec les informations de chaque tournoi. Merci de vous y + référer ! +
    + Une fois l'échéance passée, le site bloque tout accès aux inscriptions (et respectivement au dépôt des + solutions).
    +

    + +

    + Attention, modification du règlement par rapport aux années précédentes : article 4.3 +
    + "l’équipe doit envoyer par mail à contact@tfjm.org, une lettre (au format pdf), répondant aux questions + suivantes : +
    + +

    +
      +
    • Comment l’équipe s’est-elle formée ?
    • +
    • Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres avec + l’encadrant•e) ? +
    • +
    + + Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires à + une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés dans + le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non l’inscription des + équipes concernées par cette lettre." +
    + + Pour plus de détail, voir le règlement : https://tfjm.org/infos-tournois/ +

    + +
    +

    Comment ça marche ?

    +
    + +

    + Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique + Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé à + cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer par la + suite. +

    + +

    + Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : +

    +
      +
    • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
    • +
    • enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière version + enregistrée avant la date limite sera prise en compte pour le tournoi). +
    • +
    + + Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, votre + inscription pourra être validée par les organisateurs locaux. +

    +

    + ATTENTION ! Votre équipe ne sera considérée comme admissible à participer au tournoi que + lorsque cette première étape aura été franchie. +

    - +

    + Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible pour + avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque tournoi (qui + sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes seront placées en + liste d'attente. +

    -
    +

    + Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer + deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers le + site pour compléter votre inscription. +

    -
    +

    + ATTENTION ! Les équipes qui ne respecteront pas les délais pour rendre ces documents + risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente. +

    +

    + NB : Ce site est récent et il est encore possible que certaines pages ne fonctionnent + pas correctement. Si vous remarquez des bugs, merci de les signaler à l'adresse contact@tfjm.org. +

    -

    Vous souhaitez participer au tournoi ? Votre équipe est déjà formée ?

    -

    Créez un compte pour commencer la procédure d'inscription ou connectez-vous si votre équipe a déjà un compte.

    -
    - -
    - -
    -

    Bienvenue sur le site d'inscription du TFJM2 !

    -
    - -
    - Ce site a été conçu pour gérer les inscriptions au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens. -
    - Cliquez ici pour accéder au site de présentation du tournoi. -
    - -
    - - -

    - Attention aux échéances ! Chaque tournoi a une date limite pour les inscriptions et une date limite pour déposer vos solutions. Elles sont affichées avec les informations de chaque tournoi. Merci de vous y référer ! -
    - Une fois l'échéance passée, le site bloque tout accès aux inscriptions (et respectivement au dépôt des solutions).
    -

    - -

    - Attention, modification du règlement par rapport aux années précédentes : article 4.3 -
    - "l’équipe doit envoyer par mail à contact@tfjm.org, une lettre (au format pdf), répondant aux questions suivantes : -
    - -

      -
    • Comment l’équipe s’est-elle formée ?
    • -
    • Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres avec l’encadrant•e) ?
    • -
    - - Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non l’inscription des équipes concernées par cette lettre." -
    - - Pour plus de détail, voir le règlement : https://tfjm.org/infos-tournois/ -

    - - -
    -

    Comment ça marche ?

    -
    - -

    - Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer par la suite. -

    - -

    - Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : -

      -
    • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
    • -
    • enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière version enregistrée avant - la date limite sera prise en compte pour le tournoi).
    • -
    - - Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, votre inscription pourra être validée par les organisateurs locaux. -

    - - -

    ATTENTION ! Votre équipe ne sera considérée comme admissible à participer au tournoi que lorsque cette première étape aura été franchie.

    - -

    Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes seront placées en liste d'attente. -

    - -

    - Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers le site pour compléter votre inscription. -

    - - -

    ATTENTION ! Les équipes qui ne respecteront pas les délais pour rendre ces documents risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente.

    - -

    - NB : Ce site est récent et il est encore possible que certaines pages ne fonctionnent pas correctement. Si vous remarquez des bugs, merci de les signaler à l'adresse contact@tfjm.org. -

    - - - - - - - - - -
    +
    \ No newline at end of file From ca1a9e441517d8da50cb4df5aa7b2145cb3fefcc Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sun, 8 Sep 2019 01:47:30 +0200 Subject: [PATCH 052/120] =?UTF-8?q?Correction=20d'un=20probl=C3=A8me?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/tournoi.php | 1 + server_files/views/tournoi.php | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 36d9e46..5d516eb 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -14,6 +14,7 @@ if (isset($_POST["edit_tournament"])) { } $orgas = $tournament->getOrganizers(); $teams = $tournament->getAllTeams(); +$orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); function updateTournament() { global $DB, $URL_BASE, $YEAR, $tournament, $orgas; diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 904f671..6bcd1d5 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -123,7 +123,7 @@ else {
    diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index a1ddb8f..b1cd39b 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -4,25 +4,25 @@ Nom de l'équipe : getName() ?>
    Trigramme : getTrigram() ?>
    - Tournoi : getName() ?>">getName() ?>
    + Tournoi : getName() ?>">getName() ?>
    getEncadrants()[$i] == NULL) continue; $encadrant = User::fromId($team->getEncadrants()[$i - 1]); $id = $encadrant->getId(); - echo "Encadrant $i : getFirstName() . " " . $encadrant->getSurname() . "\">" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "
    "; + echo "Encadrant $i : getFirstName() . " " . $encadrant->getSurname() . "\">" . $encadrant->getFirstName() . " " . $encadrant->getSurname() . "
    "; } for ($i = 1; $i <= 6; ++$i) { if ($team->getParticipants()[$i - 1] == NULL) continue; $participant = User::fromId($team->getParticipants()[$i - 1]); $id = $participant->getId(); - echo "Participant $i : getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
    "; + echo "Participant $i : getFirstName() . " " . $participant->getSurname() . "\">" . $participant->getFirstName() . " " . $participant->getSurname() . "
    "; } if ($team->isSelectedForFinal()) { $final_name = $FINAL->getName(); - echo "Équipe sélectionnée pour la finale nationale."; + echo "Équipe sélectionnée pour la finale nationale."; } ?> diff --git a/server_files/views/header.php b/server_files/views/header.php index f07fee0..584ff64 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -5,8 +5,8 @@ Site d'inscription pour le TFJM² <?= $YEAR ?> - - + + @@ -23,36 +23,36 @@ - + From 60344b896a011f3e568ac2eceea5404bd0183a8e Mon Sep 17 00:00:00 2001 From: Hadrien RENAUD Date: Sun, 8 Sep 2019 22:20:00 +0200 Subject: [PATCH 059/120] :whale: Edit docker-compose env Signed-off-by: Hadrien RENAUD --- docker-compose.yml | 4 ++++ setup.sql | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index f8abd58..e18902d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,3 +30,7 @@ services: TFJM_DB_USER: plateforme TFJM_DB_NAME: plateforme TFJM_DB_PASSWORD: plateforme + TFJM_YEAR: 2020 + TFJM_URL_BASE: / + TFJM_LOCAL_PATH: /var/www/html + TFJM_MAIL_DOMAIN: localhost diff --git a/setup.sql b/setup.sql index 471a5d9..d0e5af8 100644 --- a/setup.sql +++ b/setup.sql @@ -19,8 +19,8 @@ SET time_zone = "+02:00"; -- -- Base de données : `tfjm` -- -CREATE DATABASE IF NOT EXISTS `tfjm` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -USE `tfjm`; +CREATE DATABASE IF NOT EXISTS `plateforme` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; +USE `plateforme`; -- -------------------------------------------------------- From 722fad4e6fe5dc7ebd955035dfe5297b7e85ecc3 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sun, 8 Sep 2019 22:54:57 +0200 Subject: [PATCH 060/120] =?UTF-8?q?Correction=20de=20probl=C3=A8mes=20mine?= =?UTF-8?q?urs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/classes/Tournament.php | 2 +- server_files/classes/User.php | 2 +- server_files/controllers/inscription.php | 2 +- server_files/model.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server_files/classes/Tournament.php b/server_files/classes/Tournament.php index 8b2cff0..102fb10 100644 --- a/server_files/classes/Tournament.php +++ b/server_files/classes/Tournament.php @@ -289,7 +289,7 @@ class Tournament global $DB; $req = $DB->query("SELECT * FROM `documents` AS `t1` " - . "INNER JOIN (SELECT `user`, `type`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `tournament`, `team`, `type`) `t2` " + . "INNER JOIN (SELECT `user`, `type`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `tournament`, `team`, `type`, `user`) `t2` " . "ON `t1`.`user` = `t2`.`user` AND `t1`.`type` = `t2`.`type` AND `t1`.`tournament` = `t2`.`tournament` " . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $this->id " . ($team_id == -1 ? "" : "AND `t1`.`team` = $team_id") . " ORDER BY `t1`.`team`, `t1`.`type`;"); diff --git a/server_files/classes/User.php b/server_files/classes/User.php index 1852ea7..b037e12 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -364,7 +364,7 @@ class User { global $DB; $req = $DB->query("SELECT * FROM `documents` AS `t1` " - . "INNER JOIN (SELECT `user`, `type`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `tournament`, `type`) `t2` " + . "INNER JOIN (SELECT `user`, `type`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `documents` GROUP BY `tournament`, `type`, `user`) `t2` " . "ON `t1`.`user` = `t2`.`user` AND `t1`.`type` = `t2`.`type` AND `t1`.`tournament` = `t2`.`tournament` " . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $tournament_id AND `t1`.`user` = $this->id ORDER BY `t1`.`type`;"); diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 1db055c..0d3f454 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -50,7 +50,7 @@ class NewUser ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); $this->email = strtolower($this->email); - ensure(userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); + ensure(!userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); ensure($this->surname != "", "Le nom de famille est obligatoire."); diff --git a/server_files/model.php b/server_files/model.php index ed0005d..b0004c4 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -57,7 +57,7 @@ function quitTeam() { if ($role == Role::ADMIN || $role == Role::ORGANIZER) return; - for ($i = 1; $i <= ($role == Role::ENCADRANT ? 6 : 2); ++$i) + for ($i = 1; $i <= ($role == Role::ENCADRANT ? 2 : 6); ++$i) /** @noinspection SqlResolve */ $DB->exec("UPDATE `teams` SET `" . strtolower(Role::getName($role)) . "_$i` = NULL WHERE `" . strtolower(Role::getName($role)) . "_$i` = $user_id;"); $user->setTeamId(null); From fbabdff69c7df2a0052d1ecd577f340ba80d937c Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Sun, 8 Sep 2019 23:10:59 +0200 Subject: [PATCH 061/120] Configuration du Dockerfile et support de l'envoi de mails --- Dockerfile | 31 +++++++++++++++++++++++++- server_files/services/mail.php | 4 ++-- setup.sql => setup/create_database.sql | 4 ++-- setup/msmtprc | 18 +++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) rename setup.sql => setup/create_database.sql (98%) create mode 100644 setup/msmtprc diff --git a/Dockerfile b/Dockerfile index 04f51b8..e6e897f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,37 @@ FROM php:7.3-apache as plateforme-builder +# Enabling apache rewrite mod RUN a2enmod rewrite +RUN apt clean && apt update && apt upgrade -y + +# Install MySQL drivers RUN docker-php-ext-install pdo_mysql \ && docker-php-ext-enable pdo_mysql -COPY . /var/www/html/ +# Install zip utilities +RUN apt install -y libzip-dev zip \ + && docker-php-ext-configure zip --with-libzip \ + && docker-php-ext-install zip \ + && docker-php-ext-enable zip + +# Setup locales +RUN apt install locales locales-all -y && locale-gen fr_FR.UTF-8 +ENV LANG fr_FR.UTF-8 +ENV LANGUAGE fr_FR:fr +ENV LC_ALL fr_FR.UTF-8 + +# Setup timezone +RUN echo Europe/Paris > /etc/timezone \ + && ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime \ + && dpkg-reconfigure -f noninteractive tzdata + +# Setup mailing +RUN apt install -yq msmtp ca-certificates +COPY setup/msmtprc /etc/msmtprc +RUN echo "sendmail_path=msmtp -t" >> /usr/local/etc/php/conf.d/php-sendmail.ini + +# Setting environment +ENV TFJM_LOCAL_PATH /var/www/html +ENV TFJM_MAIL_DOMAIN tfjm.org +ENV TFJM_URL_BASE https://inscription.tfjm.org diff --git a/server_files/services/mail.php b/server_files/services/mail.php index 51b2adb..7f6d871 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -9,8 +9,8 @@ class Mailer $content = preg_replace("#{URL_BASE}#", $URL_BASE, $content); $content = preg_replace("#{YEAR}#", $YEAR, $content); - $headers = "From: " . $from . "@" . $MAIL_DOMAIN . "\r\n"; - $headers .= "Reply-To: contact@" . $MAIL_DOMAIN . "\r\n"; + $headers = "From: \"Contact TFJM²\" <" . $from . "@" . $MAIL_DOMAIN . ">\r\n"; + $headers .= "Reply-To: \"Contact TFJM²\" \r\n"; $headers .= "Content-Type: text/html; charset=UTF-8\r\n"; mail($email, $subject, $content, $headers); diff --git a/setup.sql b/setup/create_database.sql similarity index 98% rename from setup.sql rename to setup/create_database.sql index 471a5d9..d885d4f 100644 --- a/setup.sql +++ b/setup/create_database.sql @@ -19,8 +19,8 @@ SET time_zone = "+02:00"; -- -- Base de données : `tfjm` -- -CREATE DATABASE IF NOT EXISTS `tfjm` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -USE `tfjm`; +CREATE DATABASE IF NOT EXISTS `inscription-tfjm` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; +USE `inscription-tfjm`; -- -------------------------------------------------------- diff --git a/setup/msmtprc b/setup/msmtprc new file mode 100644 index 0000000..3a3cc60 --- /dev/null +++ b/setup/msmtprc @@ -0,0 +1,18 @@ +defaults +auth on +tls on +tls_starttls off +tls_trust_file /etc/ssl/certs/ca-certificates.crt +syslog on +logfile /var/log/msmtp.log + +account tfjm +host ssl0.ovh.net +auth on +port 465 +from contact@tfjm.org +user contact@tfjm.org +passwordeval "echo $TFJM_MAIL_PASSWORD" + +# Set a default account +account default : tfjm From 190039a5e8f864183b1c7ea35443c33f900ed5f5 Mon Sep 17 00:00:00 2001 From: galaxyoyo Date: Mon, 9 Sep 2019 00:41:52 +0200 Subject: [PATCH 062/120] =?UTF-8?q?Am=C3=A9lioration=20du=20code=20de=20la?= =?UTF-8?q?=20page=20de=20connexion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatcher.php | 3 + docker-compose.yml | 32 --- server_files/controllers/ajouter_equipe.php | 5 +- .../controllers/ajouter_organisateur.php | 5 +- server_files/controllers/connexion.php | 228 +++++++++++------- server_files/controllers/equipe.php | 10 +- server_files/controllers/inscription.php | 2 +- server_files/controllers/mon_compte.php | 2 +- server_files/controllers/mon_equipe.php | 13 +- server_files/controllers/solutions.php | 10 +- server_files/controllers/syntheses.php | 10 +- server_files/services/mail.php | 2 +- .../mail_templates/forgotten_password.html | 5 +- server_files/utils.php | 21 +- server_files/views/connexion.php | 181 +++++++------- 15 files changed, 270 insertions(+), 259 deletions(-) delete mode 100644 docker-compose.yml diff --git a/dispatcher.php b/dispatcher.php index 11112a6..23abe0a 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -29,6 +29,9 @@ $ROUTES["^ajouter_equipe$"] = ["server_files/controllers/ajouter_equipe.php"]; $ROUTES["^ajouter_organisateur$"] = ["server_files/controllers/ajouter_organisateur.php"]; $ROUTES["^ajouter_tournoi$"] = ["server_files/controllers/ajouter_tournoi.php"]; $ROUTES["^confirmer_mail/([a-z0-9]*)/?$"] = ["server_files/controllers/confirmer_mail.php", "token"]; +$ROUTES["^connexion/(confirmation-mail)/?$"] = ["server_files/controllers/connexion.php", "confirmation-mail"]; +$ROUTES["^connexion/(mdp_oublie)/?$"] = ["server_files/controllers/connexion.php", "mdp_oublie"]; +$ROUTES["^connexion/(reinitialiser_mdp)/(.*)/?$"] = ["server_files/controllers/connexion.php", "reset_password", "token"]; $ROUTES["^connexion/?$"] = ["server_files/controllers/connexion.php"]; $ROUTES["^deconnexion/?$"] = ["server_files/controllers/deconnexion.php"]; $ROUTES["^equipe/([A-Z]{3})/?$"] = ["server_files/controllers/equipe.php", "trigram"]; diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index f8abd58..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,32 +0,0 @@ -version: '3' -services: - db: - image: mysql:5 - command: --default-authentication-plugin=mysql_native_password - restart: always - environment: - MYSQL_ROOT_PASSWORD: mysql_root_password - MYSQL_DATABASE: plateforme - MYSQL_USER: plateforme - MYSQL_PASSWORD: plateforme - - adminer: - image: adminer - restart: always - ports: - - 8888:8080 - depends_on: - - db - - plateforme: - build: - context: . - ports: - - 80:80 - depends_on: - - db - environment: - TFJM_DB_HOST: db - TFJM_DB_USER: plateforme - TFJM_DB_NAME: plateforme - TFJM_DB_PASSWORD: plateforme diff --git a/server_files/controllers/ajouter_equipe.php b/server_files/controllers/ajouter_equipe.php index f3a25c1..6043bcd 100644 --- a/server_files/controllers/ajouter_equipe.php +++ b/server_files/controllers/ajouter_equipe.php @@ -46,10 +46,7 @@ class NewTeam { public function register() { global $DB, $YEAR; - $alphabet = "0123456789abcdefghijkmnopqrstuvwxyz0123456789"; - $this->access_code = ""; - for ($i = 0; $i < 6; ++$i) - $this->access_code .= $alphabet[rand(0, strlen($alphabet) - 1)]; + $this->access_code = genRandomPhrase(6); $req = $DB->prepare("INSERT INTO `teams` (`name`, `trigram`, `tournament`, `encadrant_1`, `participant_1`, `validation_status`, `access_code`, `year`) VALUES (?, ?, ?, ?, ?, ?, ?, ?);"); diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index 469c4c8..dbb81b7 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -44,10 +44,7 @@ class NewOrganizer { public function register() { global $DB, $YEAR; - $alphabet = "0123456789abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - $this->password = ""; - for ($i = 0; $i < 16; ++$i) - $this->password .= $alphabet[rand(0, strlen($alphabet) - 1)]; + $this->password = genRandomPhrase(16, true); $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) VALUES (?, ?, ?, ?, ?, ?);"); diff --git a/server_files/controllers/connexion.php b/server_files/controllers/connexion.php index 862b51f..2fe94b2 100644 --- a/server_files/controllers/connexion.php +++ b/server_files/controllers/connexion.php @@ -1,120 +1,170 @@ makeVerifications(); + $logging_in_user->login(); + } catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } } if (isset($_POST["forgotten_password"]) && !isset($_SESSION["user_id"])) { - $error_message = recuperateAccount(); + $recuperate_account = new RecuperateAccount($_POST); + try { + $recuperate_account->makeVerifications(); + $recuperate_account->recuperateAccount(); + } catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } } if (isset($_GET["reset_password"]) && isset($_GET["token"]) && !isset($_SESSION["user_id"])) { - $reset_data = $DB->query("SELECT `id` FROM `users` WHERE `forgotten_password` = '" . htmlspecialchars($_GET["token"]) . "';")->fetch(); - if ($reset_data === FALSE) { - header("Location: $URL_BASE/connexion"); - exit(); - } - - if (isset($_POST["reset_password"])) - $error_message = resetPassword(); -} - -if (isset($_GET["confirmation-mail"]) && !isset($_SESSION["user_id"])) { - $error_message = sendConfirmEmail(); -} - -function login() { - global $URL_BASE; - - $email = htmlspecialchars($_POST["email"]); - - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) - return "L'email entrée est invalide."; - - $password = htmlspecialchars($_POST["password"]); - - $user = User::fromEmail($email); - if ($user === null) - return "Le compte n'existe pas."; - - if ($user->getConfirmEmailToken() !== NULL) { - $_SESSION["confirm_email"] = $email; - return "L'adresse mail n'a pas été validée. Veuillez vérifier votre boîte mail (surtout vos spams). Cliquez ici pour renvoyer le mail de confirmation."; + $reset_password = new ResetPassword($_GET, $_POST); + try { + $reset_password->makeVerifications(); + if (isset($_POST["password"])) + $reset_password->resetPassword(); + } catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); } - - if (!$user->checkPassword($password)) - return "Le mot de passe est incorrect."; - - $_SESSION["user_id"] = $user->getId(); - loadUserValues(); - - return false; } -function recuperateAccount() { - $email = htmlspecialchars($_POST["email"]); - - if (!filter_var($email, FILTER_VALIDATE_EMAIL)) - return "L'email entrée est invalide."; - - $user = User::fromEmail($email); - if ($user == null) - return "Le compte n'existe pas."; - - $token = uniqid(); +if (isset($_GET["confirmation-mail"]) && !isset($_SESSION["user_id"])) + sendConfirmEmail(); - $user->setForgottenPasswordToken($token); +class LoggingInUser +{ + public $email; + /** @var User $user */ + public $user; + private $password; - Mailer::sendForgottenPasswordProcedureMail($user); - - return false; + public function __construct($data) + { + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + } + + public function makeVerifications() + { + global $URL_BASE; + + ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse email est invalide."); + $this->user = User::fromEmail($this->email); + ensure($this->user != null, "Le compte n'existe pas."); + ensure($this->user->checkPassword($this->password), "Le mot de passe est incorrect."); + if ($this->user->getConfirmEmailToken() != null) { + $_SESSION["confirm_email"] = $this->email; + throw new AssertionError("L'adresse mail n'a pas été validée. Veuillez vérifier votre boîte mail (surtout vos spams). " + . "Cliquez ici pour renvoyer le mail de confirmation."); + } + } + + public function login() + { + $_SESSION["user_id"] = $this->user->getId(); + loadUserValues(); + } } -function resetPassword() { - global $reset_data; +class RecuperateAccount +{ + public $email; + /** @var User $user */ + public $user; - $id = $reset_data["id"]; - $password = htmlspecialchars($_POST["password"]); - $confirm = htmlspecialchars($_POST["confirm_password"]); - - if (strlen($password) < 8) - return "Le mot de passe doit comporter au moins 8 caractères."; - - if ($password != $confirm) - return "Les deux mots de passe sont différents."; + public function __construct($data) + { + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + } - $user = User::fromId($id); - $user->setForgottenPasswordToken(null); - $user->setPassword($password); + public function makeVerifications() + { + ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse email est invalide."); + $this->user = User::fromEmail($this->email); + ensure($this->user != null, "Le compte n'existe pas."); + } - Mailer::sendChangePasswordMail($user); - - return false; + public function recuperateAccount() + { + $token = genRandomPhrase(64); + $this->user->setForgottenPasswordToken($token); + Mailer::sendForgottenPasswordProcedureMail($this->user); + } } -function sendConfirmEmail() { +class ResetPassword +{ + public $token; + /** @var User $user */ + public $user; + private $password; + private $confirm_password; + + public function __construct($data, $data2) + { + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + foreach ($data2 as $key => $value) + $this->$key = htmlspecialchars($value); + } + + public function makeVerifications() + { + global $DB; + $data = $DB->query("SELECT `id` FROM `users` WHERE `forgotten_password` = '" . $this->token . "';")->fetch(); + ensure($data !== false, "Il n'y a pas de compte à récupérer avec ce jeton."); + $this->user = User::fromId($data["id"]); + + if ($this->password == null) + return; + + ensure($this->password == $this->confirm_password, "Les deux mots de passe sont différents."); + ensure(strlen($this->password) >= 8, "Le mot de passe doit comporter au moins 8 caractères."); + } + + public function resetPassword() + { + $this->user->setForgottenPasswordToken(null); + $this->user->setPassword($this->password); + + Mailer::sendChangePasswordMail($this->user); + + return false; + } +} + +function sendConfirmEmail() +{ global $URL_BASE; - - $email = htmlspecialchars($_SESSION["confirm_email"]); - - if (!isset($email)) { - header("Location: $URL_BASE/connexion"); - exit(); - } - $user = User::fromEmail($email); - - if ($user === null) { - unset($_SESSION["confirm_email"]); + $email = htmlspecialchars($_SESSION["confirm_email"]); + + if (!isset($email)) { header("Location: $URL_BASE/connexion"); exit(); - } + } + + $user = User::fromEmail($email); + + if ($user === null) { + unset($_SESSION["confirm_email"]); + header("Location: $URL_BASE/connexion"); + exit(); + } Mailer::sendConfirmEmail($user); - - return false; + + return false; } require_once "server_files/views/connexion.php"; diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 1f52f94..6bc8409 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -24,14 +24,8 @@ if (isset($_POST["select"])) { $sols_req->execute([$team->getId(), $team->getTournamentId()]); while (($sol_data = $sols_req->fetch()) !== false) { $old_id = $sol_data["file_id"]; - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } + do + $id = genRandomPhrase(64); while (file_exists("$LOCAL_PATH/files/$id")); copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 0d3f454..3f1462a 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -73,7 +73,7 @@ class NewUser } } - $this->confirm_email_token = uniqid(); + $this->confirm_email_token = genRandomPhrase(64); } public function register() diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index a41261b..9db09e9 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -92,7 +92,7 @@ function updateAccount() $email = htmlspecialchars($_POST["email"]); if (isset($email) && $email != "" && filter_var($email, FILTER_VALIDATE_EMAIL)) { - $confirm_email_token = uniqid(); + $confirm_email_token = genRandomPhrase(64); $user->setEmail($email); $user->setConfirmEmailToken($confirm_email_token); diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php index 8dd4d8c..0f17104 100644 --- a/server_files/controllers/mon_equipe.php +++ b/server_files/controllers/mon_equipe.php @@ -56,15 +56,10 @@ function sendDocument() if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } while (file_exists("$LOCAL_PATH/files/$id")); + + do + $id = genRandomPhrase(64); + while (file_exists("$LOCAL_PATH/files/$id")); if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) return "Une erreur est survenue lors de l'envoi du fichier."; diff --git a/server_files/controllers/solutions.php b/server_files/controllers/solutions.php index 34f471d..e1fa85e 100644 --- a/server_files/controllers/solutions.php +++ b/server_files/controllers/solutions.php @@ -42,14 +42,8 @@ function saveSolution() { if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } + do + $id = genRandomPhrase(64); while (file_exists("$LOCAL_PATH/files/$id")); if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) diff --git a/server_files/controllers/syntheses.php b/server_files/controllers/syntheses.php index 65a2327..3a8fb9d 100644 --- a/server_files/controllers/syntheses.php +++ b/server_files/controllers/syntheses.php @@ -38,14 +38,8 @@ function saveSynthesis() { if (!is_dir("$LOCAL_PATH/files") && !mkdir("$LOCAL_PATH/files")) return "Les droits sont insuffisants. Veuillez contacter l'administrateur du serveur."; - $alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - - do { - $id = ""; - for ($i = 0; $i < 64; ++$i) { - $id .= $alphabet[rand(0, strlen($alphabet) - 1)]; - } - } + do + $id = genRandomPhrase(64); while (file_exists("$LOCAL_PATH/files/$id")); if (!rename($file["tmp_name"], "$LOCAL_PATH/files/$id")) diff --git a/server_files/services/mail.php b/server_files/services/mail.php index 7f6d871..18be95b 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -38,7 +38,7 @@ class Mailer { global $YEAR; - $content = self::getTemplate("register"); + $content = self::getTemplate("confirm_email"); $content = preg_replace("#{FIRST_NAME}#", $user->getFirstName(), $content); $content = preg_replace("#{SURNAME}#", $user->getSurname(), $content); $content = preg_replace("#{TOKEN}#", $user->getConfirmEmailToken(), $content); diff --git a/server_files/services/mail_templates/forgotten_password.html b/server_files/services/mail_templates/forgotten_password.html index 1041695..18c187d 100644 --- a/server_files/services/mail_templates/forgotten_password.html +++ b/server_files/services/mail_templates/forgotten_password.html @@ -1,4 +1,5 @@ + @@ -7,8 +8,8 @@ Bonjour,

    -Vous avez indiqué avoir oublié votre mot de passe. Veuillez cliquer ici pour le réinitialiser : -$URL_BASE/connexion/reinitialiser_mdp/{TOKEN}
    +Vous avez indiqué avoir oublié votre mot de passe. Veuillez cliquer ici pour le réinitialiser : {URL_BASE}/connexion/reinitialiser_mdp/{TOKEN}

    Si vous n'êtes pas à l'origine de cette manipulation, vous pouvez ignorer ce message.

    diff --git a/server_files/utils.php b/server_files/utils.php index 342a268..e0a26f5 100644 --- a/server_files/utils.php +++ b/server_files/utils.php @@ -1,17 +1,32 @@ Erreur : " . $error_message . ""; - -if (isset($error_message) && $error_message === FALSE) { - if (isset($_GET["mdp_oublie"])) - echo "Le mail de récupération de mot de passe a bien été envoyé."; - else if (isset($_POST["reset_password"])) - echo "Le mot de passe a bien été changé. Vous pouvez désormais vous connecter."; - else if (isset($_GET["confirmation-mail"])) - echo "Le mail a bien été renvoyé."; - else - echo "Connexion réussie !"; +if ($has_error) + echo "

    Erreur : " . $error_message . "

    "; +else { + if (isset($recuperate_account)) + echo "

    Le mail de récupération de mot de passe a bien été envoyé.

    "; + elseif (isset($reset_password)) + echo "

    Le mot de passe a bien été changé. Vous pouvez désormais vous connecter.

    "; + elseif (isset($_GET["confirmation-mail"])) + echo "

    Le mail a bien été renvoyé.

    "; + else if (isset($logging_in_user)) { + echo "

    Connexion réussie !

    "; + require_once "footer.php"; + } else if (isset($_SESSION["user_id"])) { + echo "

    Vous êtes déjà connecté.

    "; + require_once "footer.php"; + } } -else if (isset($_SESSION["user_id"])) { ?> -

    Vous êtes déjà connecté !

    +if (isset($_GET["mdp_oublie"])) { ?> + +
    LieuNom Dates Inscription avant le Date de rendu des solutions
    ">Du au getName() ?>Du getStartDate()) ?> au getEndDate()) ?>getSolutionsDate()) ?>getSynthesesDate()) ?>getSize() ?>
    ">Du au
    LieuNom Dates Inscription avant le Date de rendu des solutions
    - Mot de passe oublié ? + Mot de passe oublié ?
    organize($_SESSION["user_id"])))) - echo "getTrigram() . "\">" . $team->getName(). ""; + echo "getTrigram() . "\">" . $team->getName(). ""; else echo $team->getName(); ?> diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index e631025..783fce1 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -17,7 +17,7 @@ foreach ($tournaments as $tournament) { ?>
    getName() ?>getName() ?> Du getStartDate()) ?> au getEndDate()) ?> getSolutionsDate()) ?> getSynthesesDate()) ?>
    + + + + + + + + + +
    + + + +
    + +
    + +user != null) { ?> +
    + + + + + + + + + + + + + + +
    + + + +
    + + + +
    + +
    +
    + - - -
    - - - - - - - - - - -
    - - - -
    - -
    -
    - -
    - " /> - - - - - - - - - - - - - - -
    - - - -
    - - - -
    - -
    -
    - - -
    - - - - - - - - - - - - - - - - -
    - - Mot de passe oublié ? -
    -
    - +
    + + + + + + + + + + + + + + + + +
    + + Mot de passe oublié ? +
    +
    \ No newline at end of file From d691b3c84931573657d35ade4d354670e24452c2 Mon Sep 17 00:00:00 2001 From: Hadrien RENAUD Date: Mon, 9 Sep 2019 00:58:53 +0200 Subject: [PATCH 063/120] :lipstick: Add navbar --- assets/style.css | 82 ++--------------- server_files/config.php | 16 ++-- server_files/views/footer.php | 2 - server_files/views/header.php | 164 ++++++++++++++++++++-------------- 4 files changed, 111 insertions(+), 153 deletions(-) diff --git a/assets/style.css b/assets/style.css index bf10db5..3a2b5f9 100644 --- a/assets/style.css +++ b/assets/style.css @@ -1,80 +1,8 @@ -body { - display: flex; +:root { + --navbar-height: 32px; } -html, body { - height: 100%; - width: 100%; - margin: 0; -} - -#menu { - list-style-type: none; - margin: 0; - padding: 0; - width: 220px; - background-color: #f1f1f1; - height: 100%; - overflow: auto; - flex-grow: 0; -} - -#menu a { +#navbar-logo { + height: var(--navbar-height); display: block; - color: #000; - padding: 10px 20px; - text-decoration: none; -} - -#menu a.active { - background-color: #4CAF50; - color: white; -} - -#menu a:hover:not(.active) { - background-color: #555; - color: white; -} - -#menu-logo img { - width: calc(100% - 40px); - margin: 40px auto; - display: block; -} - -#main-container { - margin: 0; - flex-grow: 1; - height: 100%; - overflow-y: scroll; -} - -#main-content { - padding-top: 100px; - padding-bottom: 100px; - margin: 0 auto; - max-width: 1000px; - text-align: justify; -} - -@media only screen and (max-width: 700px) { - body { - flex-direction: column; - height: auto; - } - #menu { - height: auto; - width: 100%; - padding-bottom: 20px; - } - #menu-logo img { - height: 70px; - padding-left: 7px; - } - #menu a { - text-align: center; - } - #main-content { - padding: 100px 16px; - } -} +} \ No newline at end of file diff --git a/server_files/config.php b/server_files/config.php index a57349b..99b7008 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -3,10 +3,10 @@ * Config options */ -$YEAR = $_ENV["TFJM_YEAR"]; -$URL_BASE = $_ENV["TFJM_URL_BASE"]; -$LOCAL_PATH = $_ENV["TFJM_LOCAL_PATH"]; -$MAIL_DOMAIN = $_ENV["TFJM_MAIL_DOMAIN"]; +$YEAR = getenv("TFJM_YEAR"); +$URL_BASE = getenv("TFJM_URL_BASE"); +$LOCAL_PATH = getenv("TFJM_LOCAL_PATH"); +$MAIL_DOMAIN = getenv("TFJM_MAIL_DOMAIN"); // TODO Remove $MAIL_ADDRESS = "contact@" . $MAIL_DOMAIN; @@ -14,10 +14,10 @@ $MAIL_ADDRESS = "contact@" . $MAIL_DOMAIN; * DB infos */ -$DB_HOST = $_ENV["TFJM_DB_HOST"]; -$DB_NAME = $_ENV["TFJM_DB_NAME"]; -$DB_USER = $_ENV["TFJM_DB_USER"]; -$DB_PASSWORD = $_ENV["TFJM_DB_PASSWORD"]; +$DB_HOST = getenv("TFJM_DB_HOST"); +$DB_NAME = getenv("TFJM_DB_NAME"); +$DB_USER = getenv("TFJM_DB_USER"); +$DB_PASSWORD = getenv("TFJM_DB_PASSWORD"); try { $DB = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8", "$DB_USER", "$DB_PASSWORD", array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); diff --git a/server_files/views/footer.php b/server_files/views/footer.php index 078caa7..5181ba3 100644 --- a/server_files/views/footer.php +++ b/server_files/views/footer.php @@ -1,5 +1,3 @@ -
    -
    diff --git a/server_files/views/header.php b/server_files/views/header.php index 584ff64..fb7d9f5 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -1,76 +1,108 @@ - - - - Site d'inscription pour le TFJM² <?= $YEAR ?> + + + Site d'inscription pour le TFJM² <?= $YEAR ?> - + - - - - - - - - - - - + + - + + +
    + -
    -
    -
    \ No newline at end of file +
    \ No newline at end of file From 5004e1fb14b0bf33ac7339cb6b1ee8e85c57de79 Mon Sep 17 00:00:00 2001 From: Hadrien RENAUD Date: Mon, 9 Sep 2019 01:00:36 +0200 Subject: [PATCH 064/120] :lipstick: Ajout d'une vraie home page Signed-off-by: Hadrien RENAUD --- server_files/views/index.php | 209 +++++++++++++++++------------------ 1 file changed, 99 insertions(+), 110 deletions(-) diff --git a/server_files/views/index.php b/server_files/views/index.php index 3e92e36..0c0b9fd 100644 --- a/server_files/views/index.php +++ b/server_files/views/index.php @@ -1,126 +1,115 @@ - -
    +
    - From eb2fb734c69bf54e193597984afaeb132f2c4e09 Mon Sep 17 00:00:00 2001 From: Hadrien RENAUD Date: Mon, 9 Sep 2019 01:15:02 +0200 Subject: [PATCH 065/120] :lipstick: Rework on tournois.php Signed-off-by: Hadrien RENAUD --- server_files/views/tournois.php | 74 +++++++++++++++++---------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index 783fce1..8e7a7b6 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -1,41 +1,45 @@ -

    Liste des tournois

    +
    +

    Liste des tournois

    +
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
    NomDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    getName() ?>Du getStartDate()) ?> au getEndDate()) ?>getSolutionsDate()) ?>getSynthesesDate()) ?>getSize() ?>
    NomDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NomDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    + getName() ?> + Du getStartDate()) ?> au getEndDate()) ?>getSolutionsDate()) ?>getSynthesesDate()) ?>getSize() ?>
    NomDatesInscription avant leDate de rendu des solutionsPlaces disponibles
    From 49a2fbe83eec6d10b8ccd654be16b5abe12d43e7 Mon Sep 17 00:00:00 2001 From: Hadrien RENAUD Date: Mon, 9 Sep 2019 01:50:26 +0200 Subject: [PATCH 066/120] :lipstick: Remold the old inscription form Signed-off-by: Hadrien RENAUD --- server_files/views/inscription.php | 273 ++++++++++++++++------------- 1 file changed, 153 insertions(+), 120 deletions(-) diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index 7abb639..25f981c 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -2,136 +2,169 @@ require_once "header.php"; if ($has_error) - echo "

    Erreur : " . $error_message . "

    "; + echo "
    Erreur : " . $error_message . "
    "; ?> +
    +

    Formulaire d'inscription

    +
    + - Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. + ?> +
    + Votre inscription est validée ! Merci désormais de confirmer votre boîte mail pour valider votre adresse. +
    -

    Vous êtes déjà connecté !

    +
    Vous êtes déjà connecté !
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    -
    /> - />
    " required/>
    -
    - -
    - -
    -
    + +
    + + +
    + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + +
    +
    + /> + +
    +
    + /> + +
    +
    +
    + + +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + " required/> +
    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    +
    + + + +
    +
    + + + + +
    +
    + + + + +
    + +
    + +
    + + + +
    + +
    + +
    getValidationStatus() == ValidationStatus::WAITING) { ?>
    @@ -62,6 +88,7 @@ if ($payment->getValidationStatus() == ValidationStatus::NOT_READY) { ?> Informations sur le paiement : getTransactionInfos() ?>
    + Date: Sat, 18 Jan 2020 17:26:12 +0100 Subject: [PATCH 091/120] =?UTF-8?q?G=C3=A9n=C3=A9ration=20automatique=20de?= =?UTF-8?q?s=20fichiers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 3 + assets/Autorisation_droit_image_majeur.tex | 113 ++++++++++++++++ assets/Autorisation_droit_image_mineur.tex | 122 ++++++++++++++++++ assets/Autorisation_parentale.tex | 66 ++++++++++ assets/Fiche_sanitaire.pdf | Bin 0 -> 54296 bytes assets/Instructions.tex | 88 +++++++++++++ assets/logo_animath.png | Bin 0 -> 106600 bytes dispatcher.php | 5 + .../controllers/autorisation_droit_image.php | 52 ++++++++ .../controllers/autorisation_parentale.php | 44 +++++++ server_files/controllers/instructions.php | 36 ++++++ server_files/views/mon_compte.php | 15 ++- server_files/views/tournoi.php | 4 + 13 files changed, 544 insertions(+), 4 deletions(-) create mode 100644 assets/Autorisation_droit_image_majeur.tex create mode 100644 assets/Autorisation_droit_image_mineur.tex create mode 100644 assets/Autorisation_parentale.tex create mode 100644 assets/Fiche_sanitaire.pdf create mode 100644 assets/Instructions.tex create mode 100644 assets/logo_animath.png create mode 100644 server_files/controllers/autorisation_droit_image.php create mode 100644 server_files/controllers/autorisation_parentale.php create mode 100644 server_files/controllers/instructions.php diff --git a/Dockerfile b/Dockerfile index e6e897f..7bfdd64 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,6 +15,9 @@ RUN apt install -y libzip-dev zip \ && docker-php-ext-install zip \ && docker-php-ext-enable zip +# Install LaTeX utilities +RUN apt update && apt upgrade -y && apt install -yq texlive texlive-base texlive-binaries texlive-lang-french + # Setup locales RUN apt install locales locales-all -y && locale-gen fr_FR.UTF-8 ENV LANG fr_FR.UTF-8 diff --git a/assets/Autorisation_droit_image_majeur.tex b/assets/Autorisation_droit_image_majeur.tex new file mode 100644 index 0000000..7cb1727 --- /dev/null +++ b/assets/Autorisation_droit_image_majeur.tex @@ -0,0 +1,113 @@ +\documentclass[a4paper,french,11pt]{article} + +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{lmodern} +\usepackage[frenchb]{babel} + +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{amsmath} +\usepackage{amssymb} +%\usepackage{anyfontsize} +\usepackage{fancybox} +\usepackage{eso-pic,graphicx} +\usepackage{xcolor} + + +% Specials +\newcommand{\writingsep}{\vrule height 4ex width 0pt} + +% Page formating +\hoffset -1in +\voffset -1in +\textwidth 180 mm +\textheight 250 mm +\oddsidemargin 15mm +\evensidemargin 15mm +\pagestyle{fancy} + +% Headers and footers +\fancyfoot{} +\lhead{} +\rhead{} +\renewcommand{\headrulewidth}{0pt} +\lfoot{\footnotesize 11 rue Pierre et Marie Curie, 75231 Paris Cedex 05\\ Numéro siret 431 598 366 00018} +\rfoot{\footnotesize Association agréée par\\le Ministère de l'éducation nationale.} + +\begin{document} + +\includegraphics[height=2cm]{assets/logo_animath.png}\hfill{\fontsize{55pt}{55pt}{$\mathbb{TFJM}^2$}} + +\vfill + +\begin{center} + + +\LARGE +Autorisation d'enregistrement et de diffusion de l'image ({TOURNAMENT_NAME}) +\end{center} +\normalsize + + +\thispagestyle{empty} + +\bigskip + + + +Je soussign\'e {PARTICIPANT_NAME}\\ +demeurant au {ADDRESS} + +\medskip +Cochez la/les cases correspondantes.\\ +\medskip + + \fbox{\textcolor{white}{A}} Autorise l'association Animath, \`a l'occasion du $\mathbb{TFJM}^2$ du {START_DATE} au {END_DATE} {YEAR} à : {PLACE}, \`a me photographier ou \`a me filmer et \`a diffuser les photos et/ou les vid\'eos r\'ealis\'ees \`a cette occasion sur son site et sur les sites partenaires. D\'eclare c\'eder \`a titre gracieux \`a Animath le droit d’utiliser mon image sur tous ses supports d'information : brochures, sites web, r\'eseaux sociaux. Animath devient, par la pr\'esente, cessionnaire des droits pendant toute la dur\'ee pour laquelle ont \'et\'e acquis les droits d'auteur de ces photographies.\\ + +\medskip +Animath s'engage, conform\'ement aux dispositions l\'egales en vigueur relatives au droit \`a l'image, \`a ce que la publication et la diffusion de l'image ainsi que des commentaires l'accompagnant ne portent pas atteinte \`a la vie priv\'ee, \`a la dignit\'e et \`a la r\'eputation de la personne photographiée.\\ + +\medskip + \fbox{\textcolor{white}{A}} Autorise la diffusion dans les medias (Presse, T\'el\'evision, Internet) de photographies prises \`a l'occasion d’une \'eventuelle m\'ediatisation de cet événement.\\ + + \medskip + +Conform\'ement \`a la loi informatique et libert\'es du 6 janvier 1978, vous disposez d'un droit de libre acc\`es, de rectification, de modification et de suppression des donn\'ees qui vous concernent. +Cette autorisation est donc r\'evocable \`a tout moment sur volont\'e express\'ement manifest\'ee par lettre recommand\'ee avec accus\'e de r\'eception adress\'ee \`a Animath, IHP, 11 rue Pierre et Marie Curie, 75231 Paris cedex 05.\\ + +\medskip + \fbox{\textcolor{white}{A}} Autorise Animath à conserver mes données personnelles, dans le cadre défini par la loi n 78-17 du 6 janvier 1978 relative à l'informatique, aux fichiers et aux libertés et les textes la modifiant, pendant une durée de quatre ans à compter de ma dernière participation à un événement organisé par Animath.\\ + + \medskip + \fbox{\textcolor{white}{A}} J'accepte d'être tenu informé d'autres activités organisées par l'association et ses partenaires. + +\bigskip + +Signature pr\'ec\'ed\'ee de la mention \og lu et approuv\'e \fg{} + +\medskip + + + +\begin{minipage}[c]{0.5\textwidth} + +\underline{L'\'el\`eve :}\\ + +Fait \`a :\\ +le +\end{minipage} + + +\vfill +\vfill +\begin{minipage}[c]{0.5\textwidth} +\footnotesize 11 rue Pierre et Marie Curie, 75231 Paris Cedex 05\\ Numéro siret 431 598 366 00018 +\end{minipage} +\begin{minipage}[c]{0.5\textwidth} +\footnotesize +\begin{flushright} +Association agréée par\\le Ministère de l'éducation nationale. +\end{flushright} +\end{minipage} +\end{document} diff --git a/assets/Autorisation_droit_image_mineur.tex b/assets/Autorisation_droit_image_mineur.tex new file mode 100644 index 0000000..4f14a43 --- /dev/null +++ b/assets/Autorisation_droit_image_mineur.tex @@ -0,0 +1,122 @@ +\documentclass[a4paper,french,11pt]{article} + +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{lmodern} +\usepackage[frenchb]{babel} + +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{amsmath} +\usepackage{amssymb} +%\usepackage{anyfontsize} +\usepackage{fancybox} +\usepackage{eso-pic,graphicx} +\usepackage{xcolor} + + +% Specials +\newcommand{\writingsep}{\vrule height 4ex width 0pt} + +% Page formating +\hoffset -1in +\voffset -1in +\textwidth 180 mm +\textheight 250 mm +\oddsidemargin 15mm +\evensidemargin 15mm +\pagestyle{fancy} + +% Headers and footers +\fancyfoot{} +\lhead{} +\rhead{} +\renewcommand{\headrulewidth}{0pt} +\lfoot{\footnotesize 11 rue Pierre et Marie Curie, 75231 Paris Cedex 05\\ Numéro siret 431 598 366 00018} +\rfoot{\footnotesize Association agréée par\\le Ministère de l'éducation nationale.} + +\begin{document} + +\includegraphics[height=2cm]{assets/logo_animath.png}\hfill{\fontsize{55pt}{55pt}{$\mathbb{TFJM}^2$}} + +\vfill + +\begin{center} + + +\LARGE +Autorisation d'enregistrement et de diffusion de l'image +({TOURNAMENT_NAME}) +\end{center} +\normalsize + + +\thispagestyle{empty} + +\bigskip + + + +Je soussign\'e \dotfill (p\`ere, m\`ere, responsable l\'egal) \\ +agissant en qualit\'e de repr\'esentant de {PARTICIPANT_NAME}\\ +demeurant au {ADDRESS} + +\medskip +Cochez la/les cases correspondantes.\\ +\medskip + + \fbox{\textcolor{white}{A}} Autorise l'association Animath, \`a l'occasion du $\mathbb{TFJM}^2$ du {START_DATE} au {END_DATE} {YEAR} à : {PLACE}, \`a photographier ou \`a filmer l'enfant et \`a diffuser les photos et/ou les vid\'eos r\'ealis\'ees \`a cette occasion sur son site et sur les sites partenaires. D\'eclare c\'eder \`a titre gracieux \`a Animath le droit d’utiliser l'image de l'enfant sur tous ses supports d'information : brochures, sites web, r\'eseaux sociaux. Animath devient, par la pr\'esente, cessionnaire des droits pendant toute la dur\'ee pour laquelle ont \'et\'e acquis les droits d'auteur de ces photographies.\\ + +\medskip +Animath s'engage, conform\'ement aux dispositions l\'egales en vigueur relatives au droit \`a l'image, \`a ce que la publication et la diffusion de l'image de l'enfant ainsi que des commentaires l'accompagnant ne portent pas atteinte \`a la vie priv\'ee, \`a la dignit\'e et \`a la r\'eputation de l’enfant.\\ + +\medskip + \fbox{\textcolor{white}{A}} Autorise la diffusion dans les medias (Presse, T\'el\'evision, Internet) de photographies de mon enfant prises \`a l'occasion d’une \'eventuelle m\'ediatisation de cet événement.\\ + + \medskip + +Conform\'ement \`a la loi informatique et libert\'es du 6 janvier 1978, vous disposez d'un droit de libre acc\`es, de rectification, de modification et de suppression des donn\'ees qui vous concernent. +Cette autorisation est donc r\'evocable \`a tout moment sur volont\'e express\'ement manifest\'ee par lettre recommand\'ee avec accus\'e de r\'eception adress\'ee \`a Animath, IHP, 11 rue Pierre et Marie Curie, 75231 Paris cedex 05.\\ + +\medskip + \fbox{\textcolor{white}{A}} Autorise Animath à conserver mes données personnelles, dans le cadre défini par la loi n 78-17 du 6 janvier 1978 relative à l'informatique, aux fichiers et aux libertés et les textes la modifiant, pendant une durée de quatre ans à compter de ma dernière participation à un événement organisé par Animath.\\ + + \medskip + \fbox{\textcolor{white}{A}} J'accepte d'être tenu informé d'autres activités organisées par l'association et ses partenaires. + + \bigskip + +Signatures pr\'ec\'ed\'ees de la mention \og lu et approuv\'e \fg{} + +\medskip + + +\begin{minipage}[c]{0.5\textwidth} + +\underline{Le responsable l\'egal :}\\ + +Fait \`a :\\ +le : + +\end{minipage} +\begin{minipage}[c]{0.5\textwidth} + +\underline{L'\'el\`eve :}\\ + +Fait \`a :\\ +le +\end{minipage} + + +\vfill +\vfill +\begin{minipage}[c]{0.5\textwidth} +\footnotesize 11 rue Pierre et Marie Curie, 75231 Paris Cedex 05\\ Numéro siret 431 598 366 00018 +\end{minipage} +\begin{minipage}[c]{0.5\textwidth} +\footnotesize +\begin{flushright} +Association agréée par\\le Ministère de l'éducation nationale. +\end{flushright} +\end{minipage} +\end{document} diff --git a/assets/Autorisation_parentale.tex b/assets/Autorisation_parentale.tex new file mode 100644 index 0000000..6c56ac4 --- /dev/null +++ b/assets/Autorisation_parentale.tex @@ -0,0 +1,66 @@ +\documentclass[a4paper,french,11pt]{article} + +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{lmodern} +\usepackage[french]{babel} + +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{amsmath} +\usepackage{amssymb} +%\usepackage{anyfontsize} +\usepackage{fancybox} +\usepackage{eso-pic,graphicx} +\usepackage{xcolor} + + +% Specials +\newcommand{\writingsep}{\vrule height 4ex width 0pt} + +% Page formating +\hoffset -1in +\voffset -1in +\textwidth 180 mm +\textheight 250 mm +\oddsidemargin 15mm +\evensidemargin 15mm +\pagestyle{fancy} + +% Headers and footers +\fancyfoot{} +\lhead{} +\rhead{} +\renewcommand{\headrulewidth}{0pt} +\lfoot{\footnotesize 11 rue Pierre et Marie Curie, 75231 Paris Cedex 05\\ Numéro siret 431 598 366 00018} +\rfoot{\footnotesize Association agréée par\\le Ministère de l'éducation nationale.} + +\begin{document} + +\includegraphics[height=2cm]{assets/logo_animath.png}\hfill{\fontsize{55pt}{55pt}{$\mathbb{TFJM}^2$}} + +\vfill + +\begin{center} +\Large \bf Autorisation parentale pour les mineurs ({TOURNAMENT_NAME}) +\end{center} + +Je soussigné(e) \hrulefill,\\ +responsable légal, demeurant \writingsep\hrulefill\\ +\writingsep\hrulefill,\\ +\writingsep autorise {PARTICIPANT_NAME},\\ +né(e) le {BIRTHDAY}, +à participer au Tournoi Français des Jeunes Mathématiciennes et Mathématiciens ($\mathbb{TFJM}^2$) organisé \`a : {PLACE}, du {START_DATE} au {END_DATE} {YEAR}. + +{PRONOUN} se rendra au lieu indiqu\'e ci-dessus le vendredi matin et quittera les lieux l'après-midi du dimanche par ses propres moyens et sous la responsabilité du représentant légal. + + + +\vspace{8ex} + +Fait à \vrule width 10cm height 0pt depth 0.4pt, le \phantom{232323}/\phantom{XXX}/{YEAR}, + +\vfill +\vfill + +\end{document} diff --git a/assets/Fiche_sanitaire.pdf b/assets/Fiche_sanitaire.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b828b9d7e45882ad06a54278929b12aa576ae360 GIT binary patch literal 54296 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 C<@G%P literal 0 HcmV?d00001 diff --git a/assets/Instructions.tex b/assets/Instructions.tex new file mode 100644 index 0000000..ac686ac --- /dev/null +++ b/assets/Instructions.tex @@ -0,0 +1,88 @@ +\documentclass[a4paper,french,11pt]{article} + +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{lmodern} +\usepackage[frenchb]{babel} + +\usepackage{fancyhdr} +\usepackage{graphicx} +\usepackage{amsmath} +\usepackage{amssymb} +%\usepackage{anyfontsize} +\usepackage{fancybox} +\usepackage{eso-pic,graphicx} +\usepackage{xcolor} +\usepackage{hyperref} + + +% Specials +\newcommand{\writingsep}{\vrule height 4ex width 0pt} + +% Page formating +\hoffset -1in +\voffset -1in +\textwidth 180 mm +\textheight 250 mm +\oddsidemargin 15mm +\evensidemargin 15mm +\pagestyle{fancy} + +% Headers and footers +\fancyfoot{} +\lhead{} +\rhead{} +\renewcommand{\headrulewidth}{0pt} +\lfoot{\footnotesize 11 rue Pierre et Marie Curie, 75231 Paris Cedex 05\\ Numéro siret 431 598 366 00018} +\rfoot{\footnotesize Association agréée par\\le Ministère de l'éducation nationale.} + +\begin{document} + +\includegraphics[height=2cm]{assets/logo_animath.png}\hfill{\fontsize{50pt}{50pt}{$\mathbb{TFJM}^2$}} + + + +\begin{center} +\Large \bf Instructions ({TOURNAMENT_NAME}) +\end{center} + +\section{Documents} +\subsection{Autorisation parentale} +Elle est nécessaire si l'élève est mineur au moment du tournoi (y compris si son anniversaire est pendant le tournoi). + +\subsection{Autorisation de prise de vue} +Si l'élève est mineur \textbf{au moment de la signature}, il convient de remplir l'autorisation pour les mineurs. En revanche, s'il est majeur \textbf{au moment de la signature}, il convient de remplir la fiche pour majeur. + +\subsection{Fiche sanitaire} +Elle est nécessaire si l'élève est mineur au moment du tournoi (y compris si son anniversaire est pendant le tournoi). + + +\section{Paiement} + +\subsection{Montant} +Les frais d'inscription sont fixés à {PRICE} euros. Vous devez vous en acquitter \textbf{avant le {END_PAYMENT_DATE} {YEAR}}. Si l'élève est boursier, il en est dispensé, vous devez alors fournir une copie de sa notification de bourse directement sur la plateforme \textbf{avant le {END_PAYMENT_DATE} {YEAR}}. + +\subsection{Procédure} + +Si le paiement de plusieurs élèves est fait en une seule opération, merci de contacter \href{mailto: contact@tfjm.org}{contact@tfjm.org} \textbf{avant le paiement} pour garantir l'identification de ce dernier + +\subsubsection*{Carte bancaire (uniquement les cartes françaises)} +Le paiement s'effectue en ligne via la plateforme à l'adresse : \url{https://www.apayer.fr/ANIMATH} + +Vous devez impérativement indiquer dans le champ "Référence" la mention "TFJMpu" suivie des noms et prénoms \textbf{de l'élève}. + +\subsubsection*{Virement} +\textbf{Si vous ne pouvez pas utiliser le paiement par carte}, vous pouvez faire un virement sur le compte ci-dessous en indiquant bien dans le champ "motif" (ou autre champ propre à votre banque dont le contenu est communiqué au destinataire) la mention "TFJMpu" suivie des noms et prénoms \textbf{de l'élève}. + +IBAN FR76 1027 8065 0000 0206 4290 127 + +BIC CMCIFR2A + +\subsubsection*{Autre} + +Si aucune de ces procédures n'est possible pour vous, envoyez un mail à \href{mailto: contact@tfjm.org}{contact@tfjm.org} pour que nous trouvions une solution à vos difficultés. + + + + +\end{document} diff --git a/assets/logo_animath.png b/assets/logo_animath.png new file mode 100644 index 0000000000000000000000000000000000000000..da4533ee3695392417e3db8afc4b9852fddc1cd2 GIT binary patch literal 106600 zcmYIv1yodF*Y%yDo1r^KQluNC2k8=|Q(B}YB!?bAloXIgP(eDSQMyyQQ@XqU(f9w} zcX3&>=B~N*-1D5X_dffH)Kpi%!=}Op002)(5%wGaP(T0x;>1Kp?$O+T?TY*Wxj$Es z1xf~Kwvb=YU#cj;fQP?-*-c*)kbAIP6b;+~Ahq}JKWH^B4~pE0@kU8a9%BxL9Giw- zzNE$v02lxzn2e71%x;EPBgy*NgVg5JO5cNgY&Or4?9O0`ZEjww0X=#7@(WX73zO`L zmL+-8!cWtYDI6#ZmEfn`myu04%FeZm^KUaxZY(oxZMZ1Z#(>NVl{#x%ug$^!{Y>}F zp(`3`t>!S|!L0azz)j22xx>TC(k!|FI+rsEA2^A;*5A!qZ7qcndEXJI)b4T@0hTvA zkbnE-4Vo+@P8ht)^r6&t0g2 z69pqPlNa7^I*Crw3EJI?bsnk%R6rua{^B#b#?)npctpK6cfA2YVlG=0a$^DYe)@GP z)q(?jb7VVE&d!32@IejLrITmszxace&K(9}CfW&fPyT!Q-xdc{8$%|j2{qNq zJZLFr#QzM={`W?5?TE6A_HWlqP5_|eTNw^&2GHKa+4B;Bgkma$?rF5F=}OrB`ytyW zR5l0jMBQp?9Tij+Kwv^;`;Cc>Chw-)S*tPNMx|mV1RwwVblbf>CUJP^J4jw==XM392Iot^sXzjWOGxdQ8F{NSS($Wq)#$JH;+J$q^@G`-+%zpyp z@5M6ob;qOuLZe!4h@&*DngKusg>ff-3t?c8#e?j*Ne{)D9PV4aJ)0joV|e`Ufr?fr zBv6$zxfj#7@acIhOg864Q4J#yRPxe*$QBL@g8_sPfVH1NE0TZ{$$-5raw-2iN(sb& z2IIR(JyCYvn;B;|AiE^Tl^hVKl#7Nj8DJbD9Az=0#+rCT~Y(A2WNNFZ85{Br;(t=_r8-~ijLoj)@Vu+_1`5G~R zxxle$iZ^%uKAQhKgY^cNF*-11`#sC4H#8(BCk#x12?7UU`bm{tHYoD(!x;d|jhU$) z*X5&y`$GD6)4lJlB+CAGu-HVs_Msc^9iT;3B}?P;PlASLW*zZ zvZQwLfvf?8BC@Lg9ZaQwOQXO&@6Y(2MxdD(;)${Zxb+mrQ{ydFf(SwJ6zCw-I2bJx z1N0S>tncQW7I4_37oARL@!xQK@$S>iGZdiOBSwL0BPQ~jSiyBdUb+A1Wtspc>qqJM ze*AEzCJ<8qCmi98#eeWO&Kd%5*M7ULplP2maQt@^9wSEq*5CM6aqgs7{4s7?Q><$2 zd*XpWKCCCNIiQLCxQA-LDt-|KArR7tZ)DP}FJ~}-{pR~8x1MvKeaim#;?Xv^^ufU8 z%k!0{)=M;gPD04J3BUwpV7L-CpgcqgL4z?|8n?3IX2T>&AY;#g8;>1{FA~7*(bRfYu-hg?ktbpFe!_ zQ5*_0)4mkZb985Hrk=o+WRzb*Obo{;D7Rr9#yG=R%bTm*DY+P?e-n7(i;r65^dIPu z$$5l43$8^@`#@0J;62`kOlRL&KRg^cnlG&Opb;JgFc^|c`^zD}?n8817qokn?|6AcOo&KN^GC(9i~Oc^$|nCW1?Ze}WQQg?CA| zY}J~=B$><0UtL)2Aco$G=QIBA9T_BD{kCtTfY0uXTQm{;5k0meyw~NLWll;8yGrW# zMV&-Caw|*nV$t(#t9tRx!=|$o!O-IUz=yk)*(~#+JuwHO>|5un!)BE-*G*TE9|tK9 z(UuLOK~%C2rFj+sh)sWcDXeSeWJW^24Ip<;2uy^Dc*#PvGgm&;aySy>dr%#gE_SLr z7cjr&1OAtX4c6_n4C4HXA9LB}&ZpQ@%6XeI(_P+TI;sT&Lm zUVF)m;w-UU`hgkA;Y^uXOg(u^On9+*8(GAC>-$P|bzlHO1$slW!~k409nN&Qtrib0 z&5d1566gHQd%ch4U&x06t!H=Y*FO%*3aTZWBmFI{rX!@d1QhwSXceAGv*;J3Ko!!k znB3F@@HHXQLDFY0NW)4&0u$qcPxfZq*JvR2@1Ul}k7qTCJbpVG>IO8a-%K3by^K)r z8x(OnIF_2}@(sURrR&2{c#3cs51T2}njyDZBB5Yxj!Pieuk!0D zK$vexpOd#I>>c=Aotz1tMZZgq2GS8ah8%qWjj;b{tJk@NgGgqEn7&5n zKY;N4$xW8v?R`|#pGkldCw`OZ93vj902O$*^e#nS)07lMt^9dGBp+aKQ!k{+Qw$C! zDEWw`3Dp#>@l18Mi-I~4#%c7fdz;G3TUf~R`WT^}7}m0JHM`FgHV`K0}R zFTMM);^ogqllSxFoi5eH!p>XA;p-jUi4CvIe;$`7r%(M@Sv-vDrQ}XN!E6qi{4<6CO0L0_$)8c@db84!qG5_5(o&60W2`D@8y9jnOiKk|B-b z^ycsx8##w{NmTH-6m7HmcHj4aIAE7rfKln5@FuNK^&1|DERF(%072W(!>7_joL=HO zLc!Wm^SpziZqPW3LZ|tP6?bUimEZn~D8?z(5ha8ZWT&L9JzZ`8;%x4b<@KPy=!LKY z(cz=zy$>6Civ*w%|IvRnRXO*>K`|2qIR#b<)POtC8< zzJ2m?7ck#2nY?H{csS;|cfN2uZT|-kjzioR)LPn5_)R-DhnS#YGG7G_^sEj!2#vsq zN|y-CL^7Cv!FZQ+&wRW1HvwvaScgnpNP>3^;gyv%0}PCnlT3IOpcYH0gat&9hBGld zf`u1$5Mtze#=SKG2@$c16Kkn#<}t*^^ZJp(Y)ZUw1+XsT4wt%BKmZbY&ioP;9f#Ru zN<({gT}Gg`5E3Dchex?q@64wpWf!76qMHk0~>5T zQ8_J>=**V7%s36VwC+UM!E5~CRm%*Vzp-U#o<}^(dcjmH2JSUYUSrTv3H6PNqrAKP zaZeBC=nJZ1T~cUG7;1U%Y%hgl`SUp`Q_XW^-cLb*_l zR8458NDsqr!h4+VTCC9LcF)@`a+;DAFTa3~Jhui|s=_-^kLq#HwR9C9^Rad^IV;{{ z$w(1KEBbCSMP=MjLrPM4x6;XfE&5Hh9(h~oWZ87dB*5v>sKJ-mEtFTWS33=6x7GRx zA=JEQ(pxFqy+j7bCe1`#y@aDU-T8Xic}?K>{PxJ^fzo&DG{Mp^t0E6t*xL410=h}* zChT7(2#i3BE_9u+u3as6y&GG+vssh-;WjKxFeSDX%uY-Gq+q|jKO^O>C0Hza=_|t< zNL&qJd#4LAaS~I(usAq9HnC~E^C1EIUM`jd?9z*|V{e>9^4#Ag5$9sekr+#JUmf## zPUB4XCVh9U?XRy?_gCMGJa+Uq@6newC=-V2I3F&up1yg!-?(3t^gfyeBn5s?AwowG zvmJsmL{}}va3SA04zeS}WVLq?lYa6e>^h$*uS81H=o^Wm3e+%uy~^}zHH*V|XqG^(9QdK&YP~3ThWd{o9urWy4;}EXc6c4Ohk_RC9EbY$^&Lhk zJ`Ff*tISe;;Y=-qNbf*K!WrHWv62E*@0P^?yt-j#tg^^<9PcRtIS)k>0==kY=|u9& z&;TXwBS@K^no51pnsGQxzv7v>QbYxdr>w=EbgWV>B|~yyC}v!B$>+)nict0!q#e8j zANDJs&_w$W{(v|dy;zAGxobYsw?`(8T!#-3FLLY+bLbPY*w4cQX{u<&igX4; z(cko;+#A+L-)=-d^fO@iZ+!TcE0w0ZW5R=BX_@R9%cMa%18hg@ z_@%Od+ZHzYy0yE^5ZPSFc1l@*s3$AP`%80JLuA~=50MBRB4TnJ2*6&?RKgC? zdIW#lnWrW8mj0gU8RQt-?&uT3{D%JVc{3gTli?u08z;my79lyy*Nt~%{9&l;g%9JZ zqH*?j?(tbkCSi@gvCU=HV0ld*zb5KhC{{SWXi%MgExVKaI8D z9<%SP<;u3xi?EV1K(RAxdyvsjtog-AZo{s6j$)?HC~IU^LNuUtwkt~t?E-%+74(;0 zReTv;t(ZO9z^FW$yx{@?PmgY&%)Obd{J~$Kiy;q3gA;S7%mvtcv|YRI3UR<1M}GQ0 zb5??->5}xHPxM?vT~u`*lcI9tggK#8EjjjASH3iy${cM$pF*Aix#jzvsuFuPwLJAWuFMfx+Td;`E;12q)jgA3it6#yq08MxNdp%UPgj2 zjAuQSeRD2es#EWsKTYzvI4tvqd=Qxf9C%9a?%W&whK4Uw+*xZ%O6+H%Wf6H{ArJj4akB)cMEFl29}N*EF&Yq4CHM@ z4E$xR2JR^hc39!>y-{n;Byd}A062S#MD?@~#zB+z@r`{8w`$;eh$EHC`k;{KERxQC z)D?aWgVEx|ZQ&|9fIeY<6YduT_n+}%*XgipG`k$gx!co)vVQiFgC`{H-7Gx~os*d& zreo`uCw2a%)D4p}Elc<Uov2-=x{hkunklyr`Iiz)JFH!dRhkEf+~GlC-Pq#hRi(Px0= zzFN^2H9hN&v}>ZoIfMGNf9+>&c-Jlx8sEj`IQ2hOSQ7LI-cT_Sjh-{Nlh4+NiHWe5 z^8C4EWx@ZpH(@J~Nh2k#@lV1lvU%5XAli6&-L+U(*mAWmXZO|Y%|c-g`vPx`lL}<| zJwk{fx29i5UfLHz0tgUlqd>M9TmV&~e4NeSVg?L!&z!6)Z0G}Qxx!@@($#o-SG zz*pb=J19gcP^_P2N*4C0u)C>8cYh#wHptG4h3J;jzMixA@oI)xx@TK4A5j%m><-YC zPvB*VdK@+YhkXg9!jtFXqx*F?8xJFOV@YtqM1{83K%OiJPjtwe0eD}9JTSEPvRF-F^)`2=G0W~%oplXQ>DJR3efxPr5lTB&-I66o42 zFm|y4Ho@y@{!_45Myp98(-Hi4MIuJZYI@+g5=Dne`nAY zJ)ifKfZy>t_^FuC(Nf^u{Pd4kqpLp}H7*F%a2nq~^s6{K^E;0mpCL(&w#^JYwLzex zMw=v+3woU3wi}AcY{NwA6<@59sCSw`W(&m+{8s9oiD_vDV# z`3xFShI=j456}7s1kOU9W9~1o@dlf zi`?BKK&$lvNvkn^<+JZGsRJbf?QIDs-oKkxWpIej4nk0+{K&+t9PvZwZkH3lLwK@+ zukxLF@|JS4DA#VfWxH=uHOVHvu7p&L)J_vaOP6ITJ;IB&KRnUvW~McWCmbKR8Vqh1 z=swWV-TXREBtP1cFxqrc;gF>o>KwnQr@uKP!!s-MtcLBGHXYTx^V_MfayKy@pDl0h z^oRjzU+{z-66y*_UCi7#lR!-|q$T|5;elbIdEqaXttr0Tghw@1ad(|}AW@sBz*|yG z&!^kijaN(7J!wC)k7j=h3*40x%Ht`bI|=w!YjV+QC_tE0e8C7;-3g+l;IAzB=|#3G ze-USMAQ$BcW(m~^+u?HYV*Nb3+*eQi=O(qu#BXYJJ<+WEq1&yhNvK7f(xh-7upo~% zC!7yJ5A}bMbpjI7TA*Mh9#bsLin~Q!u+k@g9;tySVgG8VzIkyy&VXgZCxM?cZCo;r z#zt+MNPStoLO9O!J}!wEkuGIdsLbo@DxU4_W-GS~qt)Ysg){j?`U z5(EAqe!^0DrZG`z$t`*0+d%e)*&NSmCLyq+eBQGS$Jy_V2)`q)OflgVN1Pk?k1`SY zt0F<~@J~}>ToeiDe_#Xdoe|H@-`=#EJ~H!wit}m7y|PZjum4!Z@g;SgYzZI|vQn}3 zrGobWWoD&XDWdk-nbQ9zmN13?rYf$;TPXzQds@E8!X2s}9#<2&$jp|#Mn1s!_e0s6 zn~S!L~5kl_jo@p(4Hk?qtepncSBYw#F6_5jKm4!wnm`f!Q zk%W9)=-T4ycJf<(8j8Vn$LLU$q^Yd%wSWbtYRw%2Q3@< zKB~Obx*l3Q^;mz1bm$b$N2t}=jUT;>Q&w7s^8FV33!1B?MaWM>jvY)U&p`=t`HfnQ zcho!_b4T4W#7O?QaDK6Pa+ZsnZ=KphEny+&3v_^au>==iKf`0e234#rzjsR>q+AbH z#cF^is5QM%H_R5)`eqAsbHUCbLC-tyR6LvZsM1(kRcS!V)+eorB3_S8iwljL@(W(W z8J))xG7+kmMy14Eq5V^Ak2#G6t}TrDmt6erf6L<5ErZ_G9lSlQzkT1h%kujm8ngbK zYD5%TDYHArqSa2_HL+)&A`}hZQ(hN==01BFg%hp<6amac`ms+?;?DBr!U23D>oHmX zJ_q$Y?t%8s#DqUCYu-IdL!_7~KH=@>c zMj{n+e~C>lh+ZTiaGfXXw`*>k#C(-RoM|s8gU$BlDD?=Q9%D3otYS6CvmDY6m*-w^ z4QLGf07+JW5D4|3G}V@%(i?M6m4ja@3p&;rw4f4q)r7h4XH#mUx7?cyy&azZTmo5Y z3|=P4$o{3WEPGBHZW2mfR%8yEm=R5FQ&o`S4QRDRwuCw?Ew8sC|8?8|N6)kf> z3%^ACt>a~Nsx7exlQ0Ack*_-syaLfG7KzYg8BSAQ`}~s8=lkou8y7zA8qeka0y#4J zVTU#TINkum)z(BdK1(|K$p?Ohkvp#iJ4f-W z+OI2B(N3L?lj&C>rbhKdW$3Q+YplFgw#Y)>Y$@b2v8Mo2vnR~Nuf>m)U>gIk&y^rv zI_#l?=ZJ~^5{=-7QnR<1-R~7l-wV?<(m=h#F>RT!q!pu?OQS!(M$;VS^}9E*!IG)r zOj_Lsp4tC{X17x!H&Nn8S9;OYJX+f98+r@3;}cC{gCIp>_-70awsAp$>gw_;4l*_0 z%|rLiISrYr6I*vOPd-(17CD%_5CRY&8iv6<7z~4TaB+#^qKx7DmLYk58CRz9+*>zO z8NvDfY~%DdJ^$wg=ny_x>-m78whEZd4@JWHe!si4H?`noz$r?@IUkeBOFTIxH=7xX zn$G#H59otC7+`Q6QJH)Z`vFxbR3$yTGtx*g+gkNh7;}A?uoI76{bQcxQ-VavkP}o{j2#|-W<5wEZ8bWsF`d|JuzG=S%m4loqlenSIiCZ$2F=s~ZCd86A3gn}?8_4^4ZKymue7 z-u%>=^SCqckwtcE5(V)gKkdmEqpqSqe(w87z0!&E<>g8~D~f?eIvV`W_nq+~j}T#; zT56poQdVFkbhN>BG~=4Z@7L*4<>l?@q`(L|>uA~DEtfS`-Tl7X9E;yGP&JTyHBKb8 zxR_QL0y~D@ZqRQ99};d6YYU-qc!TrrrA6lhY}V;}@8WTB6hHg*N_ao6JCYP%A;y9r zAlYFe1#apyeA*~*?u;cBi14I=Az)4h|8Ox?ezKE%zHfSBvbkLq?cCw0mz9ayA8uBw zj?asWlKt*ApX)aMT69`DqRMU1qipalGLl7-e?1-Jmt{%ABq5D&D;I_T2-d@igH{4u zFjNlXUEAl+H!CZ=7bitt8~a&L@~_ejMqN#&X<}k6Z0#EW!p*$TA^qD^IRm)Bl>6qu z(TMiqZF;SVyI6pKXG|DM!-4KXOBcdc-_98`YAr3|7IXhKCt;mnrPYuk47nPgQm^M3nE`~Dzu-}f zPm2}ssQyNM#UzIpx2%C?egJ20?$j_y=5l>C8kcI!5+-Ud)UO=;M5L)!AgxlRZlta% zxI<>dN!GO3O|4yK+yAkbLG791T04g7Y%khPZR*{aFD<|HGEUPzp zYqG5Okf`vGsGk+?K&IqYI`{GB(pI3$AUZ+X#A|g~MdW0Ox~z7aChB$(TER(QV_v(x zCoS@z7LOAJ!gWcb6X+;sg{w6ecM>h8{KnpYhy9}~?Vmp`{MLvuWbISHlYw&E}lRAxqc!%Q!WJ zU7U3MIv-XlZ=;favkzhT5f%a=>um~U0=09e<(>;U+!t{f+{d=AVOH`mLyJ~2zOkQ0Lkuwo zC)lAyQX>5LYF1~YNPmwepb40Fi0-75q+?RI(TlS>Q*C@mx%}<6OO{|BfMoof^(Xao zY6BmxB}K9)b2@pViQ}?fPsw!NZR8~l4n&2F9*fv6q75fL@ZT1Op=qwC7m*sxN@u&q zEgxy9QXKLEZ}vogz1eCEYT636Jo-huxf=H3&!^v=OM-Csh&z1Y%s>(#+vq@R5}@er zH?!tuJ>nOQzfZL~dm?bYX6grZ>@7FZ)q3(K@XhNMf)5lT@9C(1>oxCOc}ZR?H{Q28 zyGWPDt>T?v^;hXLjK1ayU+a3~o0U84mDuP=+Gp)hR4qP`E@s6Dr1K$#+#l+CXnzO) zMF=JL9W8g`HRHnlB}bHH*M#Wxn?c#DKLrlDk5l%1J7XMiI%LHyf0(paIcl>n1R?50 zSWTo6DUm5`U`;FrmTXY=7pB7q#g`rSs4INs{(OQQwr#1pC;s{hL{_&%HpgGWZ%Doz z3DJiq;q36cs;2}{Ur3~k6A~9 zrAZld#94nspS!7V$K+h3Cm106i(ZJU>M)$--z{&3X}HwIDSqbW90;mRepd zG98Sltr>KD78-Bi1eK*^*z6knC}XA69iAd#%So*2M8S~uaW$k;K?nt|-Q;I@s!}Z( zf0KRTDayeDvipdNdPRVu&el$-BrDCq1nS|>M^Qurja<(G@ziRQ6#{~fP=%88S{12H}F7(W1s)?VfR{PLhye@5vM zf;spOcgP*;Se)buJ&wX;=}&pec6QU%`4y-<&|fcgMwUbX=}jU-D(ewQ7A^^`;S=OD zek9FK8_UV{Hs^Yo{C=;4aR*tPR9`##TJ~#cyxV!`Z)xB*@qKq`nPXnVn7c0d)1~SWY^~y| z8M=Te^_u;yTA-NDlcVJetamzMak<2kQHWktpDxj>cc}{>if?9k{0+Hghin&~UZOy+ z)k%LHWWFU;*n6m?KNZ`Wuzkbr%7-30Wq2VN)LHFdAb7L@X`%wm@661CX>0W{iVaDQ zS`iE1Z#_ySKn?)G2lc8GHEUltUOot%FH+MQJKK(#AO|f z{?8t6kB(4G>(-BwJ%axYtl4J#2*GN#S4;b8Bnl`y^`n%=MYH9A&rX%;!S|~^ui8P! zpP?q{3GdgZs$<^S%ZI*~{l@gg5KM)zD~Rj|D+QZ9iY$Ns@I+MH z(XN|A9Ji1XW1=9|taU~=@~iN|k~NkfbQAnwEZc43#CC8zbt{@k+&DTv>X~T=_W+($ zh?!JtyxnC;Ko-nA!+i~g4Xa9lOMx%h_%=#o)Yj|5f(?)&pN1NZe#W9>y*1{!=-soi z+zPgQk&ow&hP_A=g>k{J2RT-xNA+>nfwXxpqRW7lI5Wd%FakK-;dkN-{9%pAxQY1A zb3yQZXh%8${yV+x`op?H=czl!1!Z-F`xKTmN`)S4eqp1)m4XX+Bkv;v3?@|L#0jmx zpH`Bi0+udMoNm7o0f3#iBe+Iljj!?K(%GUz0w;GG%Er={X(2k|fa31n#@@)wEP)f6 z=T_mVJ)McYl(b#{OycKX|3!;h%lCtyxAJ}VZyg`;Lk5hhR2RJexcMe!RZ&k}^e-0! zRqSM{U9whUNxerysDF%WJZrf(xEx7&8TnL!LPRUf?$9$m8Y(v!SV9Ro`Y9Egu-7`- zCcElLHh?}!+e1*VhH=31CA}b8O14R&^0e<=&}|`n?e@BI4i4aR(TWzRa~XDn!`kb` zJ&2YMbzo%x4JI#56xg0Im<)J~^^IJn*u7*Tavbu91KOyrdQe?b=zVok7oA*H_-g+0 zmJ_9AiR(v1cIZtHu zn##5`Y7lFd6u{CSNNxG{31Fz%$82lFhYYAKf}Y2iSHAeEnKtz9EgG6MSx31)6>xqa z3cgqvJ~5m5kWo92dGHkfsi4KuE{boAU$>}mH^sd`T_;-$|4%yA=awcd=A)Zy}v?J z;!|al)brGcPF0wRIbC!&u*+ISYvGa2s3X**9e+ZQF?e(1mGO1|u5+clJQc-U5~NRB zxB7{{Y-me(80j712Fj2Ss*vOT(;c3tA{7^}ZhS_V%mp`w11yjJOa+{G2dxUfwtM_Q zlU;9Y0l-C+Nkp^fs6PmAV><*gJIvbv^J4DXu@|6hdHH3tg=F#4ogiBL7O=CVAA6De zSj;j%0K4Do7o^u_FjCs3u4;$hFpl)Llt!dB_hf(3_O z1na~3cv67Z%G(6tjFulZX>5E_AgexwOkdkOS>BmY#00S`wHT|b)sK$|Dm)%~ncMi# zZY~Gc{Oo2WYy*yzKfa~6Iwz}+<#%qvu|3Xm_9jf5!%6{iQli4|rt%u8HC;{#GSlOA zF59|%C$I^Pz1f7a$J|K@OUX7b|uo@CoimMox%tLj^!qINk_(CZ{##aQ|o$FI9H8ISCa zf{;LN#oMM{kZ;76ko{Wd);KuJq4kXR8Hr((^vetf+u|Jw%VW`&)r{+315_9Edqcx% z`=#C|pX)C8Moa4z@1L*{PL%%IQ1{uUi;;!SpyplMCZYcm05kW_nIYM!tHPCp3N??>4YixFHuQRxV0s1+3?pr`)?6nP6jcq6Ge@tc0bUDE}Fh_#}odf%CL zwpw!K{mx*K)cu^&kBiPgGvC?+gSOAMU-91){1J4EwP=2q`Z4c7zNaCvZy_lZk_0rxsvxL`sX@CYbE)q+h9NxlqV6jItKU@dwG<=K%1W6^Mb+KcC+dx zG5HL2IflCs11s>4=Oa)^d;W>n^IFv`G)22zH5HGZIc~7F%bCJp21a}Qj4xQmU@hAA zF!kBDyfAt6I+yISVw$^3N$VjXB~be2wEsDWV>D8x$2YT)_Ims z?kwJN`eE=lDKTAJepADae8Z>DZrQ&R#Y>c}_wM~&iSK*Fep9*LZPu>dcQSb#Ac^#8ad}UMOglC4NW3Nmq}7{)HwYf0 zJUaW%H9iG^k&q&N4h)nfUK`A{s~g|de-oD?d(@vQXUp|gO2-01DocM*_Z9AFnoPnG zl)}tohHbB0w{a);cC|97`i{^$*k%Yr2VT8OtFQXT_J-^yS-#s`Cr>gq+8C-dt^!zg zcXMQ%s4Z+;G8C1m6X#_c6Gsorrs7N-4nih?8P4`&^-?y_R4D7!O;5u%YO&@uXcy%) z?=a~cQ?Vq6JeDakc3e$LfH)!V$p6^?n(?5)kGQ8e8Mgyzn{nT3S0aT!h8B``zusJP z2XBaMl2No(ru!+X+)S~b=2g2wd zV)n8cMbGK{n-Hf$;pA55Sx{32#hl)_!Ce(68)%e#neOYoc(NBAcXU+Kw&xZoogn&H?CuchhK@xJiX@+3Y@fX5a4bXtVsmW)blpZB)n1HK$H6RIHQI%*zRcEqgVNQZFAy_azM|(7|e8-Kq+D+9`ztVk&EOa%J(5|r&v0S zk2nzAjTJhU!oiKvyBBl7tH>EtL4zjKx?_ZFV}?A5Q*68}cISlUfu(~G8z@LUAr)oG zWM}TS`|t*hc;M}8pvplaj7)#aZ6(M(KvFE;1HU3e-@x6&P~$${WPIKat;cm;j z>{LalCs~FE`W#jB^gLtGu&Za4k!4BSCO{4*30gb*GR0L;#MVD=H-8?@YU1-;G_Zg2 z<~QMt>-U({$WW{bnXc-!v`+=3$kjS861BM+(Y%a((ea=9T5*Ht?Qpr#32%gPvE3is zLfWP$AOC_ups|s~jt;o=*X=(*i)s7!t(6K*NR#8U?E2To7U%nq6V2@Lnsl4h!S;HO zrwxWwMQzQ1%bPyyH&^m9+(_?4;sYe4w1J>4f-XXw-k);p;S~S(xZv{wngn-Q{;!hM zC>nyZ0WaL}u@UY4b8uLT*}1hV zzNP!Jpl~E+1Hk!ELcf zS>#UYE#)@VUA(Nt;JS(k@fbIjL*f>^<-8o>)smg~065YMe4j&jG=#8g&XZ74YRYUkvpque^%P*NGg)_pRDcy(ZFb?*WBq=b_ zc?aR*1nT)g0YflxoNl>?S{!ee1aI?0)`O87GqTCIp0yf!@?|NL+GiI*kO|MglG*q&h3YDuq^-Pi(INr)X0{jcQV5Vaa9K zakXFLjQ==#M^&LY1N-6}vMfOcmn?u;#gN6t@dlV9-*gPpM5C(P`{kwKEE^j__6~C}@Z#l`d>5jo5 zIUpf1+7aV9Ayund%_a%j2~P%cjz!}=)dg1GMWi z!l$7*Tx#-f#L*c3v$=AW9W7r{OE!(yT?2Nj6s$xGnoI1fD&^Eihq!U&P75r?(lBV_ zF~`%LOWvZ{=8uX^fQ9NFL$N954bLc)&ggE=CA z$4`~CANFjdFM5+*}JO zEL>S8h}o??OkpH;eNekb|BBQpvRr;$X}b)SF||JYE@(UKnjLzW*z+|Ga47#$Qzh@{ zZ-3)PbI{(O7M)N%ttrm(3MaeC9SjxVVU-DV2}-ciRdo__9F5rF*dFYC;)F>UM(#52Ltj}fuyW||AsF1^gIRB+;w)`J!fR@9m6>@G$t>n$iM?r?{;oY5-EOy!TLVG{>f*QW+m7ai2E4?=#9W@}?g21G|_H#W@IexXvPr zGk*BnG?5x{5!Ts2!BQV>*3n-)q}Xv5zzbO`88(QP1kyfeby5hx62}K+P|xd!b{}C6 zkd+cAy}bHWAWSb1zuqN?ws>e z4c{ywTqEZiNfzUemmdA;V)}Y5$O=KS6krA_Q$OeLpXD3DfPU*fmHc_nK#PX|Af#CE zKuHMFp*6bj1w_gw73X};wif&Dotn1ly>X;(@Qcm#>+{Y@H|H|@8wm@j_^Y|(#cr4` zAaN|1s8P5N^_!$#^O9Gi3CbuX4FsPf=)RI8S4AklUmeN{#;|REKU#z(vV6<_&A~2M z9Rv=RiVae>b2xLHu!TF;BrSm7q+B2)l` zJPjr@xC8ijNVM2ifqIDaqbSgZA1o@Dts8E=re3Wd{=nNI@>FwMrAUG9w`$?&p|s zQ&vGS@M^ZOgY{y5YUi`_Q>~W1=J|^v$kg&z>Xk1i@jdlOKrfj&sbX*yq$xW5N*1Y3 z9ZvnY7kPEq{_zYCx!(8o7Z103M6?yZI-7rpoYD6y_6a2cvUH?4@ zO6M|ixoS)8-NNQ6HO|nykJH-+x<}{=adqQ7oDhg}9QwKPm+=fnRfEJ>Qtwnvnps_j zH))ct!{2=bktza{G4H*W@yzD%!Q6h0g4z4b+tsuThn-I~#J@hG8h(JsL>3Uk#3Hkk z0P8lLK2<#EG}Ds<&OO=gj7ICP#T7CmJxYwq$JhbRQ&~-4wbe;O-+;N9FOtW5WeL-L zer<--j2K8H6xg(=A8bpxr zFjZO-ZeBxt^|WUHM2M3^YRWM}&Bn}ogAs4hgARX-AKiC%ic-#(E|0wQSV}<;tV>Ks zos5g|{k!vwGA!T)qTesbWm_xu{O);xa*nqJ)6I%c5S$N^+3yk^Ke0i^PSI1_X*+G|XJ<3kYuJ8uqII}Y&V@F$OGT=$L&Et^ilr`fr+m|g##MXj2kJmKd~SPWl{@h(F1 z+Ny(1Y#uis^`R|`8V?S3L9DahMB+TV7RcFrV&WBR9L=MZyQpzJLI`>uXLkvKV5&<` z7)ph}$%uM(V5ck)$#<3)2D@{?c#}pB`x$y!25C|o1SnG{YZh~b)@YP0levX#j)jkT z&kDyrWu$d=U39JbC~5%JaQC~{-@C>MANGEu;jz8$jiqaM^ zN)a!?h9?Y#TVC|_-qBG6oHtqyWx&RqcF&rOoc7)8> z`BPB_ja3s(*R9MPq_2_wrJPqI71z}q9N5J;{YFM{#YG+s;Hl^EkEkRm(}bE^pN}gh z4}=*r64%$CDnUB0;B%L&FdYWj1jKmPgdq4E22UEo zh7@NbraR>#nX~j^JGyjp(*L+0@1ab8;-=Qi{Fn9DKl0y;KK@Z|eLTo6hivZza7ou@ z^Xa_%KQF+-XEA-&2zk}trfhPlpihBqOl4l&3CQ{S_InIahH`(~dRVy$Y9)vRfYuG_ z>aHgM%gSs~f*e#Xi9rC} z_~sZ)zh?cJ&Ie^1%2IJe$Ch!o{?G|L_x-Tv1Wo@N}A${u?n0~T!2B?ZWyC3G!uY=NxZSHs0E-RbhwEcrUwZJ-Mm@e^R zNmKaZaUdk<2;Y710H2jWA)v%^VmIxUjjK+>?ZGNu@Bh*C6%0|e(YkwJXo;blp}V_l z=x(G-B$Vzhk&s4G>5v8i>24$i=|);Wy5Y`u?m7Qp_PqODYdx`^eF#>tlb8||l9tV? z0*AodXxn?Mq}F=yz|ByRb3}%|7a;VjCwpZIi>(9A)H|FtqK}+N=Wm36m=n_6@4q$n zzTX-RRnQHd7q+XjHoug7LuDd)%hciXA6BEvk)B_RP3qiQZQP5>{4o4i9)^)*1fmY? zA^@9ea;afm3?tz*d{=+&yka;y7JV$RF1`Q}ZKjmg-1WTVzT|8^m7e|~byy)@kAe z-ikXb+A_B`t0#GU@y7hmjaq%a^69dBQhdPJNT?gKSStEU{hKw_<>;~ds!VbwRW$Wt z`C;-1sgZS(Xhn$BG$U$Vz10^~-Wgm}3EPsF$u;jG6+P4SnvTh@nFjj<2nDEwe@Xf4 z=;W;x;yS3qm^x6ytcchaifKDo3+e=QEA6bT5(=PlngSI3GMt07 z{<+TY^?fwh9rt%X$#nOA?O&ylaZmxBTHkf+i4)d9xG_9 zHZ}T$d=>L%?7fnnWKaBu2&{&$)|)qu1R)y@)v}XNi(ul97G$h#Cr+s|!X-97QRomw z6r*`PRUPDYk2;|HLn&pvzxmyc*$`+Ct3Q466-l|J@RR0?b!08>R`NGAbroWN+1_uMOeV1j+n%Tg~ePPzS!RQucrXel#)RxbO*9IpF82CIRTS}?aSISNOL zL+qEFnX!vo8FnHD$rjO6%_(YKTB)M8&2;m%vE}*=nNI z%Mc|DKlqy=^^|6~d3YY^9Iy$KN(XfNBOHL8(6l%j?E%8{Qi+<%(Q3nv zlJ>*CQm4`93P;bUDMnZG+}iT4jbhO^(rzz`iF6>eA8#v{O{jr9#6YuA9n9!`e;sLW z6j8Y#*8GfYMH^3!DH8V2iapRV|K%mNGam7Jg~S{oga5~5@|@{MaWe2d zi~gfHG$#`ye%0@9QF?uPz6&e^0l|L2V|L(aP{8jopX11h>InhaLzH!q2@RL-_Vv_N z`~k81@{Z8nVUmxRkH!km`Rf3QU=lz&?*oVU_CD3W8_Db@sa2ly&n0&OQ@XIM;?$+L z+i5GE%me=RJw1y7d8otRx1d!Ef^WUzqY!}Xu|E~UNV1qgtVMtQ+O+7IXzn6hyweS}ZbyLW_@}bGT7*duM2-Iy2tt=G^h>p#V;SB|`oJBlRj{QH=<#O2#}J@QX(K z(6I~;i*H6A@*1gU-sq^Y*RZ^it=ypWPl`_blJlA#5qbJknWLb`($W6R3EfSL8h}fu zSgRMAWAV_pD6X*8k|gdbe`ARfmByISObO8&nEhP!_}!4%CIa#G1lkAG-_m(Em<_Ld zJxy|tfIYFtpIv#YOTbUtjns*7W7b`g9BoJT8AgxykjO?C#$SWa&}wEz7;2c*=^w|{ z?MB!6F(3$IBiyE*PBC#KIMPc{y}Q9*q`-4N-^W)qH#gvMAaICpRXg)Nv(fcD4Lkk? zC4zmgYMZQ$H{=iVpHl-@pUCBJnMhVlf<H9(ql-9}Poh#}z< zB(?A1YU=q@Av7zrwU|Dbv!?u6(NXwI=3K9r0Jxe0M<=*Gh*#f91W2?hNCCzG38^+R zcmjpE0ev=ubQt)B|AhESZ0*SgVw-RpYk%Vb4xv&5T37fxJO)P9x-OpbJ^)>KNrc&~ zTb1QxuL!fCwTq5+r6C*?ZKTBf z`Sp{B`-Y-4gu82l$tyY>X7ya6P4(Nf*CxW`I|QOu*tLXpp0zG_@{d7&c>M;j0hp+7 zX=FO7n5?R4dSxI1pVi9}5USF513Tnn%_RL**9p!fy##=z8rrX(Thu0B$B$YYRi->j z{dg`TRi?IP$Lni{7rQ3>?~1JE(~&zRup;P6SlxAa`Tn}~dFn*sbk%1KlQ z0`IDeQipWEj$a&ccAQ%OPC;^Y`Z#1D<{spd8d2Rk6s4#`L&IQY zJ1UhIkw~u@kNO+fQT^uh#%ZDXS0syA$&7u0tCvw$NjInK2e2c67c}JJWpiZg&1df@ z-T|{RGm5XXuCm^$H^hB5<+z={7V~my-JBGTMoy`X%G8-U5tfoO@<@tG`;`$TKsfe&z)3p^{K4N7+>N5SZY_Z}D1AH7B+-}2NS^iX3m6R-p8*Jz zx1LEu|FZ0ezsq5!lpsDOOo;k1JpZi+#hh-eQ!4f)WoByA(Bak2M~GI6sxrL0UK~Z1 zi+y>^unz9*Oay~jXv3USy*>?hWPr?A?KavSx9brt$JFHIUQo6h{@CC$kv_#eQmF}c zgI_lD;C6lLc6QAbIl(lg3`seYY-y$we(Q$&k#pZ+wPR)79BOPS*E~;l$gEWXI;4ZV z+l}4t0}lJV(Qc_&hu| zzYhZJR^KmxX++Ya1>^-k*S1?PgXGWICwf!4f)gWsB@In0gxtq;`dXbuZVt74Y<&{m z-!I8{9{wZv^2_&Mq5Y(2c=X&s?cl(m{a{0(sXsK!&V7KLdHlgokL8%+sy8a9C9QNl zVxay+T|grYEJ`f0CW3@_(vI-Hn(QM9w#W0x&`qbe?eU$8K2;HF+uoCfq{f*OLW4!g zAkBAdAR+1pmsVOd3;55+3+4Q>7V2p(Kn+q6$wc>-v{=>k5P5gFK37OP$i#L=^Vrj- zb0>!S4{?%lU`w9G)|e|qWT?9#(pplH8^brfAc8)K@U5f;8O8kG;qk%MRfjVJvUxBX z{JL*dN*ys%>L5kAMe%ojtq5qpFkL{pd4zt;zHYzBC0o20x0$C?)V!E>pDHBwy?6tJ zVAPPrb-g;cPLca~;V&7WDCc>iso`4DUW08_5(%EQ9%z*NIROM%vCwMr$ZGZL&bTGP^o%=sawSk56bjcKiN|owJ_ztHo*5!*`y4Dx={v@~;5VuA&SX43XK^e9sy#pNcU{RHxJ1_mZyj)Put{Sm1C)*k z_+k3t$99l7-P}s4J)<<6=u*lV!)U*EcI8@0@S%FJGAKjv zc(u^OJ^>OCmS`pnsG~CWyPQueKCGEBzQoe?!k!H?%pt7W5sXk)DUOJ}$j87yZK9T6+^1txn5m;<*!6cAW z1jW$W*Rb-2Ibq0B5&k$ff_N8Q%ClieaGJpz*0nnuOTFimX-S8Ph368b48NPtBfDye zP$dN1$Cr(BGDgdL@l8uVqxAe!zZ{W7)FY_H-WhR{;>eV|DP#9a9E|S}Op`lKI`e=J z2(`>uj8U$8xA}LJdQ&XrMmgz_i=Yl2zCPo&R4^;f(BOd`f{kh_^u7pRaLTp@y1RDO z`2>(LQ_;gmm#)6gP3k>GqBQ{ELCQs-Vo<4|q(!>UVXl!YF1~>xz2_S!FUVFid;(VF zE%qT|Ag`9YhE7QvdGOMVa_i(sb(VQN!2TfO0)G%KXkE+bb?YE_JV)P_oUlm3ureQH z)Z@p=o3&U&_@tZjq?`?})ECE49gH|{G|^Cj?vhdIe66$ts^(n&_!i4Bt3Mn4EayTg z!1o`Z&G%4X7>m|XN(}S{R%D3MiUmP~bk2ui;=C@D(`PE-3}lbZ=Bs`9=cqnu9 z`dy{NHEmK4ui=k=Nw1Kd-!9aanSfA@yeYf{AYS2$zOzT3_mWJ+$Q<|~v^aO6SfuD& zzk^)U?;D#Y*;4nBs&+^REali3g4pZw`7SmV{uvo=vKWlT!NEp40&&AyrRn!rT)G7b z*8%nv?wx9^X7{n!=0-B~n_lBJ`tWBx_c z82v3QZ!g9IDT?qu)J!=-4#DW`aAD0{#Nk($bm?-5)g#4pqY`ci7|j7WS-smU!Z=bq z)_(FSuG9Y_NVwx@>SN|NcHSD?D0FB2e(H5zQjkC~l$wQ@km($;Lo4>n*;2D(r|9*$ z|G)VIK_`QntGUg|jfslMfr0r?SEJ?S3}O4^1MSMdmH&2Ta|i)+S3pl-cZNU1!hX&TVb@Zn+B^3nfz_O8J3Rd?^mktK8`n7C zgB9zr`I@V2BRB3O`O79mY$kMuR&a`PFAl@em6BALIRc}108TxlN$lKeBn5bbo1t6< z_PbV4usa4p3m@}i6X6l3?5FnABXR0x|G9-Vc*2=+aCQP-ynW+p=gCa#EAfP=5}z0Y zsSVJ^H&>^V<)}qn!m04Q#<@nhsqG!^j$96j0@iW~(v){4V6-4m!+|7a!uT`l`GMhz z(5?NLd22FDh5M@z_!QXvF=2hn`H7d&1io6M8sqpz`=E7frGO_})QJ0(-iV4r3XRuS zwFt~4_pMuJ=k~$UGxxZI6?ZvWi#kq%0kp*B+AlvJFMxOMY~s3xMU|!Y<^U7I zWx*5tg70i%q^5Q><|xs`z+uZEMKeIvy@U5*tyA59eK<*39xO-01S%qyDn=b`R5XjN zJ~w1XM|jHIE4!1+oRyq&<}mNFI!-G`;#|8cG@Zt)@k2#9Ugb;LQ2i&_M@z8_H78(_ ztf)KuIeveNLHJX6?^(WB8NdD2(T|jPJizDsP8Pbna!!vK0J@%enKqA6cXl&?x>TidS1v+Wck>8%rz3_|N(CGqAy}her(^uqxOy zA%6Tx7}9{b^dV1%#1fAuo7sf+GfsLtUENDh+;l4oy0qcnymxd(r%_T)d4g;k%Mg0@ z+Cj6luLrZiTS)vAIfl9$Wsc9U-XjLS{Y^$`FF<{!Mym5FiKePJO)4hSu6WK6W4Kr9 z=y!~74%NPIqYCduF6G>IY;LRVTQ913*=ze4>A(pTpq;ypYEAKnTi6Svq%kmiNnN6P zBM=+l6vqpc*d3eK^q)_r11(_vH-Kk{_<(b$eq+D^iMBa&P)zhSV*xvkCG{S~NR-&l zI31V$3^F`mqalq!I?ucwtH)qP489ELxxit50iUjV$%1oBB{F;V zI-ADuKWh)e^^nLY8M}`hbdgqg6ALnc+8=U!=Eu%s9K}yl8qg5w0_*5-UxsP$j0&(Y zyWfbmw5a>iI3hXrhvPMfN}wfL$dsDsQRf{Y0H%I3lz?Wzo(xe;n$u=Mu-dvaIy%ib zQ}Lq?Ja9A`BU(`znmlh(*dUiA9UbOyC*Y@pw|LeP69eMY}m*lqy+H6+U1AQ`^-f z#GWc-#*M<L zf=yW>SWdnM(S5;-igjP&6&66iAw&I`bzR5rvFgBJbw&N!Thp8G;n!+x^Z3> z{7SOZN_`tz`j9B&KF!3Rq$CAK%F{;qj?_(a?PCjH5HZ05QaJn&&6LoOOUTpNY?Hxs zLS=p7K7nqENDix>`+T+%coA`yEh8q3vUl8qbs4^@K7~A$dB~kqY$7{156_*>Z8Pq! z)?beaY67{iOCP-?fo^-#NU=?3PxL4O7`k7S?XgKHmkFlv4lh+I*eK0L%=59H)_*q! z>*PauFxF6TK|m6;Cq5+hA+D#qG5c(y;b?jT2+)=OZBgiY<8&S{r?(?{NEb0OViNov$Rtzlfl7aV!uNW>+eII_r zYb42ckuZ2M&`;z{)6q-xmUnV)b~}{;B)|Y{IChW_G7_!WC?&vk@nH0`_gBFz3fa$! zw1<|wfQiea3(270S%rIfZQSR({pj>P*B=!`+I9XI{Df*Zkma$`<-MxZXe4O0vI6le zrH6!!P}t^hvHC^Qf&wzwY?8r$y9IY0hc?epWGfyn{1euyc(R{{bw)qtjV79osK+K{ zqtzn56&S=+2y0Bcr{UR!cSh$&{;Hl_|M>0;TK~;UI6X~0PWo8q(i!V;Y zk?1-=?GuDEtKz#xGMVuA&H%m`@Q$kTx4CJ2Bgl)cFW{15=7Td-!;)uBj;@v_`7L!s4xzDf=$SJ z48JL?BBQD>l|a2n7hdUQCYjZheAv3j+&r>EKtfGH;bjbIKvizo$3=C3OxuRC;U$e1 z)EPlpGY$}G%zoWx=u=&{Kc=p9wb>Sb^ps2Z!MOPxL_|j>)Z>-F{C@2ayaDt7>2k5)tpi8MP~K&y9h;=>D{qwhO_17YB;xj615=4tdy+pCTwf}3p@ zLTIfwwPUVI5?)+K6E#n6>8Dea#$U{*3w!d{Uv3=zo&>Q2k;Cu5#BwyLPqLYIJa2m_ z^CM_d4nFI8cIa;6~uwi7tih^+V_iW>iQw$9l7V=$I?hv{6%0gdCa}T`sE|Fuq zjJ=6@kFk={V6$MDKW=^*>NO68X@Edg7ft9n$gZ3~=SM=r$;gw!59Q4hp7=gHJN`6t zytBZuzE9?9I3Jd7LSe8#g^wQn{=9rJff}eCZtX)W!Cy%9{i_mADg8SX+!-R4+i==( ze$?!4hT=y2Xhm+QJ&h4{m@fhwQIcH28+u45%c#%K9ExejJ9rJZURn!J32LG`+4ofc z9*y_N!u1p*>~WX6ZDZ6XjN&NSoP&S2l-}Tf6#3e31vMPpi;va$76x0`US8IC*|_HOodJ4lN;d>UmbkJnXh z{8eC#`>oT;0kxo&<`)n~&iffpiy)*jx=_41?TaV7_fEjjuOvfV^+8QR?IRCo8{@2m z26v{Dw4H|FxXzMd#6^ZYE;$eK1$97a?Cm_szR^S?Gcob|O@z%{1jb&UHL)F?aKXCucuU2e|Vg05Ex9XU~H6rIi&p58a2O(E)yHwR6c6@;R$ICg4db}h!T zBtbK8;K2A_#em~YK%|b77(T#NJigo%<_hqg=Le%SQ~^H-K%C*a%nLg>B*`vz{J{G@Q z*`vc@je3G`udyOZ`%iS zY@Z5)R)1}^GHV>O(V*z=J@$RxLNuseUBQn~9o316;(7Hs6gsK;ImAZ#vcrBSC5j1$ zXE!ZA!?EhFfA(yALp{_abaP>72{afpuN2UdmZJutVReblVf=Lj-`)qG+$?W~EX-sU z_Ifd+svC?^vRX*-$#eu!Yp&sAIYi6Lqtfpp>4HP65o(nj%XDL&%aC%5#P|hIAIv`+ zys6kzJuvUQ;`jgk_%c=Wdf$8J00{X|f0F!RDXWRf%pn~99ZCSxFW3Q#O$x}4oZADijO1nw~8_&F}rBrSA zXgjBlC3^EQpS+pF+*U6PqMGhC_Uz`#_XvqlX|?`0crvdip;Y9kdGWvzbuu;0v5}wF zI<|hrPo`Z`C&V4OqI^^%gj@gb zf>33GI6}hOp_QaOcI+8g{`Vak8X&HpSQLzkwc?w}jzgBa;a^>6-*|sO1AqVtEP!is zf^`d<0BE)zyP&5UfAZ=oKMY_k_R+w}(%0L$9xl>pjW7M6yibF8M_tMZY?|ZhLSea2~H15IKzZRnPJ*N5HFWq1;t> z8ZjB^Wc4qFSDn4Hm)gj7DLi-CB^zX_ZdyWwp=X=;`(7?0x4bt28Jty zV32U;%WHjR)SsRq^PvCaaqbg?ZwW8|s?rN*LduAP{r!t{*31Jb0w|-_Vxt9OQAO`0 zS?MSt2slJ9$XaH6hrTf{V2e5U@RGkwF~fcT<7bLmxx zohk3bXP(sNa2K8rCc0I!5w(ExSHbIu8xUy(_R2=4i)4M=X>tGqe>*mYC0I>Mq_Mzq zb;*&kNYX0eudbr+_juH5qsS#a*pR zgvVA&h!<`sC&J`wufcNH-40Ief8t4okI5f2WB*2)m;%3#h~6s^3MnCYv9TGqK>!zr z(jHOnX{53C*T5u`zR*=}21#5C`_fIyU1Zw5bY8BX=L&!D^3`o8pQDF!K6hZyXGfmr z>uaIi@BSTo3RjOO4IHxTx-nP?wIu5IlPnnWX7<4;og2$Z{En7_Hk1b6uaCfyZswW&r~z&rstUxB~|n2nG<<%GM>3I z|MWMS;-qHVx2*L*)q#;=Nih8<)vI3Txp!>qI#7~pmP|FO z|Be@_4UYmH9Z;g0!;>tl+$mh?{mGt184?yO&Fb!jBmbzxZ#h>4s&@#Alv{lYZe9!d zdI-vnS{K6`2z==+jm^r5!_U{FhOa%2{p>*;fWLa{D%j)DFNfdSKn_iIuOFSM-xGUhGc3)1duaaquiQIo1)n0B* z)QgS^3#q6@C#*3;8$D%+LK$RK|4=QlV1GFH0LOLdGMZLqeWX=aETNS%q^!~Z;w!-PauvFp_(BT|mSF9F1>$#oz=Jw5Lm9NHBq?5s8H$&ItTYs`AJVDR|(F z82vJo?FL7E+E^tib5rHNZc6yPVhtx_2+n5_DH?Rfc3fIp)h{QaKw5w2-i;rbI(Gh; z^PA35^Y$eL4rf{Jeq;9vIRD}TLedp(o`>Mbh0Q|aiCPy=3cnaXITfRqq>t93covxg ze60CW#Jq6ZN>>j;dp0)ly|7UwodpqHQG_!hdm{nu!evyz#+n3Di8=x>*?E>ExV@8b zy`-zZ7!!TNP++T)_WoU(x_=vF$^>?JAoX3@RXDU9s7#pNY(zV4EGuWF#fR3JOEU=( z(aa?@pALXUDkC*kI`>ds6lf%_TXu#BWv$jr!fKp7hZ3?gHG8ttD~W1!o?Yqtx1dw> z01xyJD%^ieg=m<36JD%(X{w~g5Zl)_ZRM1cR$AhH5ps1Js3;V^NY z_4T`jTJaP_d7`5#J_Ko2Fr|nbz|}1YB`?#k7yPs(JnZ`yf_tpMFax&rg?5&sQv=hl z4{=s&1~4yp!q}KDm6R-dGDx#3V-!^G@wSFoSdEM}o27NSYudJnHG)kFbJ_7@#b1Sz zCV>#_;y_|3h0=BkF*;V?Av{I%YZU`3iQvk=*RSb<{1fdc8O2iBz7914W3|=zh8|j> zVkNjxdKwa*8YM6bDqpsFeI{xyo*gCkcvblXyVjT^*<3}38@!bZICq>3HFlZ*W|=@m zO;++hzkM=IobcIqKeZnk2%P*2==+uPuE+A!C7f?6_;s~9buyM-usorwCmt=Cpu zw2|wmr%LOi&ZX|d!H|Z!zUMOa0r(warCBR7psDw@?UznDe%?4;UF-GSB8hMv`+If| z(6{dS&vFN|8CgFh+D>s3$wJ zNBd7D6Y`)G8poV$>awR{VX4>E`}!8-WBs}~$W5^ckdj7lajMZ8fLlin(+G>nYPSNz zrA~?L0&gGhSZ}6j8Z((cpNl0xN!a_LHq0JNrWL9?qBdI?%fB*de|-cs5u&4P#9`)O zOv&O=&g}9ebqHlyC_);pjY@!;ZQjcX;{DMvlw zS>VIPK%69oi10R4#AhpZZPh$J$akZnC2S92MB@gFM(xMwy)&YNhMUEh#%%o(?aWc{ z(#xMu3;d$_aGJ^Syz%5hSm%MrLwu&s50FX*=oJ556!yIZ>;OH70y{)CL-v8 zWXurwRMXs-X%4`Tz0J+*hGNf}M3OrW=-&>o z(_Ddlu6Cvk%#ndo56ZClK~tUWxe9pAyuta#%KIKiD&>l%@l4b5SPQ*?Itlp>YN*%c zb$0qzV!?A8DUfn7MYfGG+Xbah?rCr{`lAegj+dY+?DZRdH(x4Xzj(SMxZ96}Yin^U zVK1=FaRS>*#kU+S{F*>oh20GYbzCmiszi);52tnC0SKMmxUpp7z+GI*Qf^^R(+V|; zq<#^W?}*!HpEu8}+5ZQNg1d!3ucxj4{bxFh&jfvp;-|!aU^I;7_--GTPxC>qtr=Vs z$o*ra2J}lFTQfU8Sl+P=K4eGbp)SzTI3lu>p*E<-nw1y^>ZhLVUO9Uo?kP~!r9a=y zzk8MA^Ud);XUW0@SJkR05!iP%jW}D5_Wc0(9b{q-U3F?}DXfl#0!dw0!iC!`t+0iA(^cPaU<_meA9{aH2bXmUnS5> zXX1)R(jQ5Sk!K)uL5yw-iy)QABwqSM7gs>iu3UzHq)!mE*odyrvUJOz=3Wt&X3u`% znP*_bb5N6gqW$*ZHuPAqpXe!*3bN92+3M=^H*{Zw{=c%j%m^#WP({&M3C6wRlf}mI zmRkIUf)gi{h2sBeR!N@^KDQB@xUCwF1?0s#uaPn$=w?f?QWv~qavboCi||st9wc!` zq0vr{k{Ew@M%lcG?^^&JJIorH20ejQyJ~3hH&t*Z(O^N7up=2Hda?tRPXrJ-RsGpS zDPiC$YF`78Zx<`^p4wZ>gcmLP5!*^?yP05e+m&?^3a6}y5pVNo?xqiYxjM+EcZCUE ze_PMgSn6Az>V;pR5MdyKfo!y#jJc$hxg?T?38EM;{kfkB#SSe>sM0LD_*XOP5j2M?^X0nPL z5c#eY22Ex|)%cOzV%<3uYMQ-SW4*V%z)_Wqq@Em-6?;V{la#F^f+-Oh9dDp|B#TJJ ztH)R}sGv1UUa`1%J2!81Xy1cZ6L;E13fRtdlkHzVi2R2TSKH3vOez&)eo7vbl#ni} zkVHK%Zh_)0*I^FMj32J>R>Op>M$j9R+{OC!7n;SWE*g)PK#`~r?k3ZC(V_Mbjn4a= z^G=PRyq51GD!eDBUr<6uycMK_hd?^NR65Pg*DrMK8ICD%>^gF>F7u6Crdr1duA&mP z$0&J=$0bHXHPyOp5#EE7q`GOgLL>S#jaL+_j)ADQ6uBpt!td6v>tvGneiRP30^&u_ zuxBc*Q4M{CNqP$WRo!E{P?Gp2Gm^7U)XB&0U%$(UV58Yb@FK{-seeVsGDPV3r%F^7 zMD}cuF2v?T)Y#9W_Jq_eB(fj6K{{HQ70>_9vdf=;d$ygYjbwNj*hLE6v@E|lNr=K+ z{GUVUVzG0d-OsQS1ko8o#%LXTeX69K^=|KEs^^B3>?_+*P16iO3 zP1rAvoZ{*az*qI zJ?Noiq%@W=y&KP%gHQsEj9&Ac5J~r6&Rnw8cm2o2$Ie-=2D*#dMDivB6E?F?=cvhH-Km}-KEhT3V1yX%)rvZ?py16VC^c>0w$@GS<%ceN78xlbqrDrv&FlYXj&mSPWPjV)kYhJlf7l_Rg&ZgCKU9}+OcsIE%rO$H@-_58s_{|4f-xoIX;ww?HOhO(GxlOnUug&Gd z{l7EgFt`FAsLAbVx%-)>_m94sDgi$SmBW@GV@p&4bn1<-q|n6`T40xw7~+rgn|_z} zfB$|1Ay1Q(AvHN|PmIC41)ba1m6g?N;@LMhZwpFP8#qz_`*aNCFAI$?L%Dv;PtYGt z!_YY|>x@q#xT{S~yt13#5KlfaR@=2WQyeGcU-amgYUmap{*8ZWt?wsDp2CS8_g{Hu zHbi7qcxUf_6rzUA=E*q5AtO7H!9hhJV#fs23r3bQQqjuuWaf1YV}qBikYb$I_;wv% zh*h!#m+gD@vpJ1lQbv4lk{0YsMKZW*P2p7btlijSI|hfaPvyho<4{N`2NFY|2dG+X zYlOm0t)$U^FBw|HNk1q*&4iG|;EGI(>l@V;U-C7FC)sXdiVLw|bV-!Rv&~{yYiGo1 zSpaT2>;jh7`5-!RqHmVA*X@%6#kL5nV!bUJHXLGQelU^DJ)59{@WV9+RXO3pSnx`& z{K~An!(pph=aKT4RY#j#%iw*^=C1V*BfF1C({DCBK2i7x0~`ASH}JmMoxlKyBa3UFKgGl;poFe1V_$AU z9a@Xq-H2>i)cniqfJW#yngRz~7DTRfd;B3Dl zJiiG|ZGoT|#r`t#A2Y$~k)at=D{Zd{mzw;!7w*YCX?(G@Z^jz^qa5*bPAKov*HMHd zqXCjKgEsKC6X&bz+~DT7-!tLovT`v2veVx~ZGT!_2&<8NgKt+Owxwk9pbViDt0J9m zH;JIGs_-t_DdVGriu}U=abr~ovuHqL+TvCiWH2tHlTy+C^gktka+iG||AF5-*D)zR zXA9l6h>DxPLr4MYP?AX)T1=Y??tDJ~>>8MZ5JK3-Kg%EZlyzbv34{+X0^-m=+(|B7`m$=qwnr`=NcDNq#-<&h}*qsvxz5d$u+ z>)g8fnY5uU9O-*?h@9S}|4t{HLBQ1RV078lQPb=kji++#Oq;EH&nc>1v0PBw?Q$b# z#5YAqna8M#V-$*X8mchO5~@X&Z?Ma4Nm4^&MU$1FfO?vutzZDJa6Ma!WMt0Gwdvb^ z0fxB}1PMv2nHEbC3re%@(>kqAvWL~tg)AlkNg`(h&3DxcfhtkMf?c|xVY?*UDEyD+ z3YmmuQ%2v%8nhAajF_J*_3h7y2=rP8js!j%JX-H!-#zd#sP-;hQze*sSI45!t+-E48e^l5LVB!vRzV{VR zp})0>CBjn$YN6Y26dls{CI3WG3y@rBWJ+1;!@i_e zoz;#dM~2FVOvYTO{vlKUqyf*}c!yvNQIykB~o~+*k zvyz5Ls_1<>hkSGNz|A0UIt_ystWB^iTM+i{xu28?H~kl)JZ*We7yeYpD{9qkl$=K2r|8z!XRxb&?a6PXf_`Gt1dQn%|$9&mDe`qj$8d!zX2B%!hu-w+xUmA4t#0r0W7lc^FnvVM8a-D zbzD1Vi51nO8%8juTO1|Wnp>>6|I1i?xro%AVynp2|%U;*fD z>b9y2Bs2VxH2-bgCh!GXwIfw^)d>%3k;2TFmIB8CHqm8YQ1!s&FurDo-!2O-E)A$mx}ALI z;?&uxs^aS`+Wl`_Rk7Kf=!g<#wkc;KyJZJkc(Oo01X?!%XPLd|lp!>*1sBm(3fR5XU2 zJ9goI;6YeoYUz{>d{gCq?#F)~VM2*fy+8?_9qXkEq z$SOpUN`q77I9s58!+Uxkm;1N-eRvVxKVIwOK^~;;m)(cPbRSAV#sVG)7eOncoSaIG z8j_Hp#xH3o^8nxYb9a0OK&(1v#Gywi-LS2n@|k`?r0KJvkRoiSzu{N{J}B+m6ZKL-X`%nvdEeL2BMHDgAajOjN= zb1dq=F9LA!VeTnSStCT^hr#|JQ5f*s zcZ2T}*#g#k=ZugVLe8Q6WsadYf~wtuKLzuOnACz>&!w|mh6qH`aF75O`FTss28($q zl(y1ThsRMBb1LPCj$b((vCgyfm8re?b*3|skR{)haGHZZeXi# z!1fp0VuF2W5`!TyfVx`jk(1xIrGdGHYl}M21SU;h)l<%7T(#5uu>i<}D$a%`)8$2O z!9l;(i94dJ-+X>Bw7@#Uw-GgUN3^d~XG68;3%}vt_Or&cCBQ7uNw-D~m?~IQ7hN%$ zW5?V>FeCk4zjetWYfe|9gFo#DQEF2hXD(UBnaD(2u2Z8axQe-})oFVry!pFszTMNS zCdtPMHl8BZzBQ<`4h-j@AAxb+s8WmLCrzYx3_XiPZcQ zl8vGYBDWu@|IZ5$G<1lD@ra*`f$A)S>s9)7#rBe;KGsqj&+UfuJ3I0+oke}4A%K*m zn^$ZYo61r$Zp4*~_7hgigwtW-*fFf*FjBF7&vvVU_hbEJ9f5-LUL3Fp7z<&Ab0L!0 z)d3=6h-T0C69qS&6uwDOkzS`S2xgYLyj+;F<|wEh*BfV4Ie`|Xw7J>FeRu%0h!>q3 z>4z4njtZfss!dO8p&~qs`|UI?;cmeAoec^D{I1Bt*$M8=>uZ7ULee3F0AZ{m%d5Zw zkOkh7VF%=W3Ici?&=_sU&D~+2>)o%Ge&TX;HylXe>e|Ka^O#=^E%8RXHG+|T$N}N< zV#YH_h2Hv(RB*)vw^7*0axGK9v@P>K*_|7CEN-QOp4Wl+p4D^>_az1;itx8-Zr41>B1xWBvW^2RU6*uX-p# zsnCJY-YL%S^*FzXA7!Crb)GXk)$-0}6*?ynq0hM)Zv0j!tv2K(P3VspBG{Y9%Gv38 z!1>sbTIQu30(*|#SF3@a4Rg6H#e{WJl21^>V-&wPg~*L_V$V|P-{HK}pZIX$l#J)AKkdmmpo*KQ{^7xMy$7{UlCDmWB%>7hqM z6q69xp63o$oqj=aaz+3;b3#0bE-6oTfzH!r@*Ah|hCQ)<9N*_1B;Z-#z>(a2r*p&> z?t0A%eY^e$hZGKb`Qu=>(4lrhsnN4XO9WgM35I;)Vh+DPv_o)c&eiC?g!$j#IUvWy z|A8V6@$pvH)OEJ_<{Mo0%JKF~&#$R3m;k3{=U4fBW{`g(6s)oD++;4f3d)-ltGY-; ztNGNn+xB+-*`_UU{428R!0qxfd^@4+_Gd+|#r8uVm&I)T?Vq2g3pe}_yegw661a~2 zyQ!ycAld+vL&?{~fVsTNkRoyN;Un&hv@{O+cS{|)tY|S?Wp4jsoZJ3y;KVlt&JgWz zVjwn((MeIif91sroD=0kFu0q9^QCSbU7>$?e?7MC^WX`p)f;bE!F}+`|D)+E7^-Z8 zZQo69LK^Ar?(R&E4NQ_xy!tW}cZ@v)0TaAMJvp zTqmZ2cz?%3kN^zMh!+0U7mgrG5a<^c4FQ(LZ+Q*~Dkfw7;n#{njVLW|<){~Ne~n~? zNy|%7ma^j2=hNkPdr>A$2XbM{vCYq{Sx$W*{MjcXpz8$57yH!@iXn20)Y#_ z3=k#iFP4KC0RsSfkt7jrmbu*9gC7uQ5Y+kon=-$UG9O$(Le_nFq~V&bS6Yitkz~$N ziy3VV%6o8lcQJ?7Q5kcT_T5dpPG*;wf`LMkS1@*b`h-$C(n6{iNXf840fm8`P$B29 zuZtBchQT7~+Fpb)401hJakOxHB>(7RF`}y;ATy4i;tkV%J_?y`pek z%M^Z^$R_xI6zp^}gnpChtNoo3O*=Ztzx!*EzjFKU6j<-K^#6jFr5!?@)=Oadz@a-5 z*!?(^p-QApA*8B?nvgGk+ybW|tyf6(?$s^w+mCZZQ|@xz$A>Y*)@SPMqR}q7YNcL- zruGE^00Lbq4ey_slNAEZDF&OzM{5yHn~=!WUX)Vg1d0e?%%nm6pQr$k{%A||TkNxJ zjA5p+;avSeqsY04_cn@zknL_DW~F>KD4{y=lQE1|_DKshQnB;m`IsTcdB0F^BP6vf zd3!uT$>w9pS0;@>+;+YfSw=LNw`1Kw<15aXzd`#S2v09k`j!j(e*|6hwwnmlUrn8B z^mT%!?WCm?EAb_qGlt|x@L}k!){A8tVcD^P|1T-6`Cy_6l}COY@XdCf3F30TtKR|+ zXT2-GZjia}6xOg{ZD-|B-Ib2)dszR11#uhKHJ3LZ{Hs)Mi<|ed4$$%%OOe(}QTaBC z(wITB5EZjiaoeFb=E=fZOPE>rKG?_ehfNcWmE#tSEA&45E)}&qY~FoYL_&CePr~Ut zy=4rH%yatULH!$lK4J$HRkLIKcbGJiIrAC?^_5>xhu(*$o_FaT+P7y#r0%|KW-6%) zZI{L3y>dKhE}Skuy#+$s`Z&K+RTv2O zu73O4*U=CbwKxGvaUz~+PC+pob0!0C5`6ttFH+x#PnEY>AVHgv`w)Q@oKBz}5chMU^>NELhjiVyn=J)^ z!e0uj8|N^9_<|5wce>$o|n||&23g*~wcF^*}DojmV*TlALrD5t48;6+Z&(gnHrfO3v z?DikFQN6RBjJ6KlT{H5(V-gq;XIz-dNnH&HkuyU%^frC`NJY}r@Z=;W?r@a(Fcn8*ij4ttIOa*8L=vE;XB`-IXaJ;o7>CzMz7gB=wA0~QO z$V+A;7Tc#`USl|LTy1$1LUb?(9Bi{RYb4}nwYOgfS+uP%X6X(tJ|1XA%axQn_SeQt z5?j-L!XwitW9+O2L2kDOpRw_SYQr)EIXr9~d9ip20(IXf)wK-|_=~}7gnM0%t%fK7 zh(kZEzYP}c-Ow5E!&ZO${HUB)x@u7U);>cBqbB%U2B+q8aAF8- zP8F7T!LvD%X5RgaMYKs*!FlE6moniW5%C2mM_`I)kK|w=+tskFy?3KJMRIY%IF#oC z^SDLYf4B)B(Ky3~OXmbblKiF<&WLI%e^FZM2q8}}p=i0n?Uppw8cHp8d>2)qycf%` ze-FrW{EXL6;ruBNHs~E=N>_gmXIFvon_BHzzb9!Uy7MJpV4NuRmD1IrYQ}K@PxW2R zo5}sa8hMLQNAq_04*Gk`zaap``rw@%X0<8)nZ$dth&G3iHL41t7y!&rWx)UxU=_BF zn^rsRq?V&<&F0H2@t4o9}00XN74f(bIn~2v@~gB|Ml^i;I~; zrM$>JwPCg}yeb~5#K24(*riwkhbdy4)97{;`mcX&H#FE5boC$^ysOh{yHZuLDb!={ zc&TnqS$bJuqg6vOL(oN)5zXe-^T4)KK1$ZNBPG@QYXA|w?+88gd9&92;PEdqjH`O?Q)vmO&~nj#NGJ+8&*o%}K55Q&S&#m^xBT#)=|0Dc@spOx%3x5a?l;43z~U;A`- zGaPiqP3AHzo4exN9=bJ$h`8+E3NKFV-1l!V=7wh!47?dVXfyTussCn>nR5T?7IO8V zY^Fn$SbJD>0l{4H!OX+Qf>Q`aMZBO-eC9rKkgilFNuZj>bSArTwD{j}P`+-rB$PGv z&zT%MoVD&t0K9=c?t(z0^p?4COZOiHsQKjJrXS@0D3BiEfEHsu(odCf3Skae98Rb? z#Pf(9=aUHtBborqc z$?#C+RSa=id36PG1FxRq3HkIb45<)&Md@p!IurT3kIFhKALHN?KIz=22-K%nuqRT@ zz1LT7qHTGIwRh5C5`cLb+fPdn+o*SF`L+Q8>i!H|#>%l30=MZ2;b?g8%e4Xn#KDh@ zYR|@huuUy$yJ6n9(Hz81MXrs2-6MUq@ZFRI_$(aVKZygmP5U%GrXV! zQ8?h+|Cj_bEaEc;qqo)bh@kjyGK$=b-4mB@O|lr$ZrNH{FzS*GktUIr>NDa5Ds|mblwLOiufe5%BacxhM6VnFkjY7y_H3OKc!Eze? z(WByU$T(%@RySj1KiLcsfgQ)=_ok}`|8}cI0muSbhxyCD_RtTSiZSsyje^QKEQ8Au zz0#4B2A?$i<3=KE-gdmvg|1U-U^l#PD|QZ>OnSq?=IiLANFj6&@||4{+e`Kr77ydw zxP|@wCFZJ;r^(x}U;V1fFw7^vi7`7;1p-b_GpfP zBmK<)V?QF~6B6;E()&ZoMlj)@p9iohpfW$!n1i=%WK}V(s2WqPk^h2H{l*S|^Zsd!el9VS{`}h(LY}W^eu7UgiqPe) z`tCR>Y-1r;qE4B1fjZ&hJLZq^M4sbYW=7=(*lIc2V?G?oU96ljfSiFEJQP3=sL4tX z$VW;Jd!@pGV}p4}m}HKJWa?LLtzctjg%rB>M3O%BZ9g}__BS#1lG};|{e0K4qPYrjn9`SKc)gH+!LU2o&%ZM=#?`BE*{8%U7N`<&eF!{_YgYVi zkLwNlT((%LZv0zl%gf7otk9HXioH!#5?ucSdcGO(u6_`1B4`AvSW-6*w-f(mnPn!S0IAiePB=D2LfpqR=_A))oKqjR*ng zmR`0WfU(7qu@!38q-@urG`4%PKvSeMqC=LBB+mHoRsEJ$l~3~B0A%80A(64_SIeMl z%Gq?PPvO0{d_8L>g1AT^dHR0%F{7?A8R_5eyZFZ10s|fbG{lrB4zQ4*eMbD-H z|KItSoqlL7)H!+Ra>X4@fVKV{*q0EgZ4ZoMD)QD6B-%n6Zr*)DER=-nACrl!F#$ht z11B|__R&oZE3ovtn|O)x>GAy`e`8b(AIN}bOQ`Y<}L z`$4R7p;{bl$4YY)IIYEzOkFBXKis^UG{n(6Blr}~eS0%lBEcX2dO%-5P+?1pXOFCj z*@S91lW6{D4JT-#MsgH}HGVMBmrB6b_iK&1qT9jpw2h&^sY^?AtG6DxEf13wx-?RC zjyWL7Kx;)UIZn)&(;_ZUv51bd%5_msL*K4DJGiDchCTK@pWPd({%yq;WJZ=QLR6_7Nl3qw<bG|2j|8+Vdd>Zw8-6~{%Hu`F|05CjhMk3`-dGZm(N zM#}H#n{~l-cor_*aw&h6Q{;-XI3A8ZFfwJYI#S;*m(VygUpoS#y=CZr?^PSO!>M8` zb}ww}h1U3O_Os zFdR);s6_#$dBiP8g{e;zw+z@$(U@8o6K+&--g+K9KYv;4d|I6#<|m{huAyTUJY@&E zuFz4t8jQx=+ix+ITYd_)7+tY{m4F}=%HWF>pggW|;-dGJnmG5>%ne$Pl6@)XuTFv( zsQn37dmm9B(0vh%H_K#GkDngo1`1V@(FK8$ZBYNd2}6%#9#>cV1)DX zLkP?M0czlJ&SWz~Zw`R|MFL3^0N$H_YMIx8W#K-Ap;Qd>bC7EcqrB1eE=Zqfoxh@Z zw@9&5+;c`2cLZwvDcA;*qHd%Vmo=S_#tNql^M;8i4ux3kZ;O|}05WC;3R5tJvz(NV z!@70}$=gB@Kf%JC^^IH6#+}Y-XNL&Zh1FmN4_Ol=Rn+4sy3iNr`LmYN>I|N}3DO6W zy5PPI)^EUM^dX*OBJ@>p2ftsVkAt`=z9LqCMyzl6_lfT&o|K7Rf9AL6!nZCi8?D(_ z^sn{5BR+-O&S%7Y(eBm)Rc{|m5GWwf!o`7cS57s1{vECKyJe6U? z9(|mh&_}NCPjX@FCTNZ8I^}Y2xADC__($L`1)v#2K1vJQQE*8GgiYnOQ%_s0eUYoO zk;f6J{e1jS@BHrQ7n92ZVDl~nl941`AQ@p}g~4H)OSFSBY0+jEE&zdM8smv|(dmvcud4{Wh90?EQ%-*mpBKu8{S%Gfpi&YVM@TWkBOf9WY`g!>e-ge6 zvQqSEcSGpsB#UN^xf^^A!89JU+LV>CYw9j&QI*I zXqT33n6!9#f$jH3&c7Yit*Bz6rb*iRU6|hUf$xK~Eg%*ZZ^ZJuCv${o{c8cb9decY zB_|eEh|Gh_J;C<}+EzENOi~}|qj`T>U94ZZebXhNFqQW=8Gsaf1FC6*)7yn9Bf66` z@gb`i>@KW4M^iX%B2XlrY}r2-ux&>OX2TuD(TEN3Y58?@z(x|L`bm z;L}4Ko|N>)AJq0`fDz!(HHrd^!)Gy25vJlTD^M;ThWW;vVpzr>ljiIs^I*a5h5lHmGD zaWD@u(@>yzi3WS5csyJ(Vx%slIWRzb>^bOQI1WW4;v9XcY8+43{qJ>@!gGyC*iO7} z!{9q#l~~8!H+EeQ2g;xy>*)JdGARKXZ`%2-+7u&)uaimtT#KS znF?hV-0r)^FQ3N9%|N&l10c#v`6&|PBGQMyVvikRE^=foa~&HDYwHqe|Kv7Hn5=$! zeL*NsFP*n&nj9V66>*S19-KNG`n5|#oy#Z643pEo|0&Ds0AzS`K%ffq8n$?|d(83n zV0bY$Rwal`frcwtZeC4IwG5-1vgXy8h>33oNU8z*f#hmcVqCX>7=gu3Df_mTl+L@e z1=T*PMx$^!lkX8{*|Bhda%WM|%fr1P8>i`V?0v{WjN`wn?~!Zp|Ipy3?UtFy8sjBT zfGM=GRdPJ~R7ovl2_B%7TDp)SpWfWAhGz%{iE_ovjZtcQ0QL5RJFGIy-EX-v3&#Ug zY44!nXx@p52Wrx1>!?+eK@JR`flE{@$y7NJqI}psR5}ZI zv9GHC5M1r@VZuU}Yh2G8uAnV3#BiHO>|qajO>$z@*JAxHHc3guCeRY zIkGgy{@+)oncAoBMnq(qmozWD%w;`d=TFFT#x-(AaG&izCYk~98pN=9XkGT<316Aa z8U;T4n7ZM8j{qw=`&yZ7DtN&HEk;jZhxThn!?h<7>!~2m>l~9q=ND;VpV5%p_Dq;O z_v?%{MuVI#JOlD-O_R(qo)3Q8ZC_ zF|Ar8K#i$Vio@kC!LPWShm(sy&I$vKN~V~!j?PMIv(B2)kx0l7oeGIJ^5xe;`JSJ< zX`S=O-=CKrn#^)bZa02flZAC4hMabD-4ZtsZwM6jiZs2gNllkeIPiN+I(Mr4(c68X zAH82jieSk@C`5BEKe?M95b#jjWTfFZX7jyXkb&|>lVkC7{ZKSp$9o=j z8dbv8P!S)=cA!Z1G9svxH6&ho=#YB8xNcUmcsD^oYO_V-!`FcCmyb=OkLMoqESE`x zRp<@Z-bVr!ob%c`nr?zpet8y_ZmAoYUiGF=&c0#FDr2U#wI=ExYw1(ue_z4QQ5-xW zV%f-9Imk;hP|!j&*sHXZzSg=1& zoEvJzo+-rtvz6b^8h=+{_RV#uY^^pJ7)Ag_3q(I{+vdroO;Wb;u+|#+s}EFBk4h`!NUSarf2mA6^q$D~i9rsaU$Z!BS#6 z!+3tW@z$iLzb)aP2D@pjxHa7lRqdPJ*?n4dUp;!ev)4DerC2xN4;=Y}QZiu5R_bzW zds|z0bW;iT+qyvs#{N`yusbHeeX*BJ>@G=r_zcJXGB)nLmeaJ``{$_kdzrqo5ag?w zij6z*Se|Gtcs?Ib`7^>1lxhgq{%z}b>|J)i4^ON#M;`m_2qn?3$Gy4Q!6Z3&fPF7N z1D>%fN6iPHX&pBYM}fNg0$)vyxyJ{hhanDQyT=uDC?w%|8CXJc0NYh?Wv#YQLh@}S zRQfRdZ$k|6WyKbJ{8lpw5#PCW!e*3> zx-8(Ls8p)_n$`yG6~qrv_%mX~WJFK{%l2>>z9wFAcIjZp;N)|PGZr2(>{C)+f{U#N zF2zeMfqC{%B^cW~+dZ>^p>9$8qOMmVxSiJm5$)dFi7u~!9~ZK)-NLqEHu)k(&%dEc zA!f&TbUdVnieAW0ikHyBmBV!ZjOUZAe9Cfn55+LI^tt&j%ugUk<-aNGO4YmkU@5z! zoiGdSFLcTRBt+TG zV@CWhQI#N9*v&F18~< zY{(p!()AA^BwFH+IM!+OF*eKNIvGNOmTR`nl#&7fv0KmC_HbH_Oh27+nx95m2ER*R zH-I55aM2z(!qXh2jV4#4K_Z?^AtB0zf=hnAh@|@M#}!_o0HYE?7TdhQNd zvdUhxEZVWUMbX4^G|hs#3^ATOVLnrq*Iu2~8O*a9s|3u-sOzq-$DGXUIB+VrG8_Sv zi_3t61nTc1WEZs@(9mh?)9s$jq3f_&Du3;fbLepD?|f=QJO7Fp`#9s!RAVZ?teqRz zTRl10&$szL{729P0)Xm&kt@WclO1lu!bKM@pV16uyI6mS`y@GJssG-zoqu~VG79wf zG`T{-UdP^K-%hP4A+U}L1vJpMPa~uYa5+CZbQ%GxZ|f9ICsTJ<9SfG{!%k1eqYJ*q zclEgr>waHu&`-;1kKM;gT$7I1KhK*mbmE48$7;$jCj%W|6ceZ8@>dzlUPzaE3+hgv zcif?g97jrRWcv4tt&C*G8Z_xo!}lbKy09MOFn_1PB+aofK4;-b{LL%~i$T39r6vI2 z@X9-=bC1;N`bYQYR)PT6Y%Ix4x~!+$TqfPU*r2XkU_pFJ5UnXbAb94dR&Y%CRA2_S zL71>o;veFRCG5%U=>or%?S!ILXL0whX&Ka-fs@{z#{mfaGF@*}uWfIY>376aCFd7G zDcft|#W1`tyI?W-`u4!3HT?n&MMZ`jcCq%W$Qi!l;}id5?r7hA~Upzz}UTJ61)6XBD`}o~T9ewdx&cdjEywKk*WO%+h6tU6oozAoVU8%?Hyk{m;g%2UQiCT1|%~TfV#*7rBcb z!C)L0b&0^^l=sd3_<-4bvOR~rqEF|SzfI3)gY4I(b>osNh77F8bVjnJDcOoC@`l@B z-1o6!1G?<7{0-|DFGp**2d>^K1VpkZl5;O#VBKrz;^~leNY@k`p z=m-ED$RjBbUwonjnC+gE``RoC&PUela6ZgzW`(bd)h$f*_e_->@xAI3GK0eZsoAf>7Ry& z$7w#-b@`yTYF3YLG%^a5l-dSHd4#hp`!!N6eT2`QVJbha>dhUbr3HYViC@<-lhQ*( zMhv%!!+qQL$OHcs5tHMc2t_AebmdQfp zr*#p0UEIcULb2Fu$DAAJ({HB z$do3N6b3m~V7Fw~qY*NEaDSv|MSg7`f4>W>8joDtYp<^ytf$x6_wgvU3z{y}VN?Q= z3@hl}%Y%kYaE64i6sOv|982u$M&t&vte*GlUrtgz<3zD(E9-i*J0`pV|y%ZBkn3*pCpS3Q++znabfF| z>GCJAHvLB~;%>?&dK_89!c=O9#@nX~pW3JPQ7A+5Ozlv32#$UyS>lIK@?}aXQ!xJ3 z>d>ntFjX=c{#Fd&JB?~Fn`#EQ^2$l);g&JoC(%_}LkG59wrQeMPEy*x;3212NJ}{x z9x%nQT;~bH4>V@G1vn#Amp5Q;IcWiy6k8h8Pf4s&<6d7^e^a7%Cah2MA@K$-+S6zO zky0nzo06|fsK{Ro9H^gg7eQDCAN?@5yvi>jOChM)Y1vSEE@?8=v@K4|QUZJ=j{nJ| zerPt@BemKQV&VPDcK$5g%`uMe)zG*xU&M{y=!4g0cAUZUD;f*oL(=&P>4tb`uh~I* zV&F(^qzIN3@@Bj~rHO#;gMlg5cwChkv;j1B9;x(z0e<OUp+x<1l;Yn=V$JHMuzrL@rL^w8e}g@H`mQ zX5sLtS024=RPrKNH?Gxc1xkMjoe|Zkqr1!k@ z({>@p^acUXX|Cs0uj9qZkPlg6!a^@i7in zWMF>0ji9`4znWhqiL3Ax(r-$U!PpCkMr|3wd@osmVMmCK^UkYxe0KVDGLx1%J%PLj zwko>)dda_$x3cxkcGZ2!7J!)WeHf;?7=Z6O=LZ_7>i}0U4iY!ZlEA}q zqjAHN`JM|&S?ykhPm1kB+_!cQ_`q9KhfI_|7upD+!m{KQ#QAwRbs`JgS$&U&g83d> z$3J2W?HvZk6NtE@*C2Hm)b38n$b5$KSg7PccRW`5s;(rOKg>7&RrUi53nju|^ME)d zjo*wy*Y1@yOrleF0o8qt=sBKFnl)m4mjrbU?S(cHej>P|a;WFax+F3LjBkY>RgePn zVOUB?n<_^lg>mz$=q8=#pe+pjt=aEqAd3m`KjD91{KEcgZLas+XK7JO-)($a za1vEAh&*#xmUzZS1WcES7AVdG&(4*QYzh)jvnTCtBh%e(TJOC$S_}XnuLmUc!wc+Q zBShExS?9MOtX+iQ{Hn#mm)Rbg%Q--9SUENW;;`&KnA>+{;nhR*mjJ{(mHa~yk4__; zL<`A}&W2|LUFvQJMYE6HJP`IahRE-KcUO67ztJ_^wyA4&<4}F}zMt6HO7~ehXxKlQ zz+g?rr>rQ=BRg?!+M@2QgfG>H4PtiW_X&f6d_Bs#s6=x%*0-7?KS0a|guSPl8;4Ur z5W%@AB6Dobqa-XhvP}qknJTxJAp(ogj85A2L&>N2vy}4$?#{)buZX&Fk}-u;mUWFu zbfASR_CItPbfWZf|R zEpj{GxRF{a=MG;EqDUU05TEyo2H}7cLyO)&+B?twZWR1pKeI>Q?y(Y<>8af}B*m0) zrHBMr^Lc;(;DlhAga)v%Z)cWcU-}z|9dht_h{DL@k_7QH0I~S%m=>sV#)*w*b9sJ! zc0R8J#SIk_8xf~V$-}$|ZOglu-E0SBzXbE@%y=LLYaJ)mSWCcBe3GP(F%i=xaYcm6 zAh6@Q>ViajO74jN8%?KqUcETgnx?8iZ%z=)2kL|!lCI@cS`y%{MY}6th=X9^B{15a zM;4X%fUe{Zt`Vw7eB9~{teP5~4ho+T$cDyF1I0L&5afPbL383 z9>@y$n^b2>FLwHZYDbA5tqQroQ5c4t*T@BE!-F~4nWxt9?p(T5GZ7J0L zg-Hmtf0&-YaR+-Vt+OzGKU}#LdC8zTZJhM_3z7bc20h)-y9|!jkJ&I~PhbB)5^i3M zrufrP8kA_;=gU3M$@At53qzhB8Ep`{(gFjeCGAj2pU5wf7JfLpe0RS=3ATdJ!daA)5&nP z3-8lyvelsyz)+}##1$Em$IPX};aRBB77AtxB){iPx#(E0lFB5=_3w0LLz{&IdoEuv z`P>jfY~>NXawzh@zoQPO*JNB|$V5>=U_W2NtXVlD6Oes=$vRkXGm~ z9IhXr-#r#@ujF&EW5|G&#PxN0%R?lz)*zMG5X+jJn~N+wTZ!ME()> zcSoULa$_W=*{~G!pQVmlyxRbuIHcUHn5bLt&vnM88CalvBuFa!L9wb_!e<-)O*;0x zbaFsPS?^$fxKkz`?Cq!7GVz&s*OMK|u5XhY(TL0;7Sm5sMZ;kujS3%)#r~}A`B^;% zQ);X#sAnz()TH*{vmKpa>Obq;+zCPk0*fiQtkY{+Vh2%F9s8`H(v7{wq;J+%!eZxkS+y%`o%c;U?gWVo;iD^apfSUL=4*8O#$Np`*FDGlTD$7g z1SxVZqjyg=sK&KnB?7IN7TsAsB7(R#&shSKXi3BoEp0A?OIoPgt3xN!Dm*v}sW5^1 z5*!v1`L8XZAz!@RSI#r~)7qqK9X>{lA7O8%c>bWE)r1ib{rKV+?T09!g*bBrYdH8p z>siO%%C6BP@2j#gEot|RcZVUH;T}3=04-|eK12x##|ex?dle9dVcm*j$3ksSpx9T* z%eeOeL#?%Grc6=S?>PNiRX%H})LhuwqV56s(kAZ_EJ;n7k5w#Bd=Q)&U zk3EAY?ZSotAf5)_jaJ9xY|^Y6_Q7blBI6q(Mxp?MPrEf8l3o==ebly_)g|z$W64xB zcn0hl;;a@0)ZIP1X+#_xypgc6Hj(V8yiB$ZFb)n6?%yppGq)Fi)3$OW3CWA7`g6+Z z=Z0;%hn3X9?|)zvzpm7c2w_K}{ujy81N0BGE(u=VH&>tyZ z9rV5^z$Za3#+QAcE%qfrp@~vdmO6}-fHtD|PaQui?5LSlyvB1H-`Uf4`_HPy(T(ah zyQotnXUq$-KHUvgXRei~0-WQ|TS__|QQ?;dUJdb+Wf+^V^b`_`kdC=1m7`=WJLUWz zC$h5oS*n!KQ?5~cJg2=sX@@)${L}^-9Gprz0&WqX~7`u00W5R>?J@}XT zjE~vdUqTYh@*pXU2nllHJY2PkCB$6wND>uv{HW=&=K@EDhyE!6Zwf0S%7R7tJ!G3%9WUVx@6t9o+9|Pd_SG z$^@_+@FXgL_+h&;0jK4{pZ~5en(*(b`U^dtVWU#R4s?5x9N_~5wF8vE$)HUJCoY{f z`mNy{Rn*h=-KLzor~|oo;Q}D%&;R)M%Ya;M%<*+5jZaJGb(`sPqF!S4?@4@ReQ9MU zO0_lSFO9(RVJt;(AR+5o`~?elr~47uy0!43TwlbUcs7`}&V~ID__eq7AD+82D}S4> zdSG`mQ`m6YZr4Qm|K@ROXW32lp_kqk|6?M2VqA$2Ai+5>*bQ{uv0t}S>&s$7TU0$# za2OdG=8&pE59R!&5=d`K!CF;#9vM8Zcx1Z+yBPf^J12Jr#eFUGDiRKst?>;B<>x`X zCX>8)yzAu$goGg^&!qxp6O+TajD+MuRpX{RDMy~NR)2>(^}MRbkkhVl=o$n}N)nP9J+7EC_=`pbnp}+kVmU(_RO4 zr5P8w_syjFhtGt*{^i>sqF*QddFXb9!)(-$N{xw=ZbIT+0rThfpa>1$O^fzG>{vm6 zKs*&+a${wLU$=RfEhzZ(op{lvg|=spihuA*P3MTpyV3=-^?j@_%Dl&Mo{f)|>5?gw z+CCzYT=KqA&FGnz?1G)LB;ggie!;iaR@O%n>eCpYNXjn&ZP{}Wj1?;~P8wD~xD5>x ztL~U3s>uiCD}v`QyOGw*!s#|wSFwzCgZ(n~qY%cdf zccP6cNPL*c)?QP|W=rJ{Qq#>#)P-0jPBs_YLgM@4xv54@qUnS$FDyUTvrk{krcmjU z3*p2s=#eO}fOy!ZEb>3(%?4eDX~`w!bSQqe^c-w7N;+x38VslNs@K}M?(iF!&$qK- zS6BS~jlL~rnOcg7c#mgkJtU4un4OG^oUQ zT!(fPjQ=hLQsJy6^cEJKelX}5<6Qk-c7S;dG!*cUK}|%(4+i zUPV$e;y*P0KLID7sx2YTrV#UbP1*wwDDxt8dGp78+Y-)_!8V0m*a2>s1*12}oU%di zg$UQ`8)xe@@7TkXKZ}qZjxTd$e?e_xdj0=#0Zy3nWyO-HHWe_B5<>QckqomIlXJ># zt8yG8XV3*=beO|gB(@hi9p!e?Q;bg_0V2jnQHUJ+V)Nc2 z5vvFb3P5*9h6~jxe6BG=tKOmOy3-EMj)Vg)Fir1CIx2p2Gu8Sy6v6~MY;bCJz=;sJ zS-Hatdgu>2_=HJ~FN)wxU=j0AmpEncfEEgdwoBKO%DJfh z;6xnp>l(~zNUzu0P3AeSf4D-|_@~^#ptz18ORlq*{=s)mE?$2F$#h96Ll!C2?8GEy zgCSPb#b}Uu>E99<+U)lFQ%*fnaE33T+1EpKke@~b1~Ab^&w1gcD!of{Q6a-_Q1y1U z2lX|}URrtTuYqidC*644H5a{ap^5yGbPppGoye3rkJ@0aVkd6o#qK+Kb}ZCeusl9z zyhavkvZ6f2Ji|U4{B)f3y|9`dG2H8<#-9;gvNj*8v^8VZmK=ARC4BvjgMk~R>3ju| zRhPXC{*F7R-;Q%|R8>MAb(JAIUhlk@lD5Su4JH#<3PPC;o^eq96jix`2jJ&MAG%ke zyLa8GfmMMsT%(z*d;Xn!*nWi<+078do}R09q^gKUF#{(XTlLE#x%1<893ZyYlfIqz zjPtcZiw!z?)~s2u26Zgb1s*^F1fv$lFp4?kchBr=>X__n%N5e?w9+KS&%z6$p};Q~ z(1}Jkm*|F^C_I2(f#&4AGmePTa<>LMsb}(U4_g|wKa#}5m_JLvGHmW+!~UV>;#TF4 zVoahYuL85d=$rt~fF`y@q@-m;}lo}LKz$`2I{*`&?X%QP< z47mS;9g%W_{GDz6$LmM?xRt*H_0q{tx(nNhY2k!;r*PsD8iB{}8zgOOk#23h7;kO- z1aq>4Fsx5RPjpQURZU*~)b~clc+8eV0tmT~s%@i7z7mf+wwol97bp=HJZ1?T#hZo@ z3s(#Z73-Nu`I?A^7P7vf{CIlL0TPAggFN43XfjwI<@2IEwxu{lPA?R_dkg{ zFFRw?KWujn{q?8=i?Uh2s8QXL?W@w6gQXDdmEr?Hs6#{rLQn!g2|~PJ8lWr@sx{g^ zp+Pc6^ims4kf{knwH}HDIbpy*AQvkSj^>Yfbt4nAD>ll}lem~dgXPivd#h7G(LbZ< zgwAobrZ9+rK(9@+V3m{f6M#UEypjN?ltLlEsn9?RX~jyZfU{DHMT*szo|Fru5VNyE zu%fCeTiLov!^)}mcJuQu{vr7DMW-bSQXVt2YFxjR_uRD=59)d>&b(|4>X#N_+|8Sx zM7ihRZo-$(+<>q{JMx^IA58G1T&6!jf+^w?sBdeE|yt#W^Xc`-`J5dGnM3 zqr`I~`^T8?KVY0ba15Rr*2n()@Gf`B*4x!r)9&uc@zsfAOGc-83NLjCJMu#o2X!C( z8B@yxoal$`%N&EeJd8U>d`A}olW(47&MCMoF#>=(5uEWgadlC!$7R9^aPi?zn)CWhSI9VT!i`wDDUGMnK*Vofm zepFboqWVfG?Cul+(HgNCN0e^sg_I(~$~uh-`u=VBpEmos`NSn3V95vTaQVk4U}}$9 zE&Q}Ugor#=NHTMRC{hApEB^xqv(Rfv86-rA4Wj_e9s{Kaar~i?7?35R3Z1%XQn`cd z2rEjV>p!iq$Pq*&0v<4fO8~4cte?F0oY9A_`bY0~>D;l0{ibKg?+y-h>c9u^?67_q zKJ87s`Tl&=WOI~Cc(i22I(+f;4GKVB0q~dZ_qIqTWK*TkIOWOqIbZD~CAIfbV$bTD ztmjFQB_bsRnfXu_#6Cc4^oJ|;o+EX8LD^ip7GRR2)&sLu)`4TO#hOe)ZeqUCo@-Vi zTMOOD_0N&sSL^`u;fVTc+`a-F8J~zB!1=pBvBtOs2t|eq0WMUEiy0`AgtdyXhM5-y zip!)B3w#xPT~e5u-@Z+g&+fV6%=Ewe%2@F98h-_{x!`Rf=m!SZ1t?=tTKWJWU4U6pH!`$g1`$;XLX&JRI3K{9%T|`h z8OI+qo*LE%7Y-heiMMtOdkbwE2j=TI;@DDg^xS}6>JXBD_xa2}eAIH9xFO&jeA}(0 z1W?PuDDq?6lvP#!;bfD%h)cU6K)XlR;Kf6}40^n`yO{sRI+d8d4h8L!q^@r*Rxdq> z@DBjTf9>Oy-TvE@Lj|GPtRb8^zzsOQHDrmpmh(pTNG7<3zfyk`DQY}B-rQxx&|GMK9n}EK&Wxtv-_jI%^ z=!nDH55T0)yP)gdQ-Y_kdTki5N*5dMyPsFP?ex6wIZFw&eRG$^9I4n|>w*L(iG^1T)WuaJmFhS@N zFU!pJ!~73F5wH|M8lYkZZ_kRGgHQ!fPV)q;B#Tb2thvvikA>!i3)g$Ao?~J zsGqiLSohm0cXwa$Z$E@)rvocOJmUG+JdCM#_Sh=c(0Nyn!?e3Xnb#9~54#DV>!cLl zaVSfwMOB#z5Qg%=E+i_v(G@cn2THB>q&(||2L>!S^YSrxVrU=45l0+xY^m7y^8hO| zgk=YX-S%BRQRghl@c0a)FbFePWser?7~`UW99MUn%G5^HIC?NHZic~mu zV0bx&x>AszAgn4D{N(rh%YOjCpS}oazasDhJN{>op?lvu=%QuoKOG+)(g9m!rt_k# z7A5lF{Om&X9YO%3wi6fJ$wBnC9O*lq&M~uMp`ehU0wiSNT0!2&2~jkwVR7p@yEZyu z?lC)FyZo2l&!eCB#5sG9!`Rs;p!Y#9|1Q_s;{!e{tzK7i6%_9TP?nh!x=ZflFQB}} zcz897grxVnPVKnaf$viHHbp!RVxkz@>VPu%o5os`gvC6J6*rm?ao> zLHLdYy;i?P;oGO&eUR1goZfR*)653H6EjXCK>;yp7?2KqhV|%(tip=Xhq3cESH>N6 zNYKY!ryhAT5%JSk%*JW=9rVYZ1a$0nFJ_Ft(*Ao>1pqVC$^A#}pUDOtgrL2Y;x^@# zHI0%9uYn+HLL?dzP$h(@B2bMKa)G|dB^$C%Wa+0IIj`E?dFBYz!>)jjv*j35t*FAQ zRb^?KsoP`W+UjEl31ln+?CWtvNExhL-7<2_fH|T|X}K#103I_ufD`5!m10k^N--l4 zf<9G>f0Tme`id8_;>Fn$KtW)6j z*_?kgfCX^@5JwzwZ0T5?gDn7d{8$ZIlEK|I%m`Tcx@((v>g2co*li0&3}D(spV08p zYQbF<5Nrsz-i833%%RFE#Ksm9PHQnc*lpQCa`1ya>Q7 zG`|bD{Llj^DNDFX(JnY=uQBNR65+4gUyjo{+y~($0N{69004j>3c&C|2oM&RY#175 zfWpydKyDwL8NsjdnoI#Oxy#H0l~Tu$ptbCCF&X5BMM$&7Ohj@iaGIoC2*87&=L_p5 zC!aIskV*h}@Wj_CRX2&MRT*?1clb&G<0qas<7*E1Qb-hnshSxcMe2_Rl+DB@`8O)G zY_JAO^D)Z->@xMjS$hEZa><;vzv<_>RZIff9shUy@XGC*{MljW-&v4M%Hjrf{*S#Y zkGE=S|KDe=ea@Y4bI~AEi715^k$HZL%9Lg_s5F?zXb{Sf<~hxT2BHBWl?;)nWQt0p z`Of#Av)6ilf2_5KbMgL^M&0G3?!D)B&faUUz4kMFhqMa$g|TxK<75KPWX(qlK}jSi zLPY6cj)Ev(5ETF@B0`KA0u1Rn!ui)Fu@Kw_F*ParNkLJ3lgrqp;%@$;3HKBgpZjx~Kk1Y$od(y{IwLKaPdVWz?$^C3F1&Rh zYE-L)aeWU@6Qs3kHi>(O&YDhyYlINLG28V)6w);Fp^e_W5{NWFuGYGu*8EXYR5YJ6 zv|HYd_l(A?A;qGSQ8G$K$v9Bsg0Ecqu#S=cthquxu&D@77a4$a9869)#z}e^87Y~Vn$M`AXHC6vv1B2vjL#>cZ?}D|2q7b_(cn} zt8cX89$QpxdUnz8w+Ldb*cx>E{(RnJH^3@cogOdjOh|SDM<*16U4#|%0wE;x?+tfM zvqqVe>I)t@cSW;kN_ig!d-uGQ$Wa-!bVl@OT_v+VUwiTsnDqG#XnV$Mn6k1pTGyNM zuUc<2@A)((=lA^kp!rk=6@WR(5Y25CX>v6YMgkELSaYU~h*#T8xp30HJf2Cd7gO6Q z7xK$@d{nkDJJz2B(pfVxlS2gMDHnx=(cwjVo*0N-x9Q9*grrezr(QG<0LI<;o=hzj z(JjU`^iO8$Z6Asm6Ta4S(G?S0eo%)sKTeX0jN&V#g&uj5@BzNqW32}-YAYn;GIK>C zX-eCv7fl0zxetGi#!sGcK(6Nj=>*JrX9Zq;`wQ&cokv0vc4p<%Coeth6GOZN;Ia3Xqm%$ZgxLS#eM2DJA@H$+Mq<-vcvva^pt<1nDnng?aDeGkcgdGyU?2M9 zH?7#~TKFpehUKJ4Km(M-%xTO>*320~P(GM{)r=fwy@QChg7JwUvHqmvDtF_9Oa;F|{S(~h@4q>?`R(6}U%VfS57Q0os!lINPN`ije)S!L7ZK5=U?dU2 z4OuEvhz($?2A&cG2+$EJXuHz-;`}1F0f2W(5`dCXGD^ll+0WK!ET}E4{=a&3Qw;rL z05r1($Vm)>!>;aO?N4ZEk{}>Lpd`~yjsb|qG$>}CTgsHYLNdxh;sAJVG=_8>3cg7I z9M9K?{%E0QlD>005wh;tl~(_D#V8Ma)FktUnf;N$gvruo<0~;pUO& zF#r^1$2yWgIWY2=kqQ&oi;%c20z)RiS63t`W=;hVmr*gO&7=!I0)SCX-bMRYFZn~~ zqSb^8^rSY6F?TZ1ZrVj(O=|hUSXSIYNZO$_XBcN>A|}@4@d5(Exiu#O1vO!E02F|6 z&h!q;-fA)Syxm*A-F3jO=RQpWdJTO8AQ%1aY?kozW|yA{gv+Y{&w1yI$gr2+JH?UC z37Ylsj+B*|xh4s!#sVj~N=Kxi93mp zrwJ*xvDV)*=r?BmNon4~8eb(v4>%ujmM;?Zub)a00<`l z|CW)G6mqzzWrQLy<`Ul$AF8;}a%`ZbJ__0wB{IMykLkQDAxL2z{R} z`S%zjZAXlb&sN+#N7G5lJVbSvOZz7pqDVyN!&u%jqmZde`}L_A0RGlS<+S7^!48$xBu(k~u z4k45M^sHDSAk4qnH)GmuOK|hZ^8f&oT77UeYyJ;F+qC9PvfN9L1wa85CkO()=750! zX&DvIx0!U|asZgr`U430*J@T$3QTJC0oqQz2yLfbv|wV359%@FOcJz<6{o|<)_PID z4&7_TvS;!F)dH3O0tnhW!! zSek^(SEm*5Vf(NGz#co+@B9cq*oIFpl76~iKFeyp`oJJTnu!5z=pIa9?`wiJlk(M; z{S_8YgDLPMF%1G{fP`I&Y{sJbVj)@@W6~a~RjBE!sam3FG=0NYA9FZa*S6 zu-QYp@OiBU&@0b(+;vr_7nT4x5r#LxAm6UtH<2-fCn6>Y+Y8dn>_{oIVsZDnCOwAt znKQWSj*GAN zE9D~?b3=K2{a7`*wYbh_*B|xR+1v5dRu`>ZQ{~hNxT4}>LX=Q83$V4|qt@qh^4~qj zyU+U+OV6m@Mny?^QCPRwoa!HX5 zj!0UkHLuM`D)URlw3@%RI(_O!BH}*po$yF@(XUS^j(b61SU-qE4{AT1(EuC~jYVZr zJ^;M?<1@JIg!_)jwI?Jg0Ipp_%B%&8kPc8%O)APbxGxT zk-C`#$-6#&VI7~E#kh0ANBD<1980=JAk?|*)Ns}~yr z07hK75M35t2^kS{R9v45AW9bIW3wVn2>IIuQX>h@$uNl{`B<|8b9b%D_<_XR9Z@DB04?4u&A~pMSZ2Y1`#DoK@N!0!AJ!- zPDJ@cR0wd)lV>s;7!$K~p*4c7$_B(DA4Sk)X%4ZTlS`hfmQ;*esx?YFWdUv8t zle01E@z%Jb_Y{ok-TH`rc-C#!2Vc&73`B%xJxA6nD2Od^B*ht2Xej|Aunx1@!M-Lo zg>!l7Dpghx^?Yk&j~7eAl9Ev}O2z>j{Wb82z&T&)vsUNx;sQpBX1ENJA-|VUAm(|| zFoTVfNhwL+S4-lDzOF9=HHUY#JgE$eh#=MsTARhd#WD^6l|NOJw#Ly$nF!0<7X$GZ z3Ts`2UAF)*i3$O2Ji3)c0@_-4mDU-VdfwVv4GgL{e4fPpO5oNCkr6P&k;dvI8d8Gq45 zz^qbBN4wrU^1ST_>U#d66ENsPx}= z=2mhX=O`)YXd;ck!;i`5DZgaUWXU zKMo+cQwIc4p117Z`74KE)XHH1aKtA70I+J-;~+A|VY6Q7yz-hm2Crt|G$Is*q$Ery zh}nA{P*^U=sw^ofgd20+b^u-kfQN^?iYL3@SQ4O=jFNGHhkC0IuxSNQlt;*@$aF?4 zh`NoS=R63}LzU3QLb-`|awSbYLO!r#;;Srcv@Y7(DQDRhzVB9@b zad*$kGROOc$2Vy7sV>yF7H->kt;V?-gz<|N;X=uq&r%)AeIn1uQe0bw;P(N{+LP4} z9*&9iVA_==MGU|mB>(_$TBRnc@B5$Nv5SAeRkix%0LTIGGYk;F*!UVPFwy^R%9m}? z`t(V7X;nwuQg;jhE$L56q2zfvc~X60&NKi?&c-tG5RuEi7LF&v zPaIx)>_@*4L=*?@8&1H_Ym7(F`lE9|f-vc(Ss8aFj^`Z+Hp7 zly-~vH~|2FGSyQ703ssh>A0!`LDHD9dK6CEng}?_ey$t{DiOe}nUNeTRCN$GlQ_^x zK>HgmM&gZY{%+J|aE&5Y9Vdl25sWIkbBa!kMk3V&p@!02P7rb8v@K!5IW91h7ssZziH2l~UWJ6l=h|e%`2_tG#Z= z-x=*6n*=a0uAhPOOdZ%BC1WoKVS=mmixDZa5Ymw@ZY&dAcVA3jY z-9KFO-R}q7=%Zwmj3YAWA8|EAm-#_}_TR^gJ+};0Ks0$8YEVPSyOtdG=iK^R7awL5 zme-Y<*^N~CgeK%_R1cBa!on6|46SFIE0YMQ8l{JRJWD*?)4o`GxyJdK8hxrKVxZ@q zA`;%0C>pD?(tR?ofTl4U%tL_v4iS#Ss@36QA5)RT<~euXDurcr|9&FSw*EAX`>ZK| zAIuLL1DN~gznh)21(_K~Vfw1u(4y`Hv_9R4(U=4Pa70uQs0d6+_#;m*6m(F6RGcG{ zvTIkmHh!evdyYfOjUi^kA{{FJ`}|uk(Dv<=tVRwq|Ks_a)_w`K9M_Ov?y{^*!LHa% zLQ;;_9I<>*jj%Q>LWdJTzcho(5@FR*wM&fwfRR_fZSWa;F>V}DPqw3&3l+KDYb z_0Q0*AmcIMAO7VoFn3Bn5(0F@3g|1gxIB0jD;ueqfUT0O-tC9T10dz0~NJKg@_}|5~#9PI!Z)2Qiyy2yQSdmo{NW#+{stQ59iupK>`Zu^L`b< zzYD#b%@@YhHa;_L9C(st2~r0^`e2g>O0+%aAZn*DL0ACLgpk=60?To*$FU-hXUw53 zBk)lSb`Y%@NeoWXnpZGmog>AnSX^zDLTnU*ew#P4M?yACWA4I5?Vb_oDM?%ycloGt z8JIet0|1~KG+QG803ZNKL_t(z@5va`yG_FNIb5YV52aE4$_KGw;nPsAUQB|129OM( z5Ed&NIOR}+WUT){H4lh9DX2osRW}0o@R#3rl_UWrqh##Q;D6Bzptl}|=rTXy=gchm z#pY*lK~@DSd))WpmXY6iuf^|L0^PSZ#A9m?>vLbUoAB$|CU8Dx1@+&paJh@XLF>;d z9JY3$!7P&nP$h~UKb|Ru0KnC26z12K*nO_RoB!i;FIlbdo~_(BD=S|gzC~}`;qoya zf(D7~xA5mD$Ss3dOY1MYCkcRG{5orPC`0+{-^0di$klG46b$ z29y3=PwVyRoC>XW2`P|T^>SZ3JXm>;(WhvyX*nH6i)nBH+|wH9N}-?ZxWjr%>OaGLcP zaf}dDBPXx$bRp;z0H^-=%hpm-h=`CP89=&qG{`rm7}z8oso7xn1sm7dhzX5|eW7(5 zhbP!&X#%_Hcv3LD)%^ibhE2Vo# zDSl#x6Go(2pqGbA6SlA+{FMbNB%=Q`zH?~Rxx>2s((=BsnD$JEk_j#uC1YPF0MDNX z@nlcXA{*RKXj@wR`uUAiu)Ddwr*uuIqEs+Pm=+hQ`^s-cdijas@&|@cgIkN#`olW` zIBS){XEt!I^M!lk_XW5w{>SJbjC=4Nyc&Rv5>PpUyMH`W4grArUn-hkTk?5dxmZ@` zf9r$1cd7)l0+B@T>XcXgGc|uZqZ9d-VIgxJkAL9PFoTU$0NYMXqoRWryxM7TRV)&O z_kOJ>B+-|s-(uuJlc1Tml-z}Y>#}2{wM{}qo*$CmNT+~~8#qu407afz*plJjpkddO z_vmwH-}5m(erW>$U~=2Vr|CF1AVImTjk*tWBHlX?YxJtd3{zh|0M6 z>I?vz+yW&4>{o`c$j&Vsl9O9F&vE1fQp(0sh!Y(t%SkDci4Z5EZIZ-RBIJUhnc-;W zCn0CVc*!~5BB{0y+mov6*TkLjuhhn z_z6J6Hi1)iy_1j8Z;!nzK7UkCwP18lJ)vJa0KoET4<#f3C1d}M_Pr*f;`zpjS~D+% z!I(N8Ce7*{SO}qo_4!FV+eHotA$Af`?V_UiwE#*IfRa%%_VLiYYk<5V znmAnNz)JwG`^G(HV-bxgG7lr=7t8$TSs*)TOIb2PK$R#SS$~!s1OWKJ#j#1|f%g9; z0Dg8sLFGP5^hT<%?oeS@;c!TwO3 zA|e^dGIbjOjQy<15q&=jNiGoz0e{tnpx!P-z9=XG$Pju zK}C`%hZs3Tv{MMm0+7!P*8-|UNafzc`xLWQMc{W!NT3b*Au}0Lg#FLw1`ydcjY%Ag z6pL*xnf8*;w77pvG61x^e@w{)myEw( zS$nnXUkAVsRe+j({{cG|#SA_1mOp(hKDXC_pPR{T!DXs~Zl4AE0?;EHokVXx^A6{1 zc@l*?%K!?@ib*R?nl&+)v}V#S2rj5#$C>zX$?N*nE@k8+Uu)g}G@;&o?yy=Pt-cN7 zl+UthXpTmCUlN-=7c39)5Z3Q!Aplg0VDL|8$tMBe^p%R5RwT?idC%cESFJHyW18gO zk|oDs0St-e!+sJ%ejwmQLO|@;BtB?Kz|E(P001~5T3WFiPFwu?aX6X{d3!oU(oKnE z?goIPGfp|8_bXO90w4vZ2wa>`LG*{bfWZt0z>a9DvsV(K)7mdVmw8tL0CKnFT?L>f z5wclxn)Q7R0Ya=p7gJ#TX_R_W!1ygGBRU2ECb#_%H;*`PpUlb8wMvH)X8I!N#F6$2 z&-R$SSdv4>9fp^KO|o>{OP!V;)$ivPc)9bk{hI^`qK_Cz1)$jSCd~cn{~xq4$TvYI zD~sc0eV+TSNXQR}4SJgWpj?1i*d~Eska7NF7R)4wSa`GKh1SF@JaV<=0gKS;B5S+s ztGIYhY+iH9t_i{5C^M%pxD*JPnz^j&s`7DHRf@T88LfE@m|qlveqwME*h>J6q7;KI z05Uj78z=g{CCr?mHE&N%j?4gnqsnC}02tr5T}h;K2#&a`a6#LF&I`R-xk~eU40geY z+GLWLA=qSquvxpX+Z=&e*mihC3b74@i*{z^*8zZO1ILw2Zprxjn{bEWfBo81+d%KW z05$CL{TpnLZ3_KJRY)R;b}#+u??f8+gYI=K)T=!Y*xb;z?;v};ZxWP&XE($TOW#J} z?gpfaG=Z741_h2lekfwP(X0UlF5GoCub9&x0K_9-Yx?9xsF95ii?z{ot;W=?MjE^J z=la%Nimuh>@vB2c?4Xd%zK$Nigz^qP*>sk=8vq)uaq(q6$+J(9dvz=eYMXyoIVyGl z^sW66olp#B3P{1lEHNcfew*^b1%S5S9kg5klA>v>jR7(!A^1XKW)PeKv)-H%$=C`2 zjcPr4MDJJ1)yZI_6QR(HWW9^*wb4CAn8XeXN0m~0)s2hgxd4C}U6yBRjYcG}Lu*b7 zi?|_sN`GdjDydW#2239{CBt53G?%1Q+4_ z(!-Y|iul@D^x)=H07ms#zIze?G#`21e!ZTeFz#+7pn!csq$xmI6?`3REv#Y7o|Xb) z5EFrCF8imKSS#1?(G}24q{##95NrSJ5qxbCMVgq|s;F|v_gUjlfJ6jn5Gf+K!n7pP zwB|CJ`Dg~0*P7E@S3B{zE{Mm~ugv@^3G_*dI+w@e>U71_sK#+s?{!_3YBl?P+W@P8 z=52424OjVB^_o#Zf z%1ZTcm6fVj^~w6FGtLA6F+2uZ|JnX~sIPk)vcqhM{=b;-Kc5{@&tF_iKYd1f-S?#4 z>dAU-)tDP90)XiEGicFZ(o=8S@AKona53aP%gr$jzO)|wwr&PuImZCX^}wB`#Nihpp=_`IOuM7L%ay<5wKafm;nS`+68g5tQuh?L^+Y+r|P> zF-T#UH5}sWc(ci@0gisgL1BF(4;N0JEkHym?T`>7{hKAZbjgl!h>usF@66S& zcn~vR=(6$3j)OiCz;Tqo`2)^Vv7it9RVVMR|4EEeJxS z?LTGfUMJiu`u#XojAGV5Pk`GR5dZBA(R}3onf#un1K^Iku`<4ScPiZ6qXF$gvk0`l z0T6{C2qAGf50)a}Qmnv1?)JX!mX9xUjyfkM`ki#hue~eRxL8=*JUN%=iUIkGt7=9J z#7+n%i-b_sJaC<40*+1QPVd)|-vU6?F+uP0y7C_%SI3IT>HRad3G)3gITV0}Yw2O- zZV1pOB61J*yt=yR7{#uQKeR1uhG@+p?6VhbI3ki;z0}!xz_gN0kpuxsfZ0LF02jW* zJG^N`;8X`mpqvvfDIdd-J^Q$6?Uz!^ap&{Y+m{^g7P^-bQ5=esLvUTDz^^IchA_NT zE(Ks?G&S-f0E}(+E-KV2wO^)YQtQQNJLN)1Nvjp}ZtG*~f?4>=NhVtk>7F&+vfUur^E?< zZ0!AO!5#_UWC_B*aGsc_ujxtt?|GAC_Y)5sL}2oy&>~9dG|ikM2oZpO2e6Krw`tAa zGV|u7h_kv>TJpx1p6m4U-`*UQZY!m5z=-*(Fyx8Da6mHmFCvrG8zKfLY1TiLPfL3n z0IFPiA2u&~rewo748|F!9D@yS1CApmYNf9ij!Y(^LO;egj3Y1G^)QA^wgBQ4b_rA| zuGD1!W&$Wl01oqU)7_)6`uj})d>+rAVi=lq8;*>$Buv@Mgn;^;az497&7q3|t7;;^ zEdX}^I@le2@#jvD_rG=rT|mxVAMTUxqI#+xD0c@$ofhW%eswOUkET4!vE2HsibCO~ z^?-_HWkSWqs9wjX%YN$zi3Nab7;pP!?$rb3AqQB~%8>%m9QF>avFt z9`8BIjs-!Rd=Q9m`fQEqFb-{7nvViVK{JzMpN(PWlL~&-0`a~3S+j%o;8JvFk zR{$ug+oa|m;lN(%v=q0DHj~tMpnb22kW%2cZCT=t;oWqT zJBOYYbM+|z;x@YXBYqC6Od;Voy{?2(N|$jQ@%*&sJ1PM9<=ufGDoFwkhw7x=F9FbfPrjXZ{L~n50qr?B`VO4o$4EFGvCmNhYGuzl#w`E}c6A1@=ulsK zA8s>e^LcJO<;vA~s!#(&q`k1go)IJbryZpPzI^I<^lk~@!mpKBe45nP?BnC}s8K=v zm5XhVfol}NkmjdFhr-;tDwe^}Aahhch#^7YG(a=6AcsKoD-jje8UnGdJMDKUz5@`o)_9?c~ zGUfnm+aS+tf52cs9mfzev-6RTui_mXU%5-SOx%jJ7W9gm>mF6N^N$ebp2r0ySF{izvW4KxqvU+Nr_^to=_$Q zU0L?OHL<_U3Hmk`SF7W3H@EUp z<#tbg^45e+We$Lg+C39VPKv;hLPZ_PCm(+l_wRW(>qdaADhl z0)Q@ztDB{y%0#p+XkNg(I2yhawx8^>uZs&r0Ay*+?*`QpLdiJvN9za2<3Dw)hXOw_ zMQQbdBW14tcq4!P1`EKi9r=qvgV`lQttQ=vpFU?u*Dr6pdlbF;{2e8{ki&F*@y*Xz z_hx@?)MZGG!lKw1Dd-r0lK^6^IktUgPU|M!hIgDZwCkF;M(%xukYJ=rKoC}k0N##D zS`mtJ&sF1ZtR-)MbzSWHrHIxz|DRRahhG8F^=%Vm_d5P@-t|jwa1p>NMvRDeP=VHr zJt|@iw?NR=pZdp`mq?N@0W#XLe7rSphQo(7|f15j_1H|@C5M37>dW-K;gPFf^op>}`;{@*# z*r1Di6h?wp9#b*_C#2xsmgPm>$zPZRV82v@nWH+L1D|1kCIH?@E0<(~ z!W8*QJm0+l0#O2KpTWbN2rl+q_d?=c)(0!b3TM9BeR=AQL(a`_^%I$h_wAmnNBUIxth}iQIrVz0Jbyp zuguua%$td@HYFPQIwd*!&9s3XHvfMo(enPWm^QEj+CMfCzZoa6}0@yqqAes-&4=@k~$R$9BQg*O`gaiszK0=NK5#!0L87Bc@rAG$hIcLj9kM9IvD6M=`xczD?r`NtSJzXvWfYHZ8U$FlI=_n_x3?PvN=+8d@BjG1Z zm;IoQO}jshj$P60l!SStVk;;}teBYvK_DtpasVJBsS>bf1?_*`&`Ku}Q7V8OwrY(& z?~{B%p0G}+u*j;NfA=%qe0(Ju^{EE{*!F$aMa-x}gsrTR>AgAoyMV7p>)j1R0&&)y zDjXWqazewO0AT0O2j;q!J2ssGpyjxRUr%iD!4?3=flvtMNKiKCkoXia1!rO#1pvT` z8D$Hz;|&13yT6WC*!y@pYu?R(V-AQkfwZaCoB!?i#+Zx1#H1`zM*}9vC##%em37GO zy@DB~T%{^&t*dLzX#jo{L<<-^EUt8K&D^7OX4)xx8(!BiZy=Vf6vNHnoo z>t;Q$ww*GU0VN>LzVWWnm6lI`ShsqhL@xAj9IYFfK)G4>;nkS=Dk9p>%n`c}C}wD_ zkqe>|fBtP(QvleVUARZ3F6XG4w$vEmps8q#4y{cJL%@ZKfeLbK0D$Q7_TDD|Pn`~V z_j!T+TmX=F3nE>0ETK@P+IPnV_cJ` z(p{#CniGJrA%#E+X#^U+hA;twI@t63@y78HhCVtRt)iIAL4wG+&2yqMWg7rE6ggsx zI`0oz?cb^}3I=w%ta74_Ts@U{OA+wUA&Q9pwz|@qx$6M{v+iFJWyW&Dpqrl7M+5d#nfHS7uH(r4xTMwH43sb{m2MncT}^ zMlv(f!N>rRs)FBlWxP&`oZ!3fwuD{7uR9R02B0&e5}=8pZJF>egputeRzx` zC0z-SWN z;6R#~y)XxGg&$&)%goYAxbZ^C4YMwgBD&e! z3G#?d0!mj*_NGL@$f#@cJ%^i^etyM43Bh_Q;cwq-4}5Vw03i3byvqR`1t89vlRYtg zD+ffyZ*jXnO8^cD%x?D7*+l@*VfLlCd1QkFGEcMb3*Q39#j6JT4 z&ljRZ%~EOcAj`%)(Kh#zTc4F=bZbk-VK&~IaGw?0Ae1hhwk#*R;A5?ILm|X()}YRA zFd>D|#7Kh!$^a8dacSRCue|iw9XF|ty(eQ#?=~fqe7KCzHtQ;N8i)$*gO9BZCEM-V zt8)2hmA#A5l`Xa>3dnJoYNz7mFso}OjGN@12bgOXKu)&b{QBi{D9Wx3(yo1&`{HLD zwnz%}zCE1;17{Ubi03=x7W@am2Lu3}UjIi^t~Y!QQT;Rkfa-h7<=D0HI%rpe5DCN? z667Zm%xK7y@*<)Dj7kAEovo6nvAC^{pI0^nu$FiJB7sAL=y}E}Ap2aw%uE$O)jbN0 z8f}b$h^HiIYt|ko(#zdMro@LY)}WUf0=ROmi$|+D`|UVa<#Q&0%H|NlY9Qf0VeBSlJhCu*;xSLO!-L&F&I)$`NEx_D2JZ9$ns7&7p08%6!u}MH1mhsU5 z03ZNKL_t)&<|mrUu@uRyS@>KgvmbI80~BJc*y0&!)_;!}KBLP=xOqeay#C;4$-6e> zUPY3MSaZat!P+lU!@Ir7qXu~{0cA;IdE2QMEdhWxdab~<{mwjK^VIa2|AdN2Vtrgt zwsD6oiozh`f@2>S-v)*hO?rhq|im>Q{%A9JJ-+rj#pk5~O#AHZRq0L)nU8D5xb;E3Me z`*Pg(>}vpkhhCVCPQ9m~Q=ch#e7FfHA00gF;8$lgpCABbkmX*($5+4;%y7Zj5tQ=x zAn@J2$x8zMOz=I?Q&PF9V(a(Oy*&>()WETI-&0zl!1@tr7J(rmtg{taA-HHehySThA^6i?F4M>GWy ziiRoz^0LnX0MT!Qt0o;9_vaU<8~9F*&vmnWjcZ(^yW)f*Y-`0t8>(@k6s~Cr*TtD9=}uH~@+W+t}0uxI`vtSoF-- z|MTs0w-yKh*u5$5IucZgjT&*pn%9zN3leTSv8UJ#q=0Cb6P42dU{b3O#DPozyz%lK zhSzlSsPpoKq)%8Ql?ZV!F=h^lrv{{H@1FMi!Cpy&HO`vVb9qMlS(oWGbAQ^W$10T8 z2G_#;Eo;tW<}$9*N4rX&pf$=Vt+#=&l!5WC(*28K?!9R#(bg@lIP2cE4Cn}5-E6>hkDWCk-glS1UM zW@(E6*L706qSGy;)&`KWZx`mHxqQ6PrG zM1kb3SJw;qymDZ5Z<7TB4H5vfdp>`?EE53K17-fvoI4MFWsY&cSq)H_bqQIWBm|{K z->2J8RWt;W(!uHFeqs?NXb1+h6|^8WJ-M)$oe3da4XAh>HM46K0$8@4e9-T=)Q^G& za<0N7dCKoVd)3WQ)Z_CC1pz4IVCKiC%l81FRYh`dJ$nCe0VY_NUl-!ILQMcz+afys zA%zX3OU-dI;1Cra?0GI!Stlxv!5Bv*kS#)WKn`~XASjYoEwlbM0FXd$zW~TgKKh7% z##^^02TZmo!GeQzAnbl-bUIB4D*zMtSkc!nGlCI zNu(*0v#^y|!9>Cu6N{jQ$tfhUxYdgn`~U!Lrd)VX3bPeX%m@`1@g=|!5UWt~B$*(< z7IIH4tk{mZG)8UKoqFtz5Bm+xeq<+__+M&w=lZyL)GR>+T$iRu7EB zJp*3>09@YwIghtS``Vz+xVqC|^cykvpv(n>lf&dww&DOG$HZ8vwB(HdkdeA~Pyr%D z!79v04A8BfAh8fhiYT&I@4sT6iQeWta}VNqCm6wfXtvNt3Vf16@S0Hg$sY5?f>zl+ z=41I0$jGq(AP4N)H}jqS`~6TwAWsptuaIgP`YPQ>@dVUV%FADFAMDTi= zV0~(uegXiReWUQyvHJ&VGi|F16@qbozP1@i!ix7?eJBK13aNt%kXyeC-(H0)uc&J(WJ?khjk`IEg05;pKOmV|XwQhBi8Z z_VOq6geY8QFYD0cg|+2305I!hiR-`7n0fNPPXvbj<{fLksQMXS1R&%G<+W$R6vD7j zD+9ppBuO~{Fu(S}<6_5EZbslS5vF!g0>9LzFGM6EMI^giN|hV{IJV5$3`{)IpOP+z zS-BpE(!=Tar3>G-SAaN1lK!VeZ1%=H0KoM2OUlLy)CEMyW#;5y2_eLivbnr9vI3C{ z&E-Tyyxe@$`8xri=7kk8>z+^0?76cK$}HXf%B28+W6vzN)2$Kvkohts(?zjw5FXWZS~{Jyc3U9HCoL1#)K%4@~9<`u@C z2Y}7<2H?*A)A#tj8+RQ-FFj-SlqTJWo!hAE(6@?;;*%MCl_07n1eFzn%1J4zYR%oW z<^@f<4gU`StX}`yK`S0ov0|rfbqf$lA?WvBov+OWfamVNdG8*nAQ_Un2tONqVSEB& zEQGs9?|a<-P5U?7%L)BnKV z*Y4f{t3fa+hzM3pC9@+gbs zT}%RD2@dko913Onu|hz_8)`PB|AUnP0KnO+434b+N^X;-ah3{t&ECskm%)(up~WPP0`?D%Pby;IBgorbrBAM-L(=Ah@r%LNNg& z!zrZ@_$;)`69|H&3jo)@3^c6Xxuj5L_66y20t`Rh(Bn+I&JruhFC|C<@|~#6`>Xey z^S~$QIM<+O<3;)sFjoZ-XN@GX67>FE!0fFuWC$Qpu`CV(f5VQ`2h)1NSa5Ujp6a6hY*sAQZB#_ID(pu?@0H6SG;gzl*?VBV30A{_= z1sAs(;Q#RA)&p>H>jB7KF~R&mAXy<eaDNaN2wB4`JCMNXEezDY;;{mmsb{kd; z0Gjm}en{I$KQw42e)?qx0YF|}K_@Aw27|U}))TGI0$)D_&~zwm6#P>u@EcxRz9i)<_{k2T-!BIRXIJtT}iBdP=KW6f9q#{KuRKg(E)$ zB}8TFZU8u^${8gOL;$Qg9iI0_upbs%4;2230E)|~{LB5T$$&lpfLFRMOJ$|6AVGQB zJa=`m_9(*bcrseAU`8qt<~JYFARhpdG9$S1;d%#su4Z&L1Yseu9)w&gQl`TpL(plZ zzjy?A09ne{E?+jI^U`zxShHyJJ~>9eZ1Dcn2mBwtKji_uKjndc-QxY}mmT=@rAO3% zI}fQM1)W1i`p_G{Q%(gVR!PlnM)4zBQF(3ciJL3*#MrccZ48Xw^#2v`@Ya7FG>+B<9uTYb^$#p zcqE8DkRRgj-h&sq(e7V5AeI*)K`yKtr2Q0PuL#N@h$tw%(kMFijPnsm{~RC*z=c=a zGxAsg0GI$2=2wn0O90TXKf34h@a!Ar7{7Y+T4r@3m|b{293kawW(bG~P`XNA*?I2w z03cq-h91-qYS4wjRA!WW%d|0qTg?hOS;Q@Sy&SOC^=ZSpQ~=O}FFGjq+{!!?@1MES zZ4zU?*bNu_0|^uk6$MQyB(S4as-6r0Ny{`oIsL%Y7q+>$hQQW!jl+T&Vf!{~73M1$ z0pOTpJ6ZE;%Y(MZX~fF}`VHO}iBTp8{T6@$M?`l5KwKA~WSFjGC=h2u0JeJrd+-U< z7_gJ60XWLl{{zlA4**b@?OqO0IX3Rnl8lyS@D#F2nwHFDE|cc6M6@ooe9{sCm~rQF zv>ey)keI8RM;g<~GL=);gYgT16c|gH1krx)5DkBD|M0)CU}%2=Jb!0W;)GmzH=j~ILwy$=95`lf?MJ}DXdXAFL@ z1qM$ua+v3xdE5_D(3?u@@G`NfP% z|DVnbF&wtp8Z^&72m(;`5=40{>F8Y14JL*j-EUd!jYJcQ@YXb1?2lG~y9W@aDa|jAkDzz|Y7fMZt5iKv^yVy-EP}TVjyZOF} z5Q9Bu4b0FN@P>}foM=@~ldmZs$P8*FE~krt6dH1v+)@DMnCBPxnmh2*fUh@j0r8}w z*`?Wnh?a;H7t5R{GOX>KKnIUIo><-gkf*Fy*vz!)QNHtsPQrG;N5Oh^A!~&KU3^gA==iLe$+HEit)RN0$Yct}wP77GoIx;PJguwIVp*=3$q+#Sf z&zZkmxyeE`T-WaWl<9x&1`PreMaVg+&=w0;Q>U46q16XbH(wHHSVsIpBlRefQzgw2jFIWUI+Lf>?Fca9 z?pGJe=N*0ifzdKh46=z;js3zU5~)#RjH+tyd3oRM552_u^r3(0fMc&-r4$4gMp)7! zsL765(hSwamoEmytEw8XgZDn+x-JlM$eE+sbS$nc_e1DNMiDA44k*S*bI$ia`!%1{ zA^0LEVXOjnTeQnyz|Zd={(V(A}+E@Sprk0{ahBC z8S%ddm|ge|Z5IJYl`cRaP8}#(Q<|W^lD<`n1v9FIzHfdI2R8fLMg#EuC$qLgWHFrg zis#AzRv>GE>^YBc{SB8R_VOBs{GefX~5<2Vfh+&F+Q0N zLF$T-d>L5U!!BTYAP!N7W~`c-0^6 zwQGu(#RIk0>bR>MgPOyvawfoSM-6F2cy#)G-wc0a-=hMUzCDO!GGRY$v zpE4mrm56KwQ2gL3_85BgLi@~npLj!OkmW^Wjw-$=HVRN}wE6b%__ zYlnspJpP4gZZ4f8Mivv18AN_-32Go)`yl39M+ujbGa}O!*|4#>xCOvXshl@>Rel$V#i{ew!>Fu!JiN^s1=d5PJb5?ht`VQTn zKuvPs#;I*$5EcKosjfQ!#YWMFX}{>P?RC4QA!4C^YYL5EB#bq2G#LRDF@}8Y!{)U2 z9|8!6Z4BL)FMq?e_W;0OW496}KUPx<@8tZ9xea7HEX6q~vANK&z}DHWABAwdlUbiy z)P47YSk-*U<5u2St1f(g&9*zncbX7lH}mcJ-;{dJ zEb&LjS%|xIai$jalT;(M#u(rbfyf-j%~#|%i8nr)?w}?we0gn8tEFnym~tVpj!nXn zkF_mZL<0dpb-oMjJ%6`+vz4yY8!R%hlcXPzfyk;@J9m73+aWJ<;GJ9BhtGVg(pue& z2wo)d_Yp7RM6Nh81ym7dq^IiVz54)eJ#ZYmU$XH+H&|7joFQ+|l{$Wi>Kp`v5JVmU ziex)zap5h3Uy?X5XVe%7vAWf5hrZbDuXk@_M-Lvyq<5ybCjmcoO`cYltx4=^j4>LU z0YtrFO-$$_sBFBIX;PIEMLUL8CwHo;z6GFr=h~osKUj3HF_#Qsi-8yTV=g&Q!&NJp)5$U(x!I!KKP}fjc=$>`pNzTlyPzowk=qYZK zisJP|>J4l47ZE9^&a7w5rH27wAq?EPnQpq-^f7EmT& z4yf@$Tf5lLR=Gk|Ok9^`64)UAsjqW(Iic<4_Xb4fIIHvE$ z4Hx_hq*KpP0O4s%`{wvpkUh#JW6c(arF*=|y+p1GRU7m4BQB_9yvCyNBq(l}Bv6Mv zyx^+S4emDXni}MrEC-e1`gs-wlm%KuGoeC6SFPeIfSs3873tb$_juk{Ho@=T^qseR z30XB%N|b3NlL{9}8AU)7FoQcpOF5&z2_v|vG)n-c)W6@wYETi+V7IZwt^a51=pwUK>0O!=Yy~iIWFMZrY(jey@Ke`AS32XPeNMQc zMy(DoMj9d&vqXqlGPpKUfow<0NMWiT@Y-FM96A}`&WjIi-wqb>t4FsE7NDxK;vuU# zS*>=8x&cv=7%}9c`6H=@NA{=;fvy#K?~edaUN@A(&RVz*lhGGA7>NfK)uP5;K$3VD zDj+u2Z3b?8szfI^Ru^|6P9@04w+}n`*Rcf~>kUwoJ>oJM zPzDoj8g-?ui$9qFT)iWlzqV%{Lc^=KUxUV3{n12iCz1A!-qa`tI`+KCJL$Et0Nxp& z*x-~u(0s6iPk4iG`IM?o|5Y&wNtsAVLE}&WMVlL!0MMxu(aFC|Ce)nul{?wKeq&Rb z>y{Q%uG20V2^VrzFY77qjRBA~cMg868XMdmNm~2<*OIG16fe~mb>E#x{H9T0(LAS@ zeg3M>0QT-97ub56xV}4jFP|b?%nD^$BUv-#Yyw=4S?TKY(vxd=uK+x>n#Z0WwOt+R z#_!!d+&wLH2ic>o(){9#cbKh?EIkMb_ zSQtRtIRSuL?GSf{CD{~R_7~Bnl29s*Gu5uK^KxZHj2U0K@8zL0UeBrOmI$S&5RlSi z)5=h?Geld1!C<|dxhMOcdtAQBLOpg~&b**bCCiIuni0t|)8i3M#Fr$2t4UehUT>}T zzvbW;dH_s%a~flgoIlCX-$fEI_O(v{sGHNcj~M9*8bn>oxEA0HEn@Sz#2P@eLRb0F zYFLr;uWJvDe?QkfmkhDB8yv~~mml%Is=nb!QFu5l7e|-O7`!GJKGBTyyNdBlT`AE0 zcRhM|6~HxjKD|&q=U_orGRo=8Rlu9U`Kt^B0`;(LVr!IDS6&8)~xk(8}tuSa(!qk?L`m0vjSh zu>*jARiO6yc{IhFJ!O#CQp_369ER!$g_47A%Utb=5T4mv%$`^M_+hr!weFQGY&sEm zJ<<@gWhqrGDH7FyrP$Pocg8q_m#^N!jvBZ?*WEV-4lY?uW1P76lcion{eir|V!mFP zef?dl_-%4usuTHqeK%I8O_W_5LfIGyl~{BtLjjNu z?DHYOsQt(OPYhhmVwG=-$YcRegb>X(SYx%SvW1j|T}3QmH6qfCvUt!K?gw!4dw*v4 zD>vni!{(hRyvQd3L(aN|z8kItKq(A&H^y!K5rRAR3s(V~GEX8PM{LpVdgyuJ;|H!h z@)dwB2M=rC3Vsi}od|#2bk(T9=-penW_SSS@DNWb)>rMt7TB`7`BpdgcUUG89aIZ9{{v& z($B)C!;!9ZKBuLjZIHRh==jP9|CV&(Es2~<6ev^)AT zdGQLK2I%;5+ahb^`K6;|An<2}oZ9GewAdao!&sTCW0B61q%W!f9g5a6}ceH->r+!XzBKd2rc8P1Vl6oL1s>X;kgn^v~ zaPU9oU9HHhzo#4Cu;hsi%-nHQ@_(!v54GWppFEdme2sTW)WDhgp8*u-bjA=wct(*J z1MNtTLS^UY<&0161kfwD#T@@5s#RX~YvilSicyKoW@MI)4Liximlp$&`tN==36O6; zbkFa7H)oIHE$Zg>`mHOYkw>E z6|M2M44xI}$|iLP){Hz_i#c27Z;(*+ z>hoBZiIJ3a+NFV#g0>2!=nIaqovMjedNM)cv{nR4ORmr($y^VM+<|X7@P*|y)HOwD zR3%TW)<{MvSQE+7n0(R!kyi%Z)aT=WEI&rp|4VQFbpHAa^?>a)eADb7-ve?ja^@IZ z9P@!=vA7f&8D#;QGM!2Y8kFol0E2Jq%Pj}KFwfleMLr3bI-@??2y_=gdWxYD#fz&= z5}R9SvTd0J4&=TI3sed+5oH{}Qrn!=z770NuItVm%#r&z6~SxI92oe%cUR~zk>Zp* zlHkh34iix|JAs-Z@jBB`kTv%hdQESDy-&Dqp%a_vSX~k(wiLfG8@(u&y!w@B zryf^`NKtnMIdX1jTJX@>Zr?OA6Tfn1)JAY;efIqXQ0r6woofp<*ZurMU-Om=s%Ct> zLzG`-+%q+WD^+)Hur)mr=f3d9J@NPdX`hYiBuwcvF^cK(WH_stCc8^4Z3&v|mn*5} zynol(@aFy7d`-R)q3FITur;`ZH|~3tN7Wkl2>cG7(j{k~Oa5x}wo^jvKfwjf_e?Ey z_@>C;1B6f$q1X(Mf9`5}k{_n@7PoE%nypp?+&E>y2Gg+`kkzmfN6JiZQM8O1pe@)8 zMof_RYi0uYUS<1%7{!fIbZVnUPeNx;&x^F3Ctxj7Irf?l^DW;fEQI~Uh*}qurCJ*i zS}(RWOqQ)`HE6wG={*IoLf@XU`H+?WCkE}tzqsX_tM)z=VWL{9MWhIs_>;6*nP}~% zSiz)=B^voOh}2_Qb>zO!?*Z`j`00AQ?c2cb^ir#1Q0m>dg9m1y%s5 zPYwjv1E{o0DWCHXx$p8L9s}6%&`Tk|1B3S5##ZEWCxA?iH@!$NGPV&Yib(aG#^NRb zO@&gc2W+=pcyQVYQ0*oneoSDF=#UoY`uJIORsPrewhI-MiKZkjQJR?X7!URR<{x@_ zc>SNhW=-}TLeF@Id z*E{I0Up}r&tnwbJ|4EZ6&6wFnZC~TU7=psm-ZeX{3&523+dK&iN)F(l#TRVtBh6nlPlCBtQBBG6b8COP$1(U}ubS0o0(7fhw*CBb zW0{Y#R+G}0Qq5sa!q=EBCl>GuGm0L-9fv#I`t66l_y<*8R}6C;AvmD{Ctgi0QcM9V zMC7ggZrox5z5$*onvcLQbI0 zTKf#Z)&~sZ>eKe6{rY`f1BMQF)$e7y{6~yDY@JnknCX8K$I3~kJQH_B%QpZ#kUj^U zdSlhNQ74AGAA8Nh^`O3A#*d5LAJYxv$8qWVpL_#PU4LwFz$qiUC~WIoLSuPNK~*cP zYG>c~{&nBwM?4MCZ^&h=y~%xI7xM!%Bj5P}Ma6ip8MS zqX|`Ic4HE6cR(>J3Be=Ehp0eg+Q|oQIrCTN0J)0A#FnyL;BxoUxUy#a5Fi{oyzKSf z!S@nAg6Yk zwBV{{ja5YQS}H9AprQTA@5JBK!FhD@M}5$+hd@cPsyHHOh%Xf#kgCr200cXM_E>SA z#x*$L?$7aZ-(tKJYA@vg@Kl0|UQGMS5yzSv+Vo7^KO)86H`AOzn zIe}`!_!E}&rt^&TOdEwg{U(I`-QRAj zlF^fOqg-<2yQ<$}ODkEoo=agp^JmcyKAGNw5|H2k5=EPRy*s4sl?yFUkC8}XH( zk|)M%64kL21LiExHC0*!C^0Q10L6x2OGG+EtQ}9Hbdm(4k(#$fUr!Dt$W?lG z1KfJ>3rWG|f8qMmc^eW}>5XSTM3{}Mtc4o+qr{PdW(q+mQk|?;P};c?3LsTBum_Df zetZ?cuniyKmchTQBe2LO0n=wX7*M|2Yr9$mUT^EP}TfV`Qpl zWUX($uiFWrzP@pxdd{kvT#NHD7AKCXc~JjDuN!*d9o&4rqdUx)UB9&|8;LLz)WjRL zs&)~PXCA!b$g2QOym$Q_7(p7Qo<0N!a=}D}5$(^t@=}vXwd(V1sVTsFm7=5AaTd@cDYa0({z}r#D(^oV$0+VM}}fG*vT7 z;5DiBRz~!ws6v2t{Vn!1tEKp7-W8_}ltY-3R4ggO#`@u9%8b7~C*Zbs4}>2HK~8^q zi8lZIDWA;}M+}yd2sQ=n$Ks$GYi5*JSpi#eMVmwJ-`3uJ)XN>!vK~UgnYJb-6Y;iE zcKSr0QzM?dwC_z@d;u`!o!LBi${YVvaYS6DA2_nl1T3FM?#m%D3pKF@h}&tI>P5m_ zacfV-wcb$m#V`|CdCrv5UjdGPtsj_QHeVOnB;cW|j*cdgSxeEaJR>us=Zz)fT;tNw z+pMTs#}yOJ92YsDS%hc%ZoZz~?ynbnv|qp5>*#+ucye`R?nOb~v{t(bVl{U66sIsH zQPiBqNua2WYO*DTYR~t#0(j#3V>#}^yB3;ftZ)?=o2iFsM!8W1{XtmD*OMG?_451P zFev>|LQ+{7Rp&3zP+OTlBYw?=$L?PC9#dbu1b|gnSn?ea-cWVjmKcv7oea$a-SW1P{fM%m1JyqEZJ>rahL6Gulso=$uo^ zybh3334+3EfzGZmBMHo@uea$MQ*H7JA?q~T#1A2xc57A+1i%;lY}^|9EI{w7wlUn= z=v~XC4c#!U@@9B&UC6G1gTdv>RGX4wzqAOUvvGA?t4zgqLf45}HvaQIpDeh5TEvTv zd@oc@+OkPc1LpcqHVBn4BJNuo{$~5~#A&Z^{@N3BXuCpX!;E?ZS{<23nykWVhSL;*fg}#!t)O19!6xxjyKobNf9M)DaI69F^5!`ph)zlCiqs@e9YI#g z1w*q&-KkNZs^S54YIVDt_aC=Cz6zU16j8o)}OyBC}e)=8!W-Gv+cE zs6GGOYwK9mej+l<*}5aDgsOD*J@2|ZFFx#jfSrcSttY?FN!PRe!I$RFJ7(7=Ro*m4 z5{;4Q#5MxWBC^=*#==T%@%*#u8wKFB%kS-iN{u>fP4eBUsxL^Bs7wPm>YQ8WJqWz# zZ|NV3b2>>@7CxOYnF6GpppmjE-W1G#X#;@scn1#UR}$D0s}q@mzq+P3koW! zXHgOqw=AA#!V_(&6qKOblE}KGvfRBh!fJrqR$6c{4y&#L9a8F;>H(FNsUs3lS*8Z6 zSVGer)OCUsR`gq34}X4|oZROf0Iqqh-|}ZZyZp&#JhSw3~;{(^n^5-*yRXDHISdYE_!V1tL*$PMN%Dl5UlN?hP{w9Rcn-@}(+O`T~Jktx9sQ z)DA2zFvP6Q5T&yi89Q)P-;V%p{vYuL_@S%oaxRV>II_=6IGO1RgfNRLP9~=7k*b!< z8cW(WOqZKD_-zoD!h=T-9=k5UjQ=*u1Al-0_m>3R{4d7^7;x-0-NI0JG{(%yc$r7O z%n=YMDhx<$kD68r3}8g$l~Ly%G!5XkiwYF19cwEsKtAU^0{WGzc5s`P#Jpg) zWK)8aYLvUXd8Y z?6d={YA$jWu#QNqRmSjbMb5tsV5x0RVA;jH%=Ou~U2rhfRe1|wJnwyw$%S+z2J^keg68!0svo5p3y}FPau@|D|JVm2Rg^|%nX2SH=XxfqznRY1CuSX zMrtsr1*bbjOXREOia=!c6!eTw9mss<C|He#!N>^h=5UL*d=JrOl-+ewOT;!?Q=V+hY^a&-f>io6dU((#?*;Ab1Zsi z5D%^H^sM*CGp2;cR2lE^C+0l~=+@ia;}UC6z<3R$Zq%X~R&yc&X$Y{zUd;G@MF4-5 zov=6U+3IWSfKOe1^l>9gD6AIUftf3=&fFR*bn#?7z{VYWvg9Z^yU5E*WOrlsIy!U-kS9`{Z&zk$S#CZ%)AjecMjnjXCIl?$y(-uIHW!k!BoiL?D$;MY>Ux?6w; zuRQ9V(CQ~RrG!lFh}4;tY`76+1`cXtJkLxOVbDec&-MXk)h!&{faXwQ8+fNkoV5#c zOK7en;FQbmjeg!=RSLrXBGQzJbW5sq1G)dMOAh-8;Fx{4;p%_8X4U4-;P)dw-B7mua1_DC9_KD(Y zA3O^XjM^W6@XtG+R;(E*2X$U-Dr*0$l2oZQ?Nmp#z%cA2Pn}&0VD`RtuJ`gHKC^x~ zemiZRy+mRRkTHf6K#d=;Bq_u5a%*UZi+>uH7#oH7KApoK=z zV8i4+4s3mh-iQ?)8ln{H63y<(!X%-Jn@uk1PU`1ID6Ck?O8|?tK@*_QdzL#Ux^H%+ zH-bZ_2kfc{){%jKYz9jT{GcVB)=gWeA3Ted+t90OpjwXT+O(F0lK)aNIf^zxnGNxrvkTJ^h)bFRm+mb4MYV zy*Sv=IR6y&jc2VEXbNT?KkS7KR|D98oz^wI>(H&%O-WCTT57VAmc%==Wd4{HU2?0u zQLXkLx!-eVh9$d~sutB!osiAb6d>^yh}2pXr4z#IgGTp#2Vk|GmtvRmHsF8ty64!` zlclOd#Y-Yg5%9%zOia06RoNQM>SmWA42X%vh!La#k=mdTo;rH)*rfpWAJqp9_4knk z9C6OAJaFX^E^Djx!bCSs#K@pEq_bEY1Q zy6F+iGibba6sYO?fp^4XuLF2TJb}Gq$UF~knPN!3>Z2&sGYRh?D)c6V7sZGIVPSK7 z&jGan;i&!FaFxk=1q((JxE3k2T2eHaLbaz&*Yvh;18me$+34M%)$ZcJPeaDN1MJ}I z*6-VOzAeeQMMwU(ksud|Pe(%d6+}gP<#=Ja3ZC{iB@ zfGaj`7EkV1tDVJ*l=qwmK&D%%nW|i}Z)K8LNkp&IIV$G_trwwdP|!1O89Z(YfPHW3 z!&B$Jv*;%QUw`Wyf_FOXvYkB7tOCq&^l~wdYZ40`wNXAVnN0EUp?GkfJJ!4f)5Y4y~R8q~TaM5vpCaHYsx{N)EJf)!vKG ze-iNd7nvDhI?hF~)TA2|VPs8#9xEoQOnT1=n1Lf*vT}9*UKHvM!3MZuMyhZu5r&Ce z)vI#)2X_GYSMEN~w;S{yR*#>b5!b7uV@Jx0RcbrQ^lyH!M{h^&?S5Xn%c|NiZL>&U zC>3jt+q2>!HQmbEt!A&`zwQgI?C?S&xR;)oqFPpBGipGKO`GT^?=1n~&1<4G4_A|= zcXG6+Fd8Y-2#;oawc)$&6}b|?DNFghx>oD818$n6u)pD<>9+d)2CkkH(p6(e=`t=; znV6=j5DM$p=;0lGxjk>BtdN_9glGCZfY1;^sIu;Y-qXB@80;CpDTP~$gP&!CDJ>Ui zj~}5JHf#*gP@KUNgBHv^&use20NnEKz(0(ec*mQVw0HOx7*m5H{)2$g3` zsD?|oNpba&?Oje?>sP4aXQc2Fz4Z)oOfn&ChAbkgDmImr!Y2MDTGoik{+>tpbl}Z> zUjgX2c=aN|%j|d7+Kk-WnTORbUiloz1hsS&LqiG+)l|$@6F_5j%C_JWCF5*W$stlN zLa$OG{MYEgW0wZ_&#P1A&LhV!x=Fy`Q*Pq3iQg+g5ZeAg7ZGW2VtZ-@Z0bC%p;L1q z!yAi6(Q4j^`LY<;@c@51@(OM^dvJU7+kOGCZ$DRwxb(O^L(h{j*4iqGVy;BlFZMi4 z*J)x4E+Q7NA_M}P?{dVIiv#R>)K$OvvrV2f(_}aSq)CmFf6L{)GE3NRrc5^gd!KOK z>H;gOQj$m?-1!37=E{oP7=S$v-`QMz;!neOb~^mBWH<9Y^R87b0G^~8%0`3&u*7$D zbGo&95?~{@;844OR3Z{arFk3OmnR~PrybV6e!hc}tG>?0`%Af!M8-Tmf+uF^VY6hr zlM^)}8E{ehX4Aj;lQ!2ciE&^vjXif`=XvqbPQC6kBBk)`)r@!Wn0db63Xx`nuhsKo zfLO$(O06u#m|j|F>I@LvmUc`_s^~ipI`aJ2oneXT001BWNklwU5}|ykA%hKlkE)yT5n!OuC>Fb+Da?B zd|D*Wm>5VI`Bp&jg+$(CwYOR?{#os<5Vmp&#gSj=xwAvv*t!+wktvtAfFl?Iy88OW z!>fBA1d3W!rHrbOVR$B}1vkzXWp=1Z5@22l7Ra9FzyM%OZl*#QSu$uw94M8yNdj5{ zjJ1R`2ldMVoVL}+Jn_l7ZFZkGy}1YHj$NG{Mj;pNFxy`9dcWQizJKD0rqYbH1trvy zf*Oeo>65BO+^;nrM*MHvbTF09u9HncQ8BSuggB6TQstT}gA_+3i39$~WRo&XQM_pp z7c&fs_!ZuL0Jk1Ej@>TYaFK~4YI-<&%%3mVs3eAmRJB5k1VAV%28q8}m6WOCEZ8!> zeX(kD%CC-D+Lj!`Ofhr{3iiyK2ajF$&Hm{ z|I%5>B5|Nh>>LbBg`v|OA9}%^ZE)CW9`G}j!`RS95T*lcvhR8GC2?YpS}yxJowN49 zD&?~4Y6KNi?}-${CT2Gob>?kJy^ze1E z#=artB0^g3oSt5dA)6=P(Z>D)+0!%vLt7inP_$s2&{>O2Az6CFXe<#C)sT{H>T&M} zN394jv2J{u$QoV#a$i24_7tb|{eZ^@p;x`K!_<}8`=bJltzDPEA0hD4mekH%Dyq~MX*OlT}6nkHYdZx+>JCQE#gNdi=rM}|9Z02}I7!0N_GU5rxG?DW$FbDKCv zCd4$TRQN6o?Nb2j?Qu?f)Z2cQT_evufc^gN$d6Sy|6>uJw2`L0rbvg_Q#DQIlWJdb z1t7jL(&vt+U-O>0ZfJP=75Dw7&sHjF3`!1(n8A^JqbG*OIZe&=0Q;RZf@99RgD0;) zHu%@*M=Au_#9H-42owCgYDLaBcg7g)i%yrX%wINZ3I%~OKA2c8Rd5IH0b(u%M5A3S{EtpFSDP|)B zUB}IvO5@A@BCcZo)jN~e^YTp=saRsqD>h;D0ppx0Rke4UwKM|N zB9tOYY?tpv=%_@0DTyTFuOJn{*JLtBSYFkfsLU3R>Y!-3#@s{stWsSkG_{qmxd z1nhRSgHrSxaz$s)H+zYZdR4p_bD2^cGq9hO7!*U>Y-nw_AhfSPdHu0Z1FXGrI~Sn+ zn)|xtJST&A&lN{DTdQ}Y>WdIk29a&a>`y8t5-Xw`BhwLCcf?)ecLW&o5EDM~ zkIWxRl|K@EN2jGhqa;9==_aKIPr&^BU3W9nCjJeA=m0L01w}1TQByQatbTQCj0Y7} zO=7%cT4(YVx22W}h)5#Y;qO0^VEB%hX<#4zdlyrvJ3vZ}s1ePSzN1zw22(kn{zr`k z2#4?VtG`DRO&YW1(1Q9EuViO(*83`s2Q_NFOQEqBqXxKcz?Uy#kIuEqyqXkMy(^5Z z3KDJ2vb{mF%?YA_slv$jt+~Fh_|^zpdwR@&g6=QR(R&&!J#B^vo5_nbgP{rmy8Ar& z+4^&a#sBi+<-Pw@d(80WN*l8ROj<@>Y_iloJ)3O+CN#l{Z?t_P(7D=a2rS-d&51_5 zhE%jDq5sN{rN4r))&{1o@LgYkcc#44>N2gDjNi;VxsU6fo%P&`fBnAU)5l7|oSur+ zPy;XZYl!Pfnju~ws@8hqTl#lo2<{nLhFC@OAPpka*pmIn=s_+K`2O=cStOExA!pyh z{Z||rZ8f^KwYrfJnWd_JBL187DI?ywXlxdv8Fi~1P&Duiz>bGq>fd*AK zQXw!nm(a43X_UK6udMJ&0RI^BC+c2^Olj0^q-wj1P(oEiB(PSyc%FIu&Wndk0r<;& z`XCsQ$z?Uh6oOI+t!;G@+~SzS!2~{)x$r*IX6qBp_1B?ecM!BsZD<)iwY!X@W7Ams<5+YCQf> zOgVj#Bxpn+k}Oj~@m-)dxivm_y|+V_ek~N;+*5$Nrpk!=kd*^8ba2M#9%4L4R-0V$ zYdz{#uHgicPGt>(D#L#w6&OQ}e_)%SGiOPg`t*fjwdy4m

    ~{D|}{2p(v{ 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 P;F^kphJ5)0i>LnwUcrUQ literal 0 HcmV?d00001 diff --git a/dispatcher.php b/dispatcher.php index 23234b0..90537e4 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -56,9 +56,14 @@ $ROUTES["^tournoi/(.*)/(modifier)/?$"] = ["server_files/controllers/tournoi.php" $ROUTES["^tournoi/(.*)/?$"] = ["server_files/controllers/tournoi.php", "name"]; $ROUTES["^tournois/?$"] = ["server_files/controllers/tournois.php"]; +$ROUTES["^Autorisation de droits à l'image.pdf$"] = ["server_files/controllers/autorisation_droit_image.php"]; +$ROUTES["^Autorisation parentale.pdf$"] = ["server_files/controllers/autorisation_parentale.php"]; +$ROUTES["^Instructions.pdf$"] = ["server_files/controllers/instructions.php"]; + # Assets files $ROUTES["^favicon\.ico$"] = ["assets/favicon.ico", "image/x-icon"]; +$ROUTES["^Fiche sanitaire\.pdf$"] = ["assets/Fiche_sanitaire.pdf", "application/pdf"]; $ROUTES["^logo\.svg$"] = ["assets/logo.svg", "image/svg+xml"]; $ROUTES["^style\.css$"] = ["assets/style.css", "text/css"]; diff --git a/server_files/controllers/autorisation_droit_image.php b/server_files/controllers/autorisation_droit_image.php new file mode 100644 index 0000000..18f23a1 --- /dev/null +++ b/server_files/controllers/autorisation_droit_image.php @@ -0,0 +1,52 @@ +getEffectiveTournament(); + + $majeur = $user->getBirthDate() > strval($YEAR - 18) . substr($tournament->getStartDate(), 4); + + $tex = file_get_contents("assets/Autorisation_droit_image_" . ($majeur ? "majeur" : "mineur") . ".tex"); + + $tex = preg_replace("#{PARTICIPANT_NAME}#", "\\texttt{" . $user->getFirstName() . " " . $user->getSurname() . "}", $tex); + $tex = preg_replace("#{BIRTHDAY}#", "\\texttt{" . strftime("%d %B %G", strtotime($user->getBirthDate())) . "}", $tex); + $tex = preg_replace("#{ADDRESS}#", "\\texttt{" . $user->getAddress() . ", " . $user->getPostalCode() . ", " . $user->getCity() + . ($user->getCountry() == "France" ? "" : $user->getCountry()) . "}.", $tex); +} + +$tex = preg_replace("#{TOURNAMENT_NAME}#", $tournament->getName(), $tex); +$tex = preg_replace("#{PLACE}#", $tournament->getPlace(), $tex); +$tex = preg_replace("#{START_DATE}#", strftime("%d %B", strtotime($tournament->getStartDate())), $tex); +$tex = preg_replace("#{END_DATE}#", strftime("%d %B", strtotime($tournament->getEndDate())), $tex); +$tex = preg_replace("#{YEAR}#", $YEAR, $tex); + +shell_exec("mkdir tmp"); + +file_put_contents("tmp/file.tex", $tex); + +shell_exec("pdflatex -synctex=1 -interaction=nonstopmode -shell-escape -output-directory=tmp tmp/file.tex"); +header("Content-type: application/pdf"); +readfile("tmp/file.pdf"); + +exit(0); \ No newline at end of file diff --git a/server_files/controllers/autorisation_parentale.php b/server_files/controllers/autorisation_parentale.php new file mode 100644 index 0000000..40cdc29 --- /dev/null +++ b/server_files/controllers/autorisation_parentale.php @@ -0,0 +1,44 @@ +getEffectiveTournament(); + $tex = preg_replace("#{PARTICIPANT_NAME}#", "\\texttt{" . $user->getFirstName() . " " . $user->getSurname() . "}", $tex); + $tex = preg_replace("#{BIRTHDAY}#", "\\texttt{" . strftime("%d %B %G", strtotime($user->getBirthDate())) . "}", $tex); + $tex = preg_replace("#{PRONOUN}#", $user->getGender() == "M" ? "Il" : "Elle", $tex); +} + +$tex = preg_replace("#{TOURNAMENT_NAME}#", $tournament->getName(), $tex); +$tex = preg_replace("#{PLACE}#", $tournament->getPlace(), $tex); +$tex = preg_replace("#{START_DATE}#", strftime("%d %B", strtotime($tournament->getStartDate())), $tex); +$tex = preg_replace("#{END_DATE}#", strftime("%d %B", strtotime($tournament->getEndDate())), $tex); +$tex = preg_replace("#{YEAR}#", $YEAR, $tex); + +shell_exec("mkdir tmp"); + +file_put_contents("tmp/file.tex", $tex); + +shell_exec("pdflatex -synctex=1 -interaction=nonstopmode -shell-escape -output-directory=tmp tmp/file.tex"); +header("Content-type: application/pdf"); +readfile("tmp/file.pdf"); + +exit(0); \ No newline at end of file diff --git a/server_files/controllers/instructions.php b/server_files/controllers/instructions.php new file mode 100644 index 0000000..20b58b4 --- /dev/null +++ b/server_files/controllers/instructions.php @@ -0,0 +1,36 @@ +getEffectiveTournament(); +} + +$tex = preg_replace("#{TOURNAMENT_NAME}#", $tournament->getName(), $tex); +$tex = preg_replace("#{PLACE}#", $tournament->getPlace(), $tex); +$tex = preg_replace("#{PRICE}#", $tournament->getPrice(), $tex); +$tex = preg_replace("#{END_PAYMENT_DATE}#", strftime("%d %B", strtotime($tournament->getInscriptionDate())), $tex); +$tex = preg_replace("#{YEAR}#", $YEAR, $tex); + +shell_exec("mkdir tmp"); +file_put_contents("tmp/file.tex", $tex); +shell_exec("pdflatex -synctex=1 -interaction=nonstopmode -shell-escape -output-directory=tmp tmp/file.tex"); +header("Content-type: application/pdf"); +readfile("tmp/file.pdf"); +shell_exec("rm -rf tmp"); + +exit(0); \ No newline at end of file diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index a574578..26390c6 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -206,12 +206,19 @@ if (!$has_error && (isset($my_account) || isset($new_password))) {

    Mes autorisations

    - Ces documents peut être modifiés tant que l'équipe n'est pas validée. +
    + Ces documents peut être modifiés tant que l'équipe n'est pas validée. Les fichiers doivent peser au maximum 2 Mo et doivent + être au format PDF. +
    - Modèle d'autorisation de droit à l'image : - majeur - mineur + Modèle de fiche sanitaire : Télécharger
    + getBirthDate() > strval($YEAR - 18) . substr($tournament->getStartDate(), 4)) { ?> + Modèle d'autorisation parentale : Télécharger + - Modèle vierge
    + + Modèle d'autorisation de droit à l'image : Télécharger + - Modèle vierge
    diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index d4fde02..13dda3a 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -4,6 +4,10 @@

    Tournoi de getName() ?>

    +
    + Instructions : Télécharger +
    +
    Organisateur= 2 ? 's' : '' ?> : Date: Sat, 18 Jan 2020 17:28:31 +0100 Subject: [PATCH 092/120] =?UTF-8?q?Les=20=C3=A9quipes=20non=20valid=C3=A9e?= =?UTF-8?q?s=20ne=20peuvent=20pas=20proc=C3=A9der=20au=20paiement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/paiement.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server_files/controllers/paiement.php b/server_files/controllers/paiement.php index e0804f3..6075092 100644 --- a/server_files/controllers/paiement.php +++ b/server_files/controllers/paiement.php @@ -13,6 +13,9 @@ $team = $_SESSION["team"]; $tournament = $team->getEffectiveTournament(); $payment = $user->getPayment(); +if ($team->getValidationStatus() != ValidationStatus::VALIDATED) + require_once "server_files/403.php"; + if (isset($_POST["pay"])) { $pay = new Pay($_POST); try { From a36a4cc7289036ba1457860558c1f609036dbbbd Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 18 Jan 2020 17:37:24 +0100 Subject: [PATCH 093/120] Le premier inscrit est administrateur --- server_files/controllers/inscription.php | 3 +++ server_files/views/header.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 538834d..9c6324d 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -73,6 +73,9 @@ class NewUser } } + if (sizeof(User::getAllUsers()) == 0) + $this->role = Role::ADMIN; + $this->confirm_email_token = genRandomPhrase(64); } diff --git a/server_files/views/header.php b/server_files/views/header.php index 241137a..25fbecf 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -117,7 +117,7 @@

    Cette plateforme ouvrira le 22 janvier 2020 ! :)

    "; require_once "footer.php"; } \ No newline at end of file From eee1e9d68a8dc018df9277216bf0fd666518a9e5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 18 Jan 2020 17:39:21 +0100 Subject: [PATCH 094/120] Correction dans l'ajout d'organisateurs --- server_files/controllers/ajouter_organisateur.php | 2 +- server_files/views/ajouter_organisateur.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index dbb81b7..fd3add3 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -6,7 +6,7 @@ if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) $has_error = false; $error_message = null; -if (isset($_POST["submitted"])) { +if (isset($_POST["add_orga"])) { $orga = new NewOrganizer($_POST); try { $orga->makeVerifications(); diff --git a/server_files/views/ajouter_organisateur.php b/server_files/views/ajouter_organisateur.php index 53b1c86..9db8a91 100644 --- a/server_files/views/ajouter_organisateur.php +++ b/server_files/views/ajouter_organisateur.php @@ -44,7 +44,7 @@ require_once "header.php";
    - +
    From 7096f6fee19ceb62e271a45d47fadf03488e7695 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 18 Jan 2020 17:45:49 +0100 Subject: [PATCH 095/120] Correction dans l'ajout d'organisateurs --- server_files/controllers/ajouter_organisateur.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index fd3add3..12e36c8 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -38,7 +38,7 @@ class NewOrganizer { ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail est invalide."); $this->email = strtolower($this->email); ensure(!userExists($this->email), "Cette adresse e-mail est déjà utilisée."); - $this->admin = $this->admin == "on" ? true : false; + $this->admin = isset($this->admin) ? 1 : 0; } public function register() { From cd70de049a52fbe0796d0da92cd57f932e0eb66b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 18 Jan 2020 23:57:49 +0100 Subject: [PATCH 096/120] Modifications mail nouvau organisateur --- server_files/controllers/ajouter_organisateur.php | 8 +++++--- server_files/model.php | 15 +++++---------- server_files/services/mail.php | 2 +- .../services/mail_templates/add_organizer.html | 10 +++++----- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/server_files/controllers/ajouter_organisateur.php b/server_files/controllers/ajouter_organisateur.php index 12e36c8..d196a88 100644 --- a/server_files/controllers/ajouter_organisateur.php +++ b/server_files/controllers/ajouter_organisateur.php @@ -24,6 +24,7 @@ class NewOrganizer { public $email; public $admin; public $password; + public $token; public function __construct($data) { @@ -45,10 +46,11 @@ class NewOrganizer { global $DB, $YEAR; $this->password = genRandomPhrase(16, true); + $this->token = genRandomPhrase(64); - $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `year`) - VALUES (?, ?, ?, ?, ?, ?);"); - $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->surname, $this->first_name, $this->admin ? "ADMIN" : "ORGANIZER", $YEAR]); + $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `surname`, `first_name`, `role`, `forgotten_password`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?);"); + $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->surname, $this->first_name, $this->admin ? "ADMIN" : "ORGANIZER", $this->token, $YEAR]); Mailer::sendAddOrganizerMail($this); } diff --git a/server_files/model.php b/server_files/model.php index 8e94f4f..760b806 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -130,11 +130,6 @@ function canValidate(Team $team, Tournament $tournament) $req->execute([$team->getEncadrants()[$i - 1], $tournament->getId(), "PHOTO_CONSENT"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; - - $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? AND `type` = ?;"); - $req->execute([$team->getEncadrants()[$i - 1], $tournament->getId(), "SANITARY_PLUG"]); - $d = $req->fetch(); - $can_validate &= $d["version"] > 0; } for ($i = 1; $i <= 6; ++$i) { @@ -146,17 +141,17 @@ function canValidate(Team $team, Tournament $tournament) $d = $req->fetch(); $can_validate &= $d["version"] > 0; - $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? AND `type` = ?;"); - $req->execute([$team->getParticipants()[$i], $tournament->getId(), "SANITARY_PLUG"]); - $d = $req->fetch(); - $can_validate &= $d["version"] > 0; - $birth_date = $DB->query("SELECT `birth_date` FROM `users` WHERE `id` = " . $team->getParticipants()[$i] . ";")->fetch()["birth_date"]; if ($birth_date > strval($YEAR - 18) . substr($tournament->getStartDate(), 4)) { $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? AND `type` = ?;"); $req->execute([$team->getParticipants()[$i], $tournament->getId(), "PARENTAL_CONSENT"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; + + $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `user` = ? AND `tournament` = ? AND `type` = ?;"); + $req->execute([$team->getParticipants()[$i], $tournament->getId(), "SANITARY_PLUG"]); + $d = $req->fetch(); + $can_validate &= $d["version"] > 0; } } diff --git a/server_files/services/mail.php b/server_files/services/mail.php index da1f0ad..6180e58 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -161,7 +161,7 @@ class Mailer $content = self::getTemplate("add_organizer"); $content = preg_replace("#{FIRST_NAME}#", $new_orga->first_name, $content); $content = preg_replace("#{SURNAME}#", $new_orga->surname, $content); - $content = preg_replace("#{PASSWORD}#", $new_orga->password, $content); + $content = preg_replace("#{TOKEN}#", $new_orga->token, $content); self::sendMail($new_orga->email, "Ajout d'un organisateur – TFJM² $YEAR", $content); } diff --git a/server_files/services/mail_templates/add_organizer.html b/server_files/services/mail_templates/add_organizer.html index d0331e1..56ed2c5 100644 --- a/server_files/services/mail_templates/add_organizer.html +++ b/server_files/services/mail_templates/add_organizer.html @@ -7,12 +7,12 @@ Bonjour {FIRST_NAME} {SURNAME},

    -Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM2. -Veuillez trouver ci-dessous vos informations d'utilisateur pour le site officiel des inscriptions. Elles vous permettront de gérer les inscriptions des équipes de votre tournoi.
    +Vous recevez ce message (envoyé automatiquement) car vous êtes organisateur d'un des tournois du TFJM2.

    +Un compte organisateur vous a été créé par l'un des administrateurs. Un mot de passe aléatoire vous a été attribué, mais que vous +devez changer pour des raisons de sécurité sur le lien suivant : +{URL_BASE}/connexion/reinitialiser_mdp/{TOKEN}

    -Votre mot de passe est : {PASSWORD}
    -
    -Notez bien que ce mot de passe est temporaire, et pour des raisons de sécurité vous devrez le changer lors de votre prochaine connexion sur le site.
    +Une fois le mot de passe changé, vous pourrez vous connecter sur la plateforme.

    Merci beaucoup pour votre aide !

    From 6fe398d965ad43923796a7e95f3f83dd21d23b5e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 21 Jan 2020 12:43:13 +0100 Subject: [PATCH 097/120] Modifications mineures --- server_files/classes/User.php | 2 +- server_files/controllers/ajouter_tournoi.php | 2 -- server_files/controllers/informations.php | 9 +++++--- server_files/controllers/organisateurs.php | 2 +- server_files/controllers/tournoi.php | 2 +- server_files/views/ajouter_tournoi.php | 24 ++++++++++---------- server_files/views/header.php | 6 +++-- server_files/views/informations.php | 24 ++++++++++++-------- server_files/views/tournoi.php | 6 ++--- server_files/views/tournois.php | 2 +- 10 files changed, 43 insertions(+), 36 deletions(-) diff --git a/server_files/classes/User.php b/server_files/classes/User.php index 161195b..381e71c 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -90,7 +90,7 @@ class User { global $DB, $YEAR; $admins = []; - $req = $DB->query("SELECT * FROM `users` WHERE `role` = 'ORGANIZER' OR `role` = 'ADMIN' AND `year` = $YEAR;"); + $req = $DB->query("SELECT * FROM `users` WHERE `role` = 'ORGANIZER' OR `role` = 'ADMIN' AND `year` = $YEAR ORDER BY `role`, `surname`, `first_name`;"); while (($data = $req->fetch()) !== false) { $admin = new User(); diff --git a/server_files/controllers/ajouter_tournoi.php b/server_files/controllers/ajouter_tournoi.php index 8778156..4efc6f2 100644 --- a/server_files/controllers/ajouter_tournoi.php +++ b/server_files/controllers/ajouter_tournoi.php @@ -3,8 +3,6 @@ if (!isset($_SESSION["role"]) || $_SESSION["role"] != Role::ADMIN) require_once "server_files/403.php"; -$orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); - $has_error = false; $error_message = null; diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index e41ef18..c00e109 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -5,17 +5,20 @@ if (!isset($_SESSION["role"])) $id = $_GET["id"]; $user = User::fromId($id); +$team = Team::fromId($user->getTeamId()); if ($_SESSION["role"] != Role::ADMIN) { - if ($user->getId() != $_SESSION["user_id"]) + if ($_SESSION["role"] == Role::ORGANIZER) { + if (($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::PARTICIPANT) && ($team == null || $team->getTournamentId() == null || !Tournament::fromId($team->getTournamentId())->organize($_SESSION["user_id"]))) + require_once "server_files/403.php"; + } + elseif ($user->getId() != $_SESSION["user_id"]) require_once "server_files/403.php"; } if ($user === null) require_once "server_files/404.php"; -$team = Team::fromId($user->getTeamId()); - if ($team != null) { $documents = $user->getAllDocuments($team->getTournamentId()); $payment = $user->getPayment(); diff --git a/server_files/controllers/organisateurs.php b/server_files/controllers/organisateurs.php index 446dccc..bfe340e 100644 --- a/server_files/controllers/organisateurs.php +++ b/server_files/controllers/organisateurs.php @@ -1,6 +1,6 @@ getOrganizers(); $teams = $tournament->getAllTeams(); -$orgas_response = $DB->query("SELECT `id`, `surname`, `first_name` FROM `users` WHERE (`role` = 'ORGANIZER' OR `role` = 'ADMIN') AND `year` = '$YEAR';"); class UpdateTournament { @@ -106,6 +105,7 @@ class UpdateTournament $tournament->setInscriptionDate("$this->date_inscription $this->time_inscription"); $tournament->setSolutionsDate("$this->date_solutions $this->time_solutions"); $tournament->setSynthesesDate("$this->date_syntheses $this->time_syntheses"); + $tournament->setDescription($this->description); foreach ($this->organizers as $organizer) { if (!$tournament->organize($organizer->getId())) diff --git a/server_files/views/ajouter_tournoi.php b/server_files/views/ajouter_tournoi.php index 538fba7..bf5ae09 100644 --- a/server_files/views/ajouter_tournoi.php +++ b/server_files/views/ajouter_tournoi.php @@ -18,7 +18,7 @@ if (isset($tournament) && !$has_error) { ?>
    -
    @@ -34,8 +34,8 @@ if (isset($tournament) && !$has_error) { ?> @@ -60,12 +60,12 @@ if (isset($tournament) && !$has_error) { ?>
    + value="date_start : date('Y-m-d') ?>"/>
    + value="date_end : date('Y-m-d') ?>"/>
    @@ -73,30 +73,30 @@ if (isset($tournament) && !$has_error) { ?>
    + value="date_inscription : date('Y-m-d') ?>"/> + value="time_inscription : date('H:i') ?>"/>
    + value="date_solutions : date('Y-m-d') ?>"/> + value="time_solutions: date('H:i') ?>"/>
    + value="date_syntheses : date('Y-m-d') ?>"/> + value="time_syntheses : date('H:i') ?>"/>
    - +
    diff --git a/server_files/views/header.php b/server_files/views/header.php index 25fbecf..288f3c1 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -30,8 +30,10 @@ Liste des tournois diff --git a/server_files/views/informations.php b/server_files/views/informations.php index 6abb583..7701f7b 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -66,17 +66,21 @@ if (!$has_error) {
    -
    - Date de naissance : getBirthDate()) ?>
    -
    +getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) { +?> +
    + Date de naissance : getBirthDate()) ?>
    +
    -
    - Sexe : getGender() == "M" ? "Masculin" : "Féminin" ?>
    -
    +
    + Sexe : getGender() == "M" ? "Masculin" : "Féminin" ?>
    +
    -
    - Adresse : getAddress() . ", " . $user->getPostalCode() . " " . $user->getCity() . ($user->getCountry() == "France" ? "" : ", " . $user->getCountry()) ?>
    -
    +
    + Adresse : getAddress() . ", " . $user->getPostalCode() . " " . $user->getCity() . ($user->getCountry() == "France" ? "" : ", " . $user->getCountry()) ?>
    +
    +
    Adresse e-mail : getEmail() ?>
    @@ -156,7 +160,7 @@ if (!$has_error) { getRole() == Role::ADMIN || $user->getRole() == Role::ORGANIZER) { - foreach ($tournaments as $tournament) { + foreach ($user->getOrganizedTournaments() as $tournament) { echo ""; } } diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 13dda3a..1d33a89 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -135,9 +135,9 @@ else { diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index 8e7a7b6..2c0ae8d 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -23,8 +23,8 @@ getName() ?> Du getStartDate()) ?> au getEndDate()) ?> + getInscriptionDate()) ?> getSolutionsDate()) ?> - getSynthesesDate()) ?> getSize() ?> Date: Tue, 21 Jan 2020 19:22:22 +0100 Subject: [PATCH 098/120] =?UTF-8?q?Possibilit=C3=A9=20de=20supprimer=20un?= =?UTF-8?q?=20compte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/informations.php | 3 ++- server_files/views/informations.php | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index c00e109..012a5e8 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -74,7 +74,8 @@ if (isset($_POST["delete_account"]) && $team == null && $_SESSION["role"] == Rol foreach ($user->getAllDocuments($team->getTournamentId()) as $document) unlink($LOCAL_PATH . "/files/" . $document->getFileId()); $DB->prepare("DELETE FROM `documents` WHERE `user` = ?;")->execute([$user->getId()]); - $DB->prepare("DELETE FROM `users` WHERE `id` = ?;")->execute([$user->getId()]); + $DB->prepare("DELETE FROM `organizers` WHERE `organizer` = ?;")->execute([$user->getId()]); + $DB->prepare("DELETE FROM `users` WHERE `id` = ?;")->execute([$user->getId()]); header("Location: /"); exit(); } diff --git a/server_files/views/informations.php b/server_files/views/informations.php index 7701f7b..800db2a 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -178,7 +178,15 @@ elseif (($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCA } } -if ($_SESSION["role"] == Role::ADMIN) { ?> +if ($_SESSION["role"] == Role::ADMIN) { + if ($user->getRole() != Role::ADMIN && $team == null) { ?> +
    + +
    + +
    +
    Date: Tue, 21 Jan 2020 23:23:14 +0100 Subject: [PATCH 099/120] =?UTF-8?q?Possibilit=C3=A9=20de=20modifier=20la?= =?UTF-8?q?=20page=20d'accueil?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dispatcher.php | 1 + server_files/controllers/index.php | 17 ++++ server_files/views/index.html | 112 ++++++++++++++++++++++++ server_files/views/index.php | 134 +++++------------------------ 4 files changed, 153 insertions(+), 111 deletions(-) create mode 100644 server_files/views/index.html diff --git a/dispatcher.php b/dispatcher.php index 90537e4..a0c49f3 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -40,6 +40,7 @@ $ROUTES["^equipe/([A-Z]{3})/?$"] = ["server_files/controllers/equipe.php", "trig $ROUTES["^file/([a-z0-9]{64})/?$"] = ["server_files/controllers/view_file.php", "file_id"]; $ROUTES["^informations/([0-9]*)/.*?$"] = ["server_files/controllers/informations.php", "id"]; $ROUTES["^inscription/?$"] = ["server_files/controllers/inscription.php"]; +$ROUTES["^(modifier-page)$"] = ["server_files/controllers/index.php", "edit"]; $ROUTES["^mon-compte/?$"] = ["server_files/controllers/mon_compte.php"]; $ROUTES["^mon-equipe/(modifier)/?$"] = ["server_files/controllers/mon_equipe.php", "modifier"]; $ROUTES["^mon-equipe/?$"] = ["server_files/controllers/mon_equipe.php"]; diff --git a/server_files/controllers/index.php b/server_files/controllers/index.php index a884dca..5a23b80 100644 --- a/server_files/controllers/index.php +++ b/server_files/controllers/index.php @@ -1,3 +1,20 @@ + +
    +
    +

    + Bienvenue sur le site d'inscription au 𝕋𝔽𝕁𝕄2 ! +

    +

    + Le Tournoi Français des Jeunes Mathématiciens et Mathématiciennes +

    +
    +
    +
    +
    +

    + Tu souhaites participer au tournoi ? +
    + Ton équipe est déjà formée ? +

    +
    + +
    + +
    +
    Attentions aux échéances
    +

    + Chaque tournoi a une date limite pour les inscriptions et une date limite pour + déposer vos solutions. En savoir plus +

    +
    + +
    +
    Modification du règlement
    +

    + Depuis l'année dernière, l'équipe doit envoyer par mail à contact@tfjm.org les informations suivantes: +

      +
    • Comment l’équipe s’est-elle formée ?
    • +
    • + Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres + avec l’encadrant•e) ? +
    • +
    + + Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires + à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés + dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non + l’inscription des équipes concernées par cette lettre. +

    +
    + +
    + +
    +
    Comment ça marche ?
    +

    + Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique + Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé + à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer + par la suite. +

    +

    + Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : +

    +
      +
    • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
    • +
    • + enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière + version enregistrée avant la date limite sera prise en compte pour le tournoi). +
    • +
    +

    + Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, + votre inscription pourra être validée par les organisateurs locaux. +

    + +
    + Attention! Votre équipe ne sera considérée comme admissible à participer au tournoi que + lorsque cette première étape aura été franchie. +
    + +
    + Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible + pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque + tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes + seront placées en liste d'attente. +
    +

    + Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer + deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers + le site pour compléter votre inscription. +

    +
    + Attention Les équipes qui ne respecteront pas les délais pour rendre ces documents + risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente. +
    +
    + + +
    + Ce site est récent et il est encore possible que certaines pages ne fonctionnent + pas correctement. +
    + Si vous remarquez des bugs, merci de les signaler à l'adresse + contact@tfjm.org. +
    + +
    \ No newline at end of file diff --git a/server_files/views/index.php b/server_files/views/index.php index 01bf7ed..7c8e0b0 100644 --- a/server_files/views/index.php +++ b/server_files/views/index.php @@ -1,116 +1,28 @@ - + +$html = file_get_contents("index"); -
    -
    -

    - Bienvenue sur le site d'inscription au 𝕋𝔽𝕁𝕄2 ! -

    -

    - Le Tournoi Français des Jeunes Mathématiciens et Mathématiciennes -

    -
    -
    -
    -
    -

    - Tu souhaites participer au tournoi ? -
    - Ton équipe est déjà formée ? -

    -
    - +if (isset($_GET["edit"])) { ?> + + + + +
    + +
    +
    + + -
    Attentions aux échéances
    -

    - Chaque tournoi a une date limite pour les inscriptions et une date limite pour - déposer vos solutions. En savoir plus -

    -
    + if (isset($_SESSION["user_id"]) && $_SESSION["role"] == Role::ADMIN) { ?> +
    + + Modifier la page + + -
    Modification du règlement
    -

    - Depuis l'année dernière, l'équipe doit envoyer par mail à contact@tfjm.org les informations suivantes: -

      -
    • Comment l’équipe s’est-elle formée ?
    • -
    • - Comment l’équipe va-t-elle travailler (où peut-elle se rencontrer, à quelle fréquence, rencontres - avec l’encadrant•e) ? -
    • -
    - - Cette lettre permettra aux organisateurs•trices de vérifier que l’équipe dispose des conditions nécessaires - à une participation sérieuse. Sont dispensées les équipes dont la moitié ou plus des membres sont scolarisés - dans le même établissement. Le comité National d’Organisation se réserve le droit d’accepter ou non - l’inscription des équipes concernées par cette lettre. -

    - - -
    - -
    -
    Comment ça marche ?
    -

    - Pour participer à l'un des tournois régionaux, il suffit de créer un compte sur la rubrique - Inscription. Il vous faudra une adresse email pour ce faire. Un mail de confirmation sera envoyé - à cette adresse. Il vous fournira un nom d'utilisateur et un mot de passe que vous allez devoir changer - par la suite. -

    -

    - Vous pouvez accéder à votre compte via la rubrique Connexion. Une fois connecté, vous pourrez : -

    -
      -
    • rentrer des informations sur les membres de votre équipe, tant participants qu'encadrants ;
    • -
    • - enregistrer et télécharger des versions préliminaires de vos solutions (seulement la dernière - version enregistrée avant la date limite sera prise en compte pour le tournoi). -
    • -
    -

    - Une fois que vous aurez fourni toutes les informations demandées dans la rubrique Mon Équipe, - votre inscription pourra être validée par les organisateurs locaux. -

    - -
    - Attention! Votre équipe ne sera considérée comme admissible à participer au tournoi que - lorsque cette première étape aura été franchie. -
    - -
    - Pensez donc à former une équipe complète (minimum 4 participants et 1 encadrant) le plus tôt possible - pour avoir plus de chances de participer, compte tenu du nombre des places disponibles dans chaque - tournoi (qui sera dûment affiché sur la rubrique Liste des Tournois). Les équipes restantes - seront placées en liste d'attente. -
    -

    - Pour les équipes dont l'inscription aura été validée, des documents à télécharger, remplir et signer - deviendront disponibles sur votre compte. Vous allez devoir ensuite les scanner et les télécharger vers - le site pour compléter votre inscription. -

    -
    - Attention Les équipes qui ne respecteront pas les délais pour rendre ces documents - risquent d'être disqualifiées et de laisser leur place aux équipes placées en liste d'attente. -
    -
    - - -
    - Ce site est récent et il est encore possible que certaines pages ne fonctionnent - pas correctement. -
    - Si vous remarquez des bugs, merci de les signaler à l'adresse - contact@tfjm.org. -
    - - - - \ No newline at end of file +require_once "footer.php"; \ No newline at end of file From 939536a567b87d12e82c612eac7d74aa0c55b83b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 21 Jan 2020 23:26:19 +0100 Subject: [PATCH 100/120] Clarification sur l'automatisation d'un message --- .../services/mail_templates/add_organizer_for_tournament.html | 1 + 1 file changed, 1 insertion(+) diff --git a/server_files/services/mail_templates/add_organizer_for_tournament.html b/server_files/services/mail_templates/add_organizer_for_tournament.html index a61ace2..ee83644 100644 --- a/server_files/services/mail_templates/add_organizer_for_tournament.html +++ b/server_files/services/mail_templates/add_organizer_for_tournament.html @@ -9,6 +9,7 @@ Bonjour {FIRST_NAME} {SURNAME},

    Vous venez d'être promu organisateur du tournoi {TOURNAMENT_NAME} du TFJM2 {YEAR}.
    +Ce message vous a été envoyé automatiquement. En cas de problème, merci de répondre à ce message.
    Cordialement,

    From f8f3e7b41a69e15a85121909a4eec13b2b1990da Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Wed, 22 Jan 2020 13:04:49 +0100 Subject: [PATCH 101/120] Ouverture de la plateforme --- server_files/views/header.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/server_files/views/header.php b/server_files/views/header.php index 288f3c1..d383486 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -117,9 +117,4 @@
    Erreur :
    -

    Cette plateforme ouvrira le 22 janvier 2020 ! :)

    "; - require_once "footer.php"; - } \ No newline at end of file + Date: Wed, 22 Jan 2020 13:43:27 +0100 Subject: [PATCH 102/120] Affichage de liens d'information pour les tournois --- dispatcher.php | 2 +- server_files/controllers/autorisation_droit_image.php | 2 +- server_files/views/tournoi.php | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dispatcher.php b/dispatcher.php index a0c49f3..00de4bc 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -57,7 +57,7 @@ $ROUTES["^tournoi/(.*)/(modifier)/?$"] = ["server_files/controllers/tournoi.php" $ROUTES["^tournoi/(.*)/?$"] = ["server_files/controllers/tournoi.php", "name"]; $ROUTES["^tournois/?$"] = ["server_files/controllers/tournois.php"]; -$ROUTES["^Autorisation de droits à l'image.pdf$"] = ["server_files/controllers/autorisation_droit_image.php"]; +$ROUTES["^Autorisation de droit à l'image.pdf$"] = ["server_files/controllers/autorisation_droit_image.php"]; $ROUTES["^Autorisation parentale.pdf$"] = ["server_files/controllers/autorisation_parentale.php"]; $ROUTES["^Instructions.pdf$"] = ["server_files/controllers/instructions.php"]; diff --git a/server_files/controllers/autorisation_droit_image.php b/server_files/controllers/autorisation_droit_image.php index 18f23a1..41b20c5 100644 --- a/server_files/controllers/autorisation_droit_image.php +++ b/server_files/controllers/autorisation_droit_image.php @@ -11,7 +11,7 @@ $team = $_SESSION["team"]; if (!isset($user) || isset($_GET["blank"]) || $_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) { $tournament = Tournament::fromName($_GET["blank"]); - $majeur = isset($_SESSION["mineur"]) ? 0 : 1; + $majeur = isset($_GET["mineur"]) ? 0 : 1; $tex = file_get_contents("assets/Autorisation_droit_image_" . ($majeur ? "majeur" : "mineur") . ".tex"); diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 1d33a89..3995ee4 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -5,7 +5,11 @@
    - Instructions : Télécharger + Instructions : Télécharger
    + Autorisation de droit à l'image - majeur : Télécharger
    + Autorisation de droit à l'image - mineur : Télécharger
    + Autorisation parentale : Télécharger
    + Fiche sanitaire : Télécharger
    From cd584f8bb6222c045c42f79ca53ca7900032d808 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Wed, 22 Jan 2020 21:11:54 +0100 Subject: [PATCH 103/120] Correction d'un bug majeur concernant l'inscription des participants --- server_files/controllers/inscription.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 9c6324d..62917e3 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -73,7 +73,7 @@ class NewUser } } - if (sizeof(User::getAllUsers()) == 0) + if (count(User::getAllUsers()) == 0) $this->role = Role::ADMIN; $this->confirm_email_token = genRandomPhrase(64); From c64ef0646e4a5c3e278fc5dd016b0c23a5d18d1c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Wed, 22 Jan 2020 22:06:53 +0100 Subject: [PATCH 104/120] Correction de certains mots --- server_files/views/equipe.php | 4 ++-- server_files/views/informations.php | 6 +++--- server_files/views/mon_compte.php | 2 +- server_files/views/mon_equipe.php | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index 9ffda21..62fa1bf 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -61,7 +61,7 @@
    -

    Autorisations

    +

    Documents

    @@ -71,7 +71,7 @@ isSelectedForFinal()) { ?>
    -

    Autorisations pour la finale

    +

    Documents pour la finale

    diff --git a/server_files/views/informations.php b/server_files/views/informations.php index 800db2a..3cd165a 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -60,7 +60,7 @@ if (!$has_error) { getValidationStatus() == ValidationStatus::NOT_READY) { ?> - Virer de l'équipe + Exclure de l'équipe
    @@ -166,13 +166,13 @@ if ($user->getRole() == Role::ADMIN || $user->getRole() == Role::ORGANIZER) { } elseif (($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT) && $user->getTeamId() !== NULL) { ?> -

    Autorisations

    +

    Documents

    isSelectedForFinal()) { ?>
    -

    Autorisations pour la finale

    +

    Documents pour la finale


    -

    Mes autorisations

    +

    Mes documents

    diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index 95f2b65..34e20cf 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -127,13 +127,13 @@ require_once "header.php";
    -

    Autorisations de l'équipe

    +

    Documents de l'équipe

    isSelectedForFinal()) { ?>
    -

    Autorisations de l'équipe pour la finale

    +

    Documents de l'équipe pour la finale

    From 2ee1c75d0c077cfe1b461e4648bbdf8ef4bfe94b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Wed, 22 Jan 2020 22:18:55 +0100 Subject: [PATCH 105/120] =?UTF-8?q?S=C3=A9curit=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/informations.php | 4 ++-- server_files/controllers/paiement.php | 2 +- server_files/views/inscription.php | 12 +++++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index 012a5e8..6923d19 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -88,7 +88,7 @@ class AttributeTeam public function __construct($data) { - $this->team_id = $data["team"]; + $this->team_id = htmlspecialchars($data["team"]); $this->team = Team::fromId($this->team_id); } @@ -148,7 +148,7 @@ class ValidatePayment global $user; foreach ($data as $key => $value) - $this->$key = $value; + $this->$key = htmlspecialchars($value); $this->payment = $user->getPayment(); } diff --git a/server_files/controllers/paiement.php b/server_files/controllers/paiement.php index 6075092..6e042f6 100644 --- a/server_files/controllers/paiement.php +++ b/server_files/controllers/paiement.php @@ -36,7 +36,7 @@ class Pay { public function __construct($data) { foreach ($data as $key => $value) - $this->$key = $value; + $this->$key = htmlspecialchars($value); $this->method = PaymentMethod::fromName(strtoupper($this->method)); diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index cad1b12..6ebf717 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -22,11 +22,13 @@ if (isset($user) && !$has_error) {
    - - +
    + + +
    From 61d5af0651a20c32a0e0f1ab0e3140bcc6f14acf Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 24 Jan 2020 11:13:11 +0100 Subject: [PATCH 106/120] =?UTF-8?q?Correction=20de=20bugs=20concernant=20l?= =?UTF-8?q?es=20classes=20et=20=C3=A9coles?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/classes/User.php | 2 +- server_files/controllers/inscription.php | 3 +++ server_files/controllers/mon_compte.php | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server_files/classes/User.php b/server_files/classes/User.php index 381e71c..b069b97 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -300,7 +300,7 @@ class User { global $DB; $this->school = $school; - $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([SchoolClass::getName($school), $this->getId()]); + $DB->prepare("UPDATE `users` SET `school` = ? WHERE `id` = ?;")->execute([$school, $this->getId()]); } public function getClass() diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 62917e3..99adfe4 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -72,6 +72,9 @@ class NewUser ensure(filter_var($this->responsible_email, FILTER_VALIDATE_EMAIL), "Veuillez spécifier un responsable légal."); } } + else { + $this->class = SchoolClass::ADULT; + } if (count(User::getAllUsers()) == 0) $this->role = Role::ADMIN; diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index 219ded5..fa1b762 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -83,7 +83,7 @@ class MyAccount $keys = ["email", "surname", "first_name", "birth_date", "gender", "address", "postal_code", "city", "country", "phone_number", "school", "class", "responsible_name", "responsible_phone", "responsible_email", "description"]; - if ($this->user->getRole() != Role::PARTICIPANT) + if ($this->user->getRole() == Role::PARTICIPANT) $this->class = SchoolClass::fromName(strtoupper($this->class)); else $this->class = SchoolClass::ADULT; From 59985f8fc88ff8925c33be089bf710dd73e746e4 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Feb 2020 16:44:38 +0100 Subject: [PATCH 107/120] Corrections mineures --- dispatcher.php | 2 +- server_files/controllers/mon_compte.php | 3 ++- server_files/controllers/view_file.php | 18 +++++++++++++----- server_files/views/inscription.php | 2 +- server_files/views/mon_compte.php | 4 ++++ 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/dispatcher.php b/dispatcher.php index 00de4bc..6849162 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -32,7 +32,7 @@ $ROUTES["^ajouter_organisateur$"] = ["server_files/controllers/ajouter_organisat $ROUTES["^ajouter_tournoi$"] = ["server_files/controllers/ajouter_tournoi.php"]; $ROUTES["^confirmer_mail/([a-z0-9]*)/?$"] = ["server_files/controllers/confirmer_mail.php", "token"]; $ROUTES["^connexion/(confirmation-mail)/?$"] = ["server_files/controllers/connexion.php", "confirmation-mail"]; -$ROUTES["^connexion/(mdp_oublie)/?$"] = ["server_files/controllers/connexion.php", "mdp_oublie"]; +$ROUTES["^connexion/(mdp-oublie)/?$"] = ["server_files/controllers/connexion.php", "mdp_oublie"]; $ROUTES["^connexion/(reinitialiser_mdp)/(.*)/?$"] = ["server_files/controllers/connexion.php", "reset_password", "token"]; $ROUTES["^connexion/?$"] = ["server_files/controllers/connexion.php"]; $ROUTES["^deconnexion/?$"] = ["server_files/controllers/deconnexion.php"]; diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index fa1b762..9d7998c 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -188,7 +188,8 @@ class SendDocument ensure($this->file["size"] <= 2e6, "Le fichier doit peser moins que 2 Mo."); ensure(!$this->file["error"], "Une erreur est survenue."); - ensure(finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->file["tmp_name"]) == "application/pdf", "Le fichier doit être au format PDF."); + $mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->file["tmp_name"]); + ensure($mime == "application/pdf" || $mime = "image/png" || $mime == "image/jpeg", "Le fichier doit être au format PDF."); ensure(is_dir("$LOCAL_PATH/files") || mkdir("$LOCAL_PATH/files"), "Un problème est survenue dans l'envoi du fichier. Veuillez contacter l'administrateur du serveur."); } diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index f576f9e..98c2dcc 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -32,14 +32,14 @@ if ($file !== null) { if ($type == DocumentType::SOLUTION) { $problem = $file->getProblem(); - $name = "Problème $problem $trigram.pdf"; + $name = "Problème $problem $trigram"; if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; } else if ($type == DocumentType::SYNTHESIS) { $dest = $file->getDest(); - $name = "Note de synthèse $trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . ".pdf"; + $name = "Note de synthèse $trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur"); if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; @@ -68,18 +68,26 @@ if ($file !== null) { break; } if ($type == DocumentType::MOTIVATION_LETTER) - $name = "Lettre de motivation de l'équipe $trigram.pdf"; + $name = "Lettre de motivation de l'équipe $trigram"; else { $surname = $user->getSurname(); $first_name = $user->getFirstName(); - $name .= " de $first_name $surname.pdf"; + $name .= " de $first_name $surname"; } } } else require_once "server_files/404.php"; -header("Content-Type: application/pdf"); +$mime = finfo_file(finfo_open(FILEINFO_MIME_TYPE), "$LOCAL_PATH/files/$id"); +if ($mime == "application/pdf") + $name .= ".pdf"; +elseif ($mime == "image/png") + $name .= ".png"; +else + $name = ".jpg"; + +header("Content-Type: $mime"); header("Content-Disposition: inline; filename=\"$name\""); readfile("$LOCAL_PATH/files/$id"); diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index 6ebf717..92f1285 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -86,7 +86,7 @@ if (isset($user) && !$has_error) {
    - +
    diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index f65bd89..e067fdc 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -223,6 +223,10 @@ if (!$has_error && (isset($my_account) || isset($new_password))) { +
    + Les fichiers doivent être au format PDF, PNG ou JPEG et peser moins de 2 Mo. +
    +
    From 826e7f7c04fe6e5ef6c41c811a39345216f3354b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 14 Feb 2020 21:12:10 +0100 Subject: [PATCH 108/120] Suppression de toute mention des Correspondances qui errait --- server_files/services/mail.php | 6 +++--- server_files/services/mail_templates/validate_team.html | 4 ++-- server_files/views/mon_equipe.php | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/server_files/services/mail.php b/server_files/services/mail.php index 6180e58..0c174cd 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -209,7 +209,7 @@ class Mailer $content = preg_replace("#{TOURNAMENT}#", $tournament->getName(), $content); $content = preg_replace("#{ACCESS_CODE}#", $team->getAccessCode(), $content); - self::brodcastToOrgas($tournament, "Demande de validation – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); + self::brodcastToOrgas($tournament, "Demande de validation – TFJM² $YEAR", $content); } public static function sendValidateTeam($team, $message) @@ -222,7 +222,7 @@ class Mailer $message = preg_replace("#\n#", "
    \n", $message); $content = preg_replace("#{MESSAGE}#", $message, $content); - self::broadcastToTeam($team, "Équipe validée – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); + self::broadcastToTeam($team, "Équipe validée – TFJM² $YEAR", $content); } public static function sendUnvalidateTeam($team, $message) @@ -235,7 +235,7 @@ class Mailer $message = preg_replace("#\n#", "
    \n", $message); $content = preg_replace("#{MESSAGE}#", $message, $content); - self::broadcastToTeam($team, "Équipe non validée – Correspondances des Jeunes Mathématicien·ne·s $YEAR - " . ($YEAR + 1), $content); + self::broadcastToTeam($team, "Équipe non validée – Correspondances des Jeunes Mathématicien·ne·s $YEAR", $content); } public static function sendValidatePayment(User $user, Team $team, Tournament $tournament, Payment $payment, $message) diff --git a/server_files/services/mail_templates/validate_team.html b/server_files/services/mail_templates/validate_team.html index 1837756..0967488 100644 --- a/server_files/services/mail_templates/validate_team.html +++ b/server_files/services/mail_templates/validate_team.html @@ -2,13 +2,13 @@ - Équipe validée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} + Équipe validée – TFJM² {YEAR} Bonjour {FIRST_NAME} {SURNAME},

    Félicitations ! Votre équipe « {TEAM_NAME} » ({TRIGRAM}) est désormais validée ! Vous êtes désormais apte à travailler sur -votre problème. Lorsque les Correspondances auront débutées, vous pourrez soumettre votre vidéo sur la plateforme d'inscription. +vos problèmes et publier vos solutions sur la plateforme. {MESSAGE}

    Cordialement,
    diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index 34e20cf..2fa7df4 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -105,7 +105,7 @@ require_once "header.php";
    Attention ! Une fois votre équipe validée, vous ne pourrez plus modifier le nom - de l'équipe, le trigramme, le problème sur lequel vous souhaitez travailler ou la composition de l'équipe. + de l'équipe, le trigramme ou la composition de l'équipe.
    @@ -113,9 +113,10 @@ require_once "header.php";
    - Pour demander à valider votre équipe, vous devez avoir au moins un encadrant, quatre participants, - choisi un problème et soumis une autorisation de droit à l'image, une fiche sanitaire et une autorisation + Pour demander à valider votre équipe, vous devez avoir au moins un encadrant, quatre participants + et soumis une autorisation de droit à l'image, une fiche sanitaire et une autorisation parentale (si besoin) par participant, ainsi qu'une lettre de motivation à transmettre aux organisateurs. + Les encadrants doivent également fournir une autorisation de droit à l'image.
    Date: Fri, 14 Feb 2020 21:23:36 +0100 Subject: [PATCH 109/120] Diverses coquilles --- assets/Instructions.tex | 2 +- server_files/views/mon_compte.php | 4 ++-- server_files/views/paiement.php | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/assets/Instructions.tex b/assets/Instructions.tex index ac686ac..da293ef 100644 --- a/assets/Instructions.tex +++ b/assets/Instructions.tex @@ -67,7 +67,7 @@ Les frais d'inscription sont fixés à {PRICE} euros. Vous devez vous en acquitt Si le paiement de plusieurs élèves est fait en une seule opération, merci de contacter \href{mailto: contact@tfjm.org}{contact@tfjm.org} \textbf{avant le paiement} pour garantir l'identification de ce dernier \subsubsection*{Carte bancaire (uniquement les cartes françaises)} -Le paiement s'effectue en ligne via la plateforme à l'adresse : \url{https://www.apayer.fr/ANIMATH} +Le paiement s'effectue en ligne via la plateforme à l'adresse : \url{https://www.helloasso.com/associations/animath/evenements/tfjm-2020} Vous devez impérativement indiquer dans le champ "Référence" la mention "TFJMpu" suivie des noms et prénoms \textbf{de l'élève}. diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index e067fdc..fc840fa 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -207,7 +207,7 @@ if (!$has_error && (isset($my_account) || isset($new_password))) {
    - Ces documents peut être modifiés tant que l'équipe n'est pas validée. Les fichiers doivent peser au maximum 2 Mo et doivent + Ces documents peuvent être modifiés tant que l'équipe n'est pas validée. Les fichiers doivent peser au maximum 2 Mo et doivent être au format PDF.
    @@ -217,7 +217,7 @@ if (!$has_error && (isset($my_account) || isset($new_password))) { Modèle d'autorisation parentale : Télécharger - Modèle vierge
    - Modèle d'autorisation de droit à l'image : Télécharger + Modèle d'autorisation de droit à l'image : Télécharger - Modèle vierge diff --git a/server_files/views/paiement.php b/server_files/views/paiement.php index 4f3c8c3..4764047 100644 --- a/server_files/views/paiement.php +++ b/server_files/views/paiement.php @@ -11,8 +11,9 @@ require_once "header.php" if ($payment->getValidationStatus() == ValidationStatus::NOT_READY) { ?>
    Le prix du tournoi est de getPrice() ?> €. Vous pouvez par carte bancaire via - la plateforme dédiée (qui sera créée ultérieurement), et indiquer sur cette page les informations de paiement - qui nous permettront de le retrouver. Si ce n'est pas possible, vous pouvez également procéder à un virement sur le compte :

    + la plateforme dédiée, + et indiquer sur cette page les informations de paiement qui nous permettront de le retrouver. + Si ce n'est pas possible, vous pouvez également procéder à un virement sur le compte :

    IBAN : FR76 1027 8065 0000 0206 4290 127
    BIC : CMCIFR2A

    en précisant bien en référence du virement la mention TFJMpu suivie des nom et prénom de l'élève.

    From 0dab65d82bbff5bb523bd9b54eb484e7a1d3a88c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 18 Feb 2020 15:33:55 +0100 Subject: [PATCH 110/120] =?UTF-8?q?3=20encadrants=20max=20par=20=C3=A9quip?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/classes/Team.php | 2 +- server_files/controllers/informations.php | 2 +- server_files/controllers/rejoindre_equipe.php | 4 +- server_files/model.php | 3 +- server_files/views/equipe.php | 2 +- setup/create_database.sql | 349 +++++++++++------- 6 files changed, 227 insertions(+), 135 deletions(-) diff --git a/server_files/classes/Team.php b/server_files/classes/Team.php index 27d1f0e..3b16bc5 100644 --- a/server_files/classes/Team.php +++ b/server_files/classes/Team.php @@ -67,7 +67,7 @@ class Team $this->name = $data["name"]; $this->trigram = $data["trigram"]; $this->tournament = $data["tournament"]; - $this->encadrants = [$data["encadrant_1"], $data["encadrant_2"]]; + $this->encadrants = [$data["encadrant_1"], $data["encadrant_2"], $data["encadrant_3"]]; $this->participants = [$data["participant_1"], $data["participant_2"], $data["participant_3"], $data["participant_4"], $data["participant_5"], $data["participant_6"]]; $this->inscription_date = $data["inscription_date"]; $this->validation_status = ValidationStatus::fromName($data["validation_status"]); diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index 6923d19..e50ed98 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -103,7 +103,7 @@ class AttributeTeam ensure($this->team->getValidationStatus() == ValidationStatus::NOT_READY, "Cette équipe est déjà validée ou en cours de validation."); $role = $user->getRole(); - for ($i = 1; $i <= $role == Role::ENCADRANT ? 2 : 6; ++$i) { + for ($i = 1; $i <= $role == Role::ENCADRANT ? 3 : 6; ++$i) { if (($role == Role::PARTICIPANT ? $this->team->getParticipants()[$i - 1] : $this->team->getEncadrants()[$i]) == NULL) break; } diff --git a/server_files/controllers/rejoindre_equipe.php b/server_files/controllers/rejoindre_equipe.php index 4379118..c7db182 100644 --- a/server_files/controllers/rejoindre_equipe.php +++ b/server_files/controllers/rejoindre_equipe.php @@ -35,14 +35,14 @@ class JoinTeam ensure($this->team != null, "Ce code d'accès est invalide."); ensure($this->team->getValidationStatus() == ValidationStatus::NOT_READY, "Cette équipe est déjà validée ou en cours de validation, vous ne pouvez pas la rejoindre."); - for ($i = 1; $i <= $_SESSION["role"] == Role::PARTICIPANT ? 6 : 2; ++$i) { + for ($i = 1; $i <= $_SESSION["role"] == Role::PARTICIPANT ? 6 : 3; ++$i) { if (($_SESSION["role"] == Role::PARTICIPANT ? $this->team->getParticipants()[$i - 1] : $this->team->getEncadrants()[$i - 1]) == NULL) break; } $this->min_null_index = $i; - ensure($_SESSION["role"] == Role::PARTICIPANT && $this->min_null_index <= 6 || $_SESSION["role"] == Role::ENCADRANT && $this->min_null_index <= 2, "Il n'y a plus de place pour vous dans l'équipe."); + ensure($_SESSION["role"] == Role::PARTICIPANT && $this->min_null_index <= 6 || $_SESSION["role"] == Role::ENCADRANT && $this->min_null_index <= 3, "Il n'y a plus de place pour vous dans l'équipe."); } public function joinTeam() diff --git a/server_files/model.php b/server_files/model.php index 760b806..6db9f62 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -47,11 +47,12 @@ function quitTeam($user_id = -1) if ($role == Role::ADMIN || $role == Role::ORGANIZER) return; - for ($i = 1; $i <= ($role == Role::ENCADRANT ? 2 : 6); ++$i) + for ($i = 1; $i <= ($role == Role::ENCADRANT ? 3 : 6); ++$i) /** @noinspection SqlResolve */ $DB->exec("UPDATE `teams` SET `" . strtolower(Role::getName($role)) . "_$i` = NULL WHERE `" . strtolower(Role::getName($role)) . "_$i` = $user_id;"); $user->setTeamId(null); $DB->exec("UPDATE `teams` SET `encadrant_1` = `encadrant_2`, `encadrant_2` = NULL WHERE `encadrant_1` IS NULL;"); + $DB->exec("UPDATE `teams` SET `encadrant_2` = `encadrant_3`, `encadrant_3` = NULL WHERE `encadrant_2` IS NULL;"); for ($i = 1; $i <= 5; ++$i) { /** @noinspection SqlResolve */ $DB->exec("UPDATE `teams` SET `participant_$i` = `participant_" . strval($i + 1) . "`, `participant_" . strval($i + 1) . "` = NULL WHERE `participant_$i` IS NULL;"); diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index 62fa1bf..d555230 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -38,7 +38,7 @@
    getEncadrants()[$i - 1] == NULL) continue; $encadrant = User::fromId($team->getEncadrants()[$i - 1]); diff --git a/setup/create_database.sql b/setup/create_database.sql index d885d4f..bc1eb1f 100644 --- a/setup/create_database.sql +++ b/setup/create_database.sql @@ -1,184 +1,275 @@ -- phpMyAdmin SQL Dump --- version 4.6.6deb4 +-- version 4.7.5 -- https://www.phpmyadmin.net/ -- --- Client : localhost:3306 --- Généré le : Dim 08 Septembre 2019 à 19:00 --- Version du serveur : 10.3.15-MariaDB-1 --- Version de PHP : 7.3.4-2 +-- Host: db +-- Erstellungszeit: 18. Feb 2020 um 14:32 +-- Server-Version: 5.7.20 +-- PHP-Version: 7.1.9 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET AUTOCOMMIT = 0; +START TRANSACTION; SET time_zone = "+02:00"; -/*!40101 SET @OLD_CHARACTER_SET_CLIENT = @@CHARACTER_SET_CLIENT */; -/*!40101 SET @OLD_CHARACTER_SET_RESULTS = @@CHARACTER_SET_RESULTS */; -/*!40101 SET @OLD_COLLATION_CONNECTION = @@COLLATION_CONNECTION */; +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8mb4 */; -- --- Base de données : `tfjm` +-- Datenbank: `inscription_tfjm` -- -CREATE DATABASE IF NOT EXISTS `inscription-tfjm` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci; -USE `inscription-tfjm`; +CREATE DATABASE IF NOT EXISTS `inscription_tfjm` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; +USE `inscription_tfjm`; -- -------------------------------------------------------- -- --- Structure de la table `documents` +-- Tabellenstruktur für Tabelle `documents` -- -CREATE TABLE IF NOT EXISTS `documents` -( - `file_id` varchar(64) NOT NULL, - `user` int(11) NOT NULL, - `team` int(11) NOT NULL, - `tournament` int(11) NOT NULL, - `type` varchar(64) NOT NULL, - `uploaded_at` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`file_id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `documents` ( + `file_id` varchar(64) NOT NULL, + `user` int(11) NOT NULL, + `team` int(11) NOT NULL, + `tournament` int(11) NOT NULL, + `type` varchar(64) NOT NULL, + `uploaded_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- --- Structure de la table `organizers` +-- Tabellenstruktur für Tabelle `organizers` -- -CREATE TABLE IF NOT EXISTS `organizers` -( - `id` int(11) NOT NULL AUTO_INCREMENT, - `organizer` int(11) NOT NULL, - `tournament` int(11) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `organizers` ( + `id` int(11) NOT NULL, + `organizer` int(11) NOT NULL, + `tournament` int(11) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- --- Structure de la table `solutions` +-- Tabellenstruktur für Tabelle `payments` -- -CREATE TABLE IF NOT EXISTS `solutions` -( - `file_id` varchar(64) NOT NULL, - `team` int(11) NOT NULL, - `tournament` int(11) NOT NULL, - `problem` int(11) NOT NULL, - `uploaded_at` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`file_id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `payments` ( + `id` int(11) NOT NULL, + `user` int(11) NOT NULL, + `tournament` int(11) NOT NULL, + `amount` tinyint(4) NOT NULL, + `method` enum('CREDIT_CARD','BANK_CHECK','BANK_TRANSFER','CASH','SCHOLARSHIP','NOT_PAID') COLLATE utf8_unicode_ci NOT NULL, + `transaction_infos` text COLLATE utf8_unicode_ci NOT NULL, + `validation_status` enum('NOT_READY','WAITING','VALIDATED','') COLLATE utf8_unicode_ci NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -- -------------------------------------------------------- -- --- Structure de la table `syntheses` +-- Tabellenstruktur für Tabelle `solutions` -- -CREATE TABLE IF NOT EXISTS `syntheses` -( - `file_id` varchar(64) NOT NULL, - `team` int(11) NOT NULL, - `tournament` int(11) NOT NULL, - `dest` varchar(64) NOT NULL, - `uploaded_at` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`file_id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `solutions` ( + `file_id` varchar(64) NOT NULL, + `team` int(11) NOT NULL, + `tournament` int(11) NOT NULL, + `problem` int(11) NOT NULL, + `uploaded_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- --- Structure de la table `teams` +-- Tabellenstruktur für Tabelle `syntheses` -- -CREATE TABLE IF NOT EXISTS `teams` -( - `id` int(11) NOT NULL AUTO_INCREMENT, - `name` varchar(64) NOT NULL, - `trigram` varchar(3) NOT NULL, - `tournament` int(8) NOT NULL, - `encadrant_1` int(8) DEFAULT NULL, - `encadrant_2` int(8) DEFAULT NULL, - `participant_1` int(8) DEFAULT NULL, - `participant_2` int(8) DEFAULT NULL, - `participant_3` int(8) DEFAULT NULL, - `participant_4` int(8) DEFAULT NULL, - `participant_5` int(8) DEFAULT NULL, - `participant_6` int(8) DEFAULT NULL, - `inscription_date` timestamp NOT NULL DEFAULT current_timestamp(), - `validation_status` varchar(64) NOT NULL, - `final_selection` tinyint(1) NOT NULL DEFAULT 0, - `access_code` varchar(6) NOT NULL, - `year` int(4) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `syntheses` ( + `file_id` varchar(64) NOT NULL, + `team` int(11) NOT NULL, + `tournament` int(11) NOT NULL, + `dest` varchar(64) NOT NULL, + `uploaded_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- --- Structure de la table `tournaments` +-- Tabellenstruktur für Tabelle `teams` -- -CREATE TABLE IF NOT EXISTS `tournaments` -( - `id` int(8) NOT NULL AUTO_INCREMENT, - `name` varchar(64) NOT NULL, - `size` int(1) NOT NULL, - `place` varchar(255) NOT NULL, - `price` int(4) NOT NULL, - `description` varchar(255) NOT NULL, - `date_start` date NOT NULL, - `date_end` date NOT NULL, - `date_inscription` datetime NOT NULL, - `date_solutions` datetime NOT NULL, - `date_syntheses` datetime NOT NULL, - `final` tinyint(1) NOT NULL DEFAULT 0, - `year` int(4) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `teams` ( + `id` int(11) NOT NULL, + `name` varchar(64) NOT NULL, + `trigram` varchar(3) NOT NULL, + `tournament` int(8) NOT NULL, + `encadrant_1` int(8) DEFAULT NULL, + `encadrant_2` int(8) DEFAULT NULL, + `encadrant_3` int(11) DEFAULT NULL, + `participant_1` int(8) DEFAULT NULL, + `participant_2` int(8) DEFAULT NULL, + `participant_3` int(8) DEFAULT NULL, + `participant_4` int(8) DEFAULT NULL, + `participant_5` int(8) DEFAULT NULL, + `participant_6` int(8) DEFAULT NULL, + `inscription_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `validation_status` enum('NOT_READY','WAITING','VALIDATED','') NOT NULL, + `final_selection` tinyint(1) NOT NULL DEFAULT '0', + `access_code` varchar(6) NOT NULL, + `year` int(4) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -------------------------------------------------------- -- --- Structure de la table `users` +-- Tabellenstruktur für Tabelle `tournaments` -- -CREATE TABLE IF NOT EXISTS `users` -( - `id` int(8) NOT NULL AUTO_INCREMENT, - `email` varchar(255) NOT NULL, - `pwd_hash` varchar(64) NOT NULL, - `surname` varchar(255) NOT NULL, - `first_name` varchar(255) NOT NULL, - `birth_date` date DEFAULT NULL, - `gender` char(1) DEFAULT NULL, - `address` varchar(255) DEFAULT NULL, - `postal_code` int(5) DEFAULT NULL, - `city` varchar(255) DEFAULT NULL, - `country` varchar(255) DEFAULT 'France', - `phone_number` varchar(20) DEFAULT NULL, - `school` varchar(255) DEFAULT NULL, - `class` varchar(255) DEFAULT NULL, - `responsible_name` varchar(255) DEFAULT NULL, - `responsible_phone` varchar(20) DEFAULT NULL, - `responsible_email` varchar(255) DEFAULT NULL, - `description` varchar(255) DEFAULT NULL, - `role` varchar(64) NOT NULL, - `team_id` int(8) DEFAULT NULL, - `year` int(4) NOT NULL DEFAULT 2020, - `confirm_email` varchar(64) DEFAULT NULL COMMENT 'Jeton de confirmation d''e-mail', - `forgotten_password` varchar(64) DEFAULT NULL COMMENT 'Jeton de récupération de mot de passe', - `inscription_date` datetime NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`id`) -) ENGINE = InnoDB - DEFAULT CHARSET = utf8; +CREATE TABLE `tournaments` ( + `id` int(8) NOT NULL, + `name` varchar(64) NOT NULL, + `size` int(1) NOT NULL, + `place` varchar(255) NOT NULL, + `price` int(4) NOT NULL, + `description` varchar(255) NOT NULL, + `date_start` date NOT NULL, + `date_end` date NOT NULL, + `date_inscription` datetime NOT NULL, + `date_solutions` datetime NOT NULL, + `date_syntheses` datetime NOT NULL, + `final` tinyint(1) NOT NULL DEFAULT '0', + `year` int(4) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*!40101 SET CHARACTER_SET_CLIENT = @OLD_CHARACTER_SET_CLIENT */; -/*!40101 SET CHARACTER_SET_RESULTS = @OLD_CHARACTER_SET_RESULTS */; -/*!40101 SET COLLATION_CONNECTION = @OLD_COLLATION_CONNECTION */; +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `users` +-- + +CREATE TABLE `users` ( + `id` int(8) NOT NULL, + `email` varchar(255) NOT NULL, + `pwd_hash` varchar(64) NOT NULL, + `surname` varchar(255) NOT NULL, + `first_name` varchar(255) NOT NULL, + `birth_date` date DEFAULT NULL, + `gender` char(1) DEFAULT NULL, + `address` varchar(255) DEFAULT NULL, + `postal_code` int(5) DEFAULT NULL, + `city` varchar(255) DEFAULT NULL, + `country` varchar(255) DEFAULT 'France', + `phone_number` varchar(20) DEFAULT NULL, + `school` varchar(255) DEFAULT NULL, + `class` enum('SECONDE','PREMIERE','TERMINALE','ADULT') DEFAULT NULL, + `responsible_name` varchar(255) DEFAULT NULL, + `responsible_phone` varchar(20) DEFAULT NULL, + `responsible_email` varchar(255) DEFAULT NULL, + `description` varchar(255) DEFAULT NULL, + `role` enum('PARTICIPANT','ENCADRANT','ORGANIZER','ADMIN') NOT NULL, + `team_id` int(8) DEFAULT NULL, + `year` int(4) NOT NULL DEFAULT '2020', + `confirm_email` varchar(64) DEFAULT NULL COMMENT 'Jeton de confirmation d''e-mail', + `forgotten_password` varchar(64) DEFAULT NULL COMMENT 'Jeton de récupération de mot de passe', + `inscription_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Indizes der exportierten Tabellen +-- + +-- +-- Indizes für die Tabelle `documents` +-- +ALTER TABLE `documents` + ADD PRIMARY KEY (`file_id`); + +-- +-- Indizes für die Tabelle `organizers` +-- +ALTER TABLE `organizers` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `organizer` (`organizer`,`tournament`); + +-- +-- Indizes für die Tabelle `payments` +-- +ALTER TABLE `payments` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `user` (`user`); + +-- +-- Indizes für die Tabelle `solutions` +-- +ALTER TABLE `solutions` + ADD PRIMARY KEY (`file_id`); + +-- +-- Indizes für die Tabelle `syntheses` +-- +ALTER TABLE `syntheses` + ADD PRIMARY KEY (`file_id`); + +-- +-- Indizes für die Tabelle `teams` +-- +ALTER TABLE `teams` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `name/year` (`name`,`year`), + ADD UNIQUE KEY `trigram/year` (`trigram`,`year`); + +-- +-- Indizes für die Tabelle `tournaments` +-- +ALTER TABLE `tournaments` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `Name/year` (`name`,`year`) USING BTREE; + +-- +-- Indizes für die Tabelle `users` +-- +ALTER TABLE `users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `email/year` (`email`,`year`) USING BTREE; + +-- +-- AUTO_INCREMENT für exportierte Tabellen +-- + +-- +-- AUTO_INCREMENT für Tabelle `organizers` +-- +ALTER TABLE `organizers` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=40; + +-- +-- AUTO_INCREMENT für Tabelle `payments` +-- +ALTER TABLE `payments` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=111; + +-- +-- AUTO_INCREMENT für Tabelle `teams` +-- +ALTER TABLE `teams` + MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=61; + +-- +-- AUTO_INCREMENT für Tabelle `tournaments` +-- +ALTER TABLE `tournaments` + MODIFY `id` int(8) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=12; + +-- +-- AUTO_INCREMENT für Tabelle `users` +-- +ALTER TABLE `users` + MODIFY `id` int(8) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=370; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; From 0018ce05ec3248428d8a8ca167f8b0ba9e1a64ca Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 18 Feb 2020 15:46:34 +0100 Subject: [PATCH 111/120] =?UTF-8?q?Les=20organisateurs=20ne=20pouvaient=20?= =?UTF-8?q?pas=20valider=20les=20=C3=A9quipes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/equipe.php | 3 +++ server_files/views/equipe.php | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 6727918..57bb549 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -8,6 +8,9 @@ $trigram = htmlspecialchars($_GET["trigram"]); $team = Team::fromTrigram($trigram); $tournament = Tournament::fromId($team->getTournamentId()); +if ($_SESSION["role"] == Role::ORGANIZER && !$tournament->organize($_SESSION["user_id"])) + require_once "server_files/403.php"; + if ($team === null) require_once "server_files/404.php"; diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index d555230..65d4dd5 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -78,7 +78,7 @@ -getValidationStatus() == ValidationStatus::WAITING && $_SESSION["role"] == Role::ADMIN) { ?> +getValidationStatus() == ValidationStatus::WAITING) { ?>
    @@ -96,7 +96,7 @@ isSelectedForFinal() && $team->getValidationStatus() == ValidationStatus::VALIDATED && $_SESSION["role"] == Role::ADMIN) { ?> +if (!$team->isSelectedForFinal() && $team->getValidationStatus() == ValidationStatus::VALIDATED) { ?>
    From d4fa8d90543e4889b8c9f36adfb33997f393b398 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 18 Feb 2020 16:10:18 +0100 Subject: [PATCH 112/120] =?UTF-8?q?Les=20infos=20des=20respos=20l=C3=A9gau?= =?UTF-8?q?x=20n'=C3=A9taient=20pas=20sauvegard=C3=A9s=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server_files/controllers/inscription.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 99adfe4..9f2ebbb 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -87,10 +87,10 @@ class NewUser global $DB, $YEAR; $req = $DB->prepare("INSERT INTO `users`(`email`, `pwd_hash`, `confirm_email`, `surname`, `first_name`, `birth_date`, `gender`, - `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + `address`, `postal_code`, `city`, `country`, `phone_number`, `school`, `class`, `role`, `description`, `responsible_name`, `responsible_phone`, `responsible_email`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); $req->execute([$this->email, password_hash($this->password, PASSWORD_BCRYPT), $this->confirm_email_token, $this->surname, $this->first_name, $this->birth_date, $this->gender, $this->address, - $this->postal_code, $this->city, $this->country, $this->phone_number, $this->school, SchoolClass::getName($this->class), Role::getName($this->role), $this->description, $YEAR]); + $this->postal_code, $this->city, $this->country, $this->phone_number, $this->school, SchoolClass::getName($this->class), Role::getName($this->role), $this->description, $this->responsible_name, $this->responsible_phone, $this->responsible_email, $YEAR]); Mailer::sendRegisterMail($this); } From 88dcb68aa88f31f9af12da471179ecd7ec73c59c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 18 Feb 2020 16:33:55 +0100 Subject: [PATCH 113/120] Organizers can change name & trigram --- dispatcher.php | 1 + server_files/controllers/equipe.php | 57 ++++++++++++++++++++++++++++- server_files/views/equipe.php | 43 ++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) diff --git a/dispatcher.php b/dispatcher.php index 6849162..17a7c94 100644 --- a/dispatcher.php +++ b/dispatcher.php @@ -37,6 +37,7 @@ $ROUTES["^connexion/(reinitialiser_mdp)/(.*)/?$"] = ["server_files/controllers/c $ROUTES["^connexion/?$"] = ["server_files/controllers/connexion.php"]; $ROUTES["^deconnexion/?$"] = ["server_files/controllers/deconnexion.php"]; $ROUTES["^equipe/([A-Z]{3})/?$"] = ["server_files/controllers/equipe.php", "trigram"]; +$ROUTES["^equipe/([A-Z]{3})/(modifier)?$"] = ["server_files/controllers/equipe.php", "trigram", "modifier"]; $ROUTES["^file/([a-z0-9]{64})/?$"] = ["server_files/controllers/view_file.php", "file_id"]; $ROUTES["^informations/([0-9]*)/.*?$"] = ["server_files/controllers/informations.php", "id"]; $ROUTES["^inscription/?$"] = ["server_files/controllers/inscription.php"]; diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 57bb549..8af48fd 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -14,6 +14,18 @@ if ($_SESSION["role"] == Role::ORGANIZER && !$tournament->organize($_SESSION["us if ($team === null) require_once "server_files/404.php"; +if (isset($_POST["team_edit"])) { + $edit_team = new EditTeam($_POST); + try { + $edit_team->makeVerifications(); + $edit_team->updateTeam(); + } + catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } +} + if (isset($_POST["validate"])) { $team->setValidationStatus(ValidationStatus::VALIDATED); Mailer::sendValidateTeam($team, $_POST["message"]); @@ -23,7 +35,6 @@ elseif (isset($_POST["unvalidate"])) { Mailer::sendUnvalidateTeam($team, $_POST["message"]); } - if (isset($_POST["select"])) { $team->selectForFinal(true); $team->setValidationStatus(ValidationStatus::NOT_READY); @@ -57,6 +68,50 @@ if (isset($_POST["download_zip"])) { exit(); } +class EditTeam +{ + public $name; + public $trigram; + public $tournament_id; + private $team; + private $tournament; + + public function __construct($data) + { + global $team; + + foreach ($data as $key => $value) + $this->$key = htmlspecialchars($value); + + $this->trigram = strtoupper($this->trigram); + $this->team = $team; + $this->tournament = Tournament::fromId($this->tournament_id); + } + + public function makeVerifications() + { + ensure($this->name != "" && $this->name != null, "Veuillez spécifier un nom d'équipe."); + ensure($this->name == $this->team->getName() || !teamExists($this->name), "Une équipe existe déjà avec ce nom."); + ensure(preg_match("#^[A-Z]{3}$#", $this->trigram), "Le trigramme n'est pas valide."); + ensure($this->trigram == $this->team->getTrigram() || !trigramExists($this->trigram), "Une équipe a déjà choisi ce trigramme."); + ensure($this->tournament != null, "Le tournoi indiqué n'existe pas."); + ensure($this->tournament_id == $this->team->getTournamentId() || $_SESSION["role"] == Role::ADMIN, "Vous n'avez pas la permission pour changer cette équipe de tournoi."); + } + + public function updateTeam() + { + global $URL_BASE; + + $this->team->setName($this->name); + $this->team->setTrigram($this->trigram); + $this->team->setTournamentId($this->tournament_id); + + $_SESSION["tournament"] = $this->tournament; + + header("Location: $URL_BASE/equipe/$this->trigram"); + } +} + $documents = $tournament->getAllDocuments($team->getId()); $documents_final = null; diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index 65d4dd5..08ce9a3 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -59,6 +59,49 @@ ?>
    + + + +
    +
    + + +
    + +
    + + +
    +
    + +
    + + +
    + +
    + +
    +
    + +getValidationStatus() != ValidationStatus::VALIDATED) { ?> +
    + + +

    Documents

    From 45426e6835d132644bb42eca6496dbca8597dc85 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 21 Feb 2020 23:26:47 +0100 Subject: [PATCH 114/120] Minor fixes --- server_files/classes/Role.php | 7 +++++++ server_files/classes/User.php | 2 +- server_files/controllers/inscription.php | 2 +- server_files/controllers/mon_compte.php | 2 +- server_files/views/informations.php | 4 ++-- server_files/views/inscription.php | 2 +- server_files/views/mon_compte.php | 2 +- 7 files changed, 14 insertions(+), 7 deletions(-) diff --git a/server_files/classes/Role.php b/server_files/classes/Role.php index 5fa557a..28ef255 100644 --- a/server_files/classes/Role.php +++ b/server_files/classes/Role.php @@ -2,6 +2,7 @@ class Role { + const OBSERVER = -1; const PARTICIPANT = 0; const ENCADRANT = 1; const ORGANIZER = 2; @@ -9,6 +10,8 @@ class Role public static function getTranslatedName($role) { switch ($role) { + case self::OBSERVER: + return "Observateur"; case self::ENCADRANT: return "Encadrant"; case self::ORGANIZER: @@ -22,6 +25,8 @@ class Role public static function getName($role) { switch ($role) { + case self::OBSERVER: + return "OBSERVER"; case self::ENCADRANT: return "ENCADRANT"; case self::ORGANIZER: @@ -35,6 +40,8 @@ class Role public static function fromName($name) { switch ($name) { + case "OBSERVER": + return self::OBSERVER; case "ENCADRANT": return self::ENCADRANT; case "ORGANIZER": diff --git a/server_files/classes/User.php b/server_files/classes/User.php index b069b97..e9fd91f 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -90,7 +90,7 @@ class User { global $DB, $YEAR; $admins = []; - $req = $DB->query("SELECT * FROM `users` WHERE `role` = 'ORGANIZER' OR `role` = 'ADMIN' AND `year` = $YEAR ORDER BY `role`, `surname`, `first_name`;"); + $req = $DB->query("SELECT * FROM `users` WHERE `role` = 'ORGANIZER' OR `role` = 'ADMIN' AND `year` = $YEAR ORDER BY `role` DESC, `surname`, `first_name`;"); while (($data = $req->fetch()) !== false) { $admin = new User(); diff --git a/server_files/controllers/inscription.php b/server_files/controllers/inscription.php index 9f2ebbb..d0ab6f3 100644 --- a/server_files/controllers/inscription.php +++ b/server_files/controllers/inscription.php @@ -57,7 +57,7 @@ class NewUser ensure($this->first_name != "", "Le prénom est obligatoire."); ensure(dateWellFormed($this->birth_date), "La date de naissance est invalide."); ensure($this->birth_date < $YEAR . "-01-01", "Vous devez être né."); - ensure($this->gender == "M" || $this->gender == "F", "Le sexe indiqué est invalide."); + ensure($this->gender == "M" || $this->gender == "F", "Merci de spécifier un genre."); ensure(preg_match("#^[0-9]{4}[0-9]?$#", $this->postal_code) && intval($this->postal_code) >= 01000 && intval($this->postal_code) <= 95999, "Le code postal est invalide."); if ($this->country == "") $this->country = "France"; diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index 9d7998c..71d26cf 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -101,7 +101,7 @@ class MyAccount ensure($this->email == $this->user->getEmail() || !userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); ensure(dateWellFormed($this->birth_date), "La date de naissance est invalide."); ensure($this->birth_date < $YEAR . "-01-01", "Vous devez être né."); - ensure($this->gender == "M" || $this->gender == "F", "Le sexe indiqué est invalide."); + ensure($this->gender == "M" || $this->gender == "F", "Merci de spécifier un genre."); ensure(preg_match("#^[0-9]{4}[0-9]?$#", $this->postal_code) && intval($this->postal_code) >= 01000 && intval($this->postal_code) <= 95999, "Le code postal est invalide."); ensure(strlen($this->phone_number) >= 10, "Le numéro de téléphone est invalide."); diff --git a/server_files/views/informations.php b/server_files/views/informations.php index 3cd165a..61b06fa 100644 --- a/server_files/views/informations.php +++ b/server_files/views/informations.php @@ -74,7 +74,7 @@ if ($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT
    - Sexe : getGender() == "M" ? "Masculin" : "Féminin" ?>
    + Genre : getGender() == "M" ? "Masculin" : "Féminin" ?>
    @@ -93,7 +93,7 @@ if ($user->getRole() == Role::PARTICIPANT || $user->getRole() == Role::ENCADRANT getRole() == Role::PARTICIPANT) { ?>
    Lycée : getSchool() ?>
    - Classe : getClass()) ?> + Classe : getClass()) ?>
    diff --git a/server_files/views/inscription.php b/server_files/views/inscription.php index 92f1285..ed94887 100644 --- a/server_files/views/inscription.php +++ b/server_files/views/inscription.php @@ -72,7 +72,7 @@ if (isset($user) && !$has_error) {
    - +
    - +
    Date: Mon, 13 Apr 2020 00:35:22 +0200 Subject: [PATCH 115/120] Collect emails --- server_files/config.php | 1 + server_files/controllers/tournoi.php | 24 ++++++++++++++++++++++++ server_files/controllers/tournois.php | 27 +++++++++++++++++++++++++++ server_files/views/tournoi.php | 4 ++++ server_files/views/tournois.php | 6 ++++++ 5 files changed, 62 insertions(+) diff --git a/server_files/config.php b/server_files/config.php index 991967f..00b9ff3 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -17,6 +17,7 @@ $DB_NAME = getenv("TFJM_DB_NAME"); $DB_USER = getenv("TFJM_DB_USER"); $DB_PASSWORD = getenv("TFJM_DB_PASSWORD"); + try { $DB = new PDO("mysql:host=$DB_HOST;dbname=$DB_NAME;charset=utf8", "$DB_USER", "$DB_PASSWORD", array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)); } diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 5d7d2f8..3b5b451 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -122,4 +122,28 @@ class UpdateTournament } } +if ($_SESSION["role"] == Role::ENCADRANT || $_SESSION["role"] == Role::ADMIN) { + $emails = []; + foreach ($tournament->getOrganizers() as $organizer) + $emails[] = $organizer->getEmail(); + + foreach ($teams as $team) { + foreach ($team->getEncadrants() as $encadrant_id) { + $encadrant = User::fromId($encadrant_id); + if ($encadrant != null) + $emails[] = $encadrant->getEmail(); + } + + foreach ($team->getParticipants() as $participant_id) { + $participant = User::fromId($participant_id); + if ($participant != null) { + $emails[] = $participant->getEmail(); + if ($participant->getResponsibleEmail() != null) { + $emails[] = $participant->getResponsibleEmail(); + } + } + } + } +} + require_once "server_files/views/tournoi.php"; diff --git a/server_files/controllers/tournois.php b/server_files/controllers/tournois.php index db4c402..cf9ebce 100644 --- a/server_files/controllers/tournois.php +++ b/server_files/controllers/tournois.php @@ -2,4 +2,31 @@ $tournaments = Tournament::getAllTournaments(); +$emails = []; + +if ($_SESSION["role"] == Role::ENCADRANT || $_SESSION["role"] == Role::ADMIN) { + foreach ($tournaments as $tournament) { + foreach ($tournament->getOrganizers() as $organizer) + $emails[] = $organizer->getEmail(); + + foreach ($tournament->getAllTeams() as $team) { + foreach ($team->getEncadrants() as $encadrant_id) { + $encadrant = User::fromId($encadrant_id); + if ($encadrant != null) + $emails[] = $encadrant->getEmail(); + } + + foreach ($team->getParticipants() as $participant_id) { + $participant = User::fromId($participant_id); + if ($participant != null) { + $emails[] = $participant->getEmail(); + if ($participant->getResponsibleEmail() != null) { + $emails[] = $participant->getResponsibleEmail(); + } + } + } + } + } +} + require_once "server_files/views/tournois.php"; diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 3995ee4..2d57350 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -59,6 +59,10 @@ if ($tournament->isFinal()) ?> organize($_SESSION["user_id"]))) { ?> + + diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index 2c0ae8d..a90ecb9 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -4,6 +4,12 @@

    Liste des tournois

    + + + + From 50aec3c105bff928a309285437d0cf1b4d1c0bf0 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 13 Apr 2020 03:41:15 +0200 Subject: [PATCH 116/120] Changement confinement --- server_files/classes/User.php | 7 +++---- server_files/controllers/equipe.php | 18 ++++++++++++++++++ server_files/controllers/mon_equipe.php | 14 +++++++++++++- server_files/controllers/profils.php | 7 +++++++ server_files/controllers/tournois.php | 2 +- server_files/model.php | 17 +++++++++++------ server_files/views/equipe.php | 2 +- server_files/views/header.php | 25 ++++++++++++++++++++++--- server_files/views/informations.php | 8 ++++++-- server_files/views/mon_compte.php | 11 ++++++++--- server_files/views/mon_equipe.php | 6 ++++++ server_files/views/profils.php | 4 ++++ server_files/views/tournoi.php | 8 ++++---- 13 files changed, 104 insertions(+), 25 deletions(-) diff --git a/server_files/classes/User.php b/server_files/classes/User.php index e9fd91f..cc8111e 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -121,8 +121,7 @@ class User { global $DB, $YEAR; $users = []; - $req = $DB->query("SELECT * FROM `users` WHERE (`role` = 'PARTICIPANT' OR `role` = 'ENCADRANT') " - . "AND `year` = $YEAR ORDER BY `role`, `inscription_date`;"); + $req = $DB->query("SELECT * FROM `users` WHERE `year` = $YEAR ORDER BY `role` DESC, `inscription_date`;"); while (($data = $req->fetch()) !== false) { $orphan = new User(); @@ -455,8 +454,8 @@ class User $team = Team::fromId($this->team_id); $tournament = $team->getEffectiveTournament(); - $req = $DB->prepare("SELECT `id` FROM `payments` WHERE `user` = ? AND `tournament` = ?;"); - $req->execute([$this->id, $tournament->getId()]); + $req = $DB->prepare("SELECT `id` FROM `payments` WHERE `user` = ?;"); + $req->execute([$this->id]); if (($data = $req->fetch()) !== false) return Payment::fromId($data["id"]); diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 8af48fd..9e9a2eb 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -68,6 +68,24 @@ if (isset($_POST["download_zip"])) { exit(); } +if (isset($_POST["select_tournament"])) { + $new_tournament = Tournament::fromId($_POST["select_tournament"]); + ensure($new_tournament != null, "Le tournoi indiqué n'existe pas."); + $team->setTournamentId($new_tournament->getId()); + $DB->prepare("UPDATE `documents` SET `tournament` = ? WHERE `team` = ?;")->execute([$tournament->getId(), $team->getId()]); + $DB->prepare("UPDATE `solutions` SET `tournament` = ? WHERE `team` = ?;")->execute([$tournament->getId(), $team->getId()]); + $DB->prepare("UPDATE `syntheses` SET `tournament` = ? WHERE `team` = ?;")->execute([$tournament->getId(), $team->getId()]); + foreach ($team->getParticipants() as $user) { + if ($user != null) + $DB->prepare("UPDATE `payments` SET `tournament` = ? WHERE `user` = ?;")->execute([$tournament->getId(), $user]); + } + foreach ($team->getEncadrants() as $user) { + if ($user != null) + $DB->prepare("UPDATE `payments` SET `tournament` = ? WHERE `user` = ?;")->execute([$tournament->getId(), $user]); + } + $tournament = $new_tournament; +} + class EditTeam { public $name; diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php index e3d6d34..f83957c 100644 --- a/server_files/controllers/mon_equipe.php +++ b/server_files/controllers/mon_equipe.php @@ -78,12 +78,24 @@ class MyTeam public function updateTeam() { - global $URL_BASE; + global $URL_BASE, $DB; $this->team->setName($this->name); $this->team->setTrigram($this->trigram); $this->team->setTournamentId($this->tournament_id); + $DB->prepare("UPDATE `documents` SET `tournament` = ? WHERE `team` = ?;")->execute([$this->tournament_id, $this->team->getId()]); + $DB->prepare("UPDATE `solutions` SET `tournament` = ? WHERE `team` = ?;")->execute([$this->tournament_id, $this->team->getId()]); + $DB->prepare("UPDATE `syntheses` SET `tournament` = ? WHERE `team` = ?;")->execute([$this->tournament_id, $this->team->getId()]); + foreach ($this->team->getParticipants() as $user) { + if ($user != null) + $DB->prepare("UPDATE `payments` SET `tournament` = ? WHERE `user` = ?;")->execute([$this->tournament_id, $user]); + } + foreach ($this->team->getEncadrants() as $user) { + if ($user != null) + $DB->prepare("UPDATE `payments` SET `tournament` = ? WHERE `user` = ?;")->execute([$this->tournament_id, $user]); + } + $_SESSION["tournament"] = $this->tournament; header("Location: $URL_BASE/mon-equipe"); diff --git a/server_files/controllers/profils.php b/server_files/controllers/profils.php index 64c1edb..51dc8b9 100644 --- a/server_files/controllers/profils.php +++ b/server_files/controllers/profils.php @@ -6,4 +6,11 @@ if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) $orphans = isset($_GET["orphans"]); $users = $orphans ? User::getOrphanUsers() : User::getAllUsers(); +$emails = []; + +if ($_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) { + foreach ($users as $user) + $emails[] = $user->getEmail(); +} + require_once "server_files/views/profils.php"; \ No newline at end of file diff --git a/server_files/controllers/tournois.php b/server_files/controllers/tournois.php index cf9ebce..68430cf 100644 --- a/server_files/controllers/tournois.php +++ b/server_files/controllers/tournois.php @@ -4,7 +4,7 @@ $tournaments = Tournament::getAllTournaments(); $emails = []; -if ($_SESSION["role"] == Role::ENCADRANT || $_SESSION["role"] == Role::ADMIN) { +if ($_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) { foreach ($tournaments as $tournament) { foreach ($tournament->getOrganizers() as $organizer) $emails[] = $organizer->getEmail(); diff --git a/server_files/model.php b/server_files/model.php index 6db9f62..2b92812 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -123,7 +123,9 @@ function canValidate(Team $team, Tournament $tournament) $can_validate = $team->getValidationStatus() == ValidationStatus::NOT_READY; $can_validate &= $team->getEncadrants()[0] != NULL; $can_validate &= $team->getParticipants()[3] != NULL; - for ($i = 1; $i <= 2; ++$i) { + + // Le TFJM² 2020 se déroulant en ligne, les papiers ne sont plus nécessaires +/* for ($i = 1; $i <= 2; ++$i) { if ($team->getEncadrants()[$i - 1] === NULL) continue; @@ -131,9 +133,11 @@ function canValidate(Team $team, Tournament $tournament) $req->execute([$team->getEncadrants()[$i - 1], $tournament->getId(), "PHOTO_CONSENT"]); $d = $req->fetch(); $can_validate &= $d["version"] > 0; - } + }*/ - for ($i = 1; $i <= 6; ++$i) { + + // Le TFJM² 2020 se déroulant en ligne, les papiers ne sont plus nécessaires +/* for ($i = 1; $i <= 6; ++$i) { if ($team->getParticipants()[$i] === NULL) continue; @@ -154,12 +158,13 @@ function canValidate(Team $team, Tournament $tournament) $d = $req->fetch(); $can_validate &= $d["version"] > 0; } - } + } */ - $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` = ? AND `type` = ?;"); + // La lettre de motivation n'est plus nécessaire, mais existe toujours +/* $req = $DB->prepare("SELECT COUNT(*) AS `version` FROM `documents` WHERE `team` = ? AND `tournament` = ? AND `type` = ?;"); $req->execute([$team->getId(), $tournament->getId(), "MOTIVATION_LETTER"]); $d = $req->fetch(); - $can_validate &= $d["version"] > 0; + $can_validate &= $d["version"] > 0;*/ return $can_validate; } diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index 08ce9a3..3cdc9b4 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -12,7 +12,7 @@
    - getValidationStatus() == ValidationStatus::NOT_READY) { ?> + getValidationStatus() != ValidationStatus::VALIDATED) { ?>
    getBirthDate() > strval($YEAR - 18) . substr($tournament->getStartDate(), 4)) { ?> - + - - + +
    diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index 2fa7df4..b9eb97e 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -119,6 +119,12 @@ require_once "header.php"; Les encadrants doivent également fournir une autorisation de droit à l'image. +
    +
    + En raison du changement de format du TFJM² 2020, il n'y a plus de document obligatoire à envoyer. Les autorisations + précédemment envoyées ont été détruites. Seules les lettres de motivation ont été conservées, mais leur envoi + n'est plus obligatoire. +
    getValidationStatus() == ValidationStatus::WAITING) { ?>
    diff --git a/server_files/views/profils.php b/server_files/views/profils.php index cc8f2e6..747604f 100644 --- a/server_files/views/profils.php +++ b/server_files/views/profils.php @@ -10,6 +10,10 @@ require_once "header.php"; Cette page recense tous les utilisateurs inscrits.
    + +
    diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 2d57350..7bd706a 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -4,13 +4,13 @@

    Tournoi de getName() ?>

    -
    +
    Organisateur= 2 ? 's' : '' ?> : @@ -35,9 +35,9 @@
    Lieu : getPlace() ?>
    -
    +
    Dates : Du getStartDate()) ?> au getEndDate()) ?>
    From a322ce4dfba5151d71169d53ac3c46db340f6c8e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 13 Apr 2020 03:57:34 +0200 Subject: [PATCH 117/120] Fix user deletion --- server_files/controllers/informations.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index e50ed98..b45e68a 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -5,6 +5,9 @@ if (!isset($_SESSION["role"])) $id = $_GET["id"]; $user = User::fromId($id); +if ($user == null) + require_once "server_files/404.php"; + $team = Team::fromId($user->getTeamId()); if ($_SESSION["role"] != Role::ADMIN) { @@ -70,9 +73,6 @@ if (isset($_POST["view_as"]) && $_SESSION["role"] == Role::ADMIN) { } if (isset($_POST["delete_account"]) && $team == null && $_SESSION["role"] == Role::ADMIN) { - /** @var Document $document */ - foreach ($user->getAllDocuments($team->getTournamentId()) as $document) - unlink($LOCAL_PATH . "/files/" . $document->getFileId()); $DB->prepare("DELETE FROM `documents` WHERE `user` = ?;")->execute([$user->getId()]); $DB->prepare("DELETE FROM `organizers` WHERE `organizer` = ?;")->execute([$user->getId()]); $DB->prepare("DELETE FROM `users` WHERE `id` = ?;")->execute([$user->getId()]); From 85f16ebd0715feddfe369ca25153ee17a166faa5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 27 Apr 2020 00:48:39 +0200 Subject: [PATCH 118/120] Add turbolinks and funny icons --- server_files/model.php | 2 +- server_files/views/header.php | 74 ++++++++++++++++++--------- server_files/views/mon_compte.php | 6 +-- server_files/views/paiement.php | 2 +- server_files/views/solutions.php | 4 +- server_files/views/solutions_orga.php | 2 +- server_files/views/syntheses_orga.php | 2 +- server_files/views/tournoi.php | 10 ++-- 8 files changed, 63 insertions(+), 39 deletions(-) diff --git a/server_files/model.php b/server_files/model.php index 2b92812..a292815 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -192,7 +192,7 @@ function printDocuments($documents) echo "$name de $first_name $surname"; } - echo " (version $version) : Télécharger
    \n"; + echo " (version $version) : Télécharger
    \n"; } echo "
    \n"; } diff --git a/server_files/views/header.php b/server_files/views/header.php index 099010e..b00d87e 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -10,103 +10,127 @@ - - + + + + + + + + + +
    -
    - Modèle de fiche sanitaire : Télécharger
    + Modèle de fiche sanitaire : Télécharger
    getBirthDate() > strval($YEAR - 18) . substr($tournament->getStartDate(), 4)) { ?> - Modèle d'autorisation parentale : Télécharger + Modèle d'autorisation parentale : Télécharger - Modèle vierge
    - Modèle d'autorisation de droit à l'image : Télécharger + Modèle d'autorisation de droit à l'image : Télécharger - Modèle vierge
    diff --git a/server_files/views/paiement.php b/server_files/views/paiement.php index 4764047..c25da0b 100644 --- a/server_files/views/paiement.php +++ b/server_files/views/paiement.php @@ -84,7 +84,7 @@ if ($payment->getValidationStatus() == ValidationStatus::NOT_READY) { ?> Montant : getAmount() ?> €
    Moyen de paiement : getMethod()) ?>
    getMethod() == PaymentMethod::SCHOLARSHIP) { ?> - Notification de bourse : Télécharger
    + Notification de bourse : Télécharger
    Informations sur le paiement : getTransactionInfos() ?>
    diff --git a/server_files/views/solutions.php b/server_files/views/solutions.php index 7d0e736..a567353 100644 --- a/server_files/views/solutions.php +++ b/server_files/views/solutions.php @@ -42,7 +42,7 @@ foreach ($solutions as $sol) { $file_id = $sol->getFileId(); $problem = $sol->getProblem(); $version = $sol->getVersion(); - echo "
    Problème $problem (Version $version) : Télécharger
    \n"; + echo "
    Problème $problem (Version $version) : Télécharger
    \n"; } if ($team->isSelectedForFinal()) { ?> @@ -55,7 +55,7 @@ if ($team->isSelectedForFinal()) { ?> $file_id = $sol->getFileId(); $problem = $sol->getProblem(); $version = $sol->getVersion(); - echo "
    Problème $problem (Version $version) : Télécharger
    \n"; + echo "
    Problème $problem (Version $version) : Télécharger
    \n"; } } diff --git a/server_files/views/solutions_orga.php b/server_files/views/solutions_orga.php index 50565e9..aa7595d 100644 --- a/server_files/views/solutions_orga.php +++ b/server_files/views/solutions_orga.php @@ -18,7 +18,7 @@ foreach ($tournaments as $tournament) { $team = Team::fromId($sol->getTeamId()); $team_name = $team->getName(); $team_trigram = $team->getTrigram(); - echo "
    Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
    "; + echo "
    Problème n°$problem de l'équipe $team_name ($team_trigram), version $version : Télécharger
    "; } echo "\n"; diff --git a/server_files/views/syntheses_orga.php b/server_files/views/syntheses_orga.php index 67220c0..477c143 100644 --- a/server_files/views/syntheses_orga.php +++ b/server_files/views/syntheses_orga.php @@ -20,7 +20,7 @@ foreach ($tournaments as $tournament) { $team_name = $team->getName(); $team_trigram = $team->getTrigram(); echo "
    Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") - . ", version $version : Télécharger
    "; + . ", version $version : Télécharger
    "; } echo "\n"; diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 7bd706a..7db87ce 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -5,11 +5,11 @@
    From a064cc18179c5120e00e2e9ee75a13e99cac8640 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 27 Apr 2020 14:25:40 +0200 Subject: [PATCH 119/120] Fix broken send mail link --- server_files/controllers/tournoi.php | 20 +++++++++--- server_files/controllers/tournois.php | 46 ++++++++++++++++----------- server_files/views/tournoi.php | 3 +- server_files/views/tournois.php | 3 +- 4 files changed, 47 insertions(+), 25 deletions(-) diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 3b5b451..0cc0155 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -122,24 +122,34 @@ class UpdateTournament } } -if ($_SESSION["role"] == Role::ENCADRANT || $_SESSION["role"] == Role::ADMIN) { +if ($_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) { $emails = []; - foreach ($tournament->getOrganizers() as $organizer) - $emails[] = $organizer->getEmail(); + $emails_validated = []; + foreach ($tournament->getOrganizers() as $organizer) { + $emails[] = $organizer->getEmail(); + $emails_validated[] = $organizer->getEmail(); + } foreach ($teams as $team) { foreach ($team->getEncadrants() as $encadrant_id) { $encadrant = User::fromId($encadrant_id); - if ($encadrant != null) - $emails[] = $encadrant->getEmail(); + if ($encadrant != null) { + $emails[] = $encadrant->getEmail(); + if ($team->getValidationStatus() == ValidationStatus::VALIDATED) + $emails_validated[] = $encadrant->getEmail(); + } } foreach ($team->getParticipants() as $participant_id) { $participant = User::fromId($participant_id); if ($participant != null) { $emails[] = $participant->getEmail(); + if ($team->getValidationStatus() == ValidationStatus::VALIDATED) + $emails_validated[] = $participant->getEmail(); if ($participant->getResponsibleEmail() != null) { $emails[] = $participant->getResponsibleEmail(); + if ($team->getValidationStatus() == ValidationStatus::VALIDATED) + $emails_validated[] = $participant->getResponsibleEmail(); } } } diff --git a/server_files/controllers/tournois.php b/server_files/controllers/tournois.php index 68430cf..7a304fc 100644 --- a/server_files/controllers/tournois.php +++ b/server_files/controllers/tournois.php @@ -3,29 +3,39 @@ $tournaments = Tournament::getAllTournaments(); $emails = []; +$emails_validated = []; if ($_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) { foreach ($tournaments as $tournament) { - foreach ($tournament->getOrganizers() as $organizer) - $emails[] = $organizer->getEmail(); + foreach ($tournament->getOrganizers() as $organizer) { + $emails[] = $organizer->getEmail(); + $emails_validated[] = $organizer->getEmail(); + } - foreach ($tournament->getAllTeams() as $team) { - foreach ($team->getEncadrants() as $encadrant_id) { - $encadrant = User::fromId($encadrant_id); - if ($encadrant != null) - $emails[] = $encadrant->getEmail(); - } + foreach ($tournament->getAllTeams() as $team) { + foreach ($team->getEncadrants() as $encadrant_id) { + $encadrant = User::fromId($encadrant_id); + if ($encadrant != null) { + $emails[] = $encadrant->getEmail(); + if ($team->getValidationStatus() == ValidationStatus::VALIDATED) + $emails_validated[] = $encadrant->getEmail(); + } + } - foreach ($team->getParticipants() as $participant_id) { - $participant = User::fromId($participant_id); - if ($participant != null) { - $emails[] = $participant->getEmail(); - if ($participant->getResponsibleEmail() != null) { - $emails[] = $participant->getResponsibleEmail(); - } - } - } - } + foreach ($team->getParticipants() as $participant_id) { + $participant = User::fromId($participant_id); + if ($participant != null) { + $emails[] = $participant->getEmail(); + if ($team->getValidationStatus() == ValidationStatus::VALIDATED) + $emails_validated[] = $participant->getEmail(); + if ($participant->getResponsibleEmail() != null) { + $emails[] = $participant->getResponsibleEmail(); + if ($team->getValidationStatus() == ValidationStatus::VALIDATED) + $emails_validated[] = $participant->getResponsibleEmail(); + } + } + } + } } } diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 7db87ce..52190a7 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -60,7 +60,8 @@ if ($tournament->isFinal()) organize($_SESSION["user_id"]))) { ?> diff --git a/server_files/views/tournois.php b/server_files/views/tournois.php index a90ecb9..5c7526d 100644 --- a/server_files/views/tournois.php +++ b/server_files/views/tournois.php @@ -6,7 +6,8 @@ From 132481fda08532b2168b64b3500927fe64a9dbe4 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Tue, 5 May 2020 01:06:57 +0200 Subject: [PATCH 120/120] First week fixes --- assets/Fiche synthèse.pdf | Bin 0 -> 71958 bytes assets/Fiche synthèse.tex | 194 +++++++++++++++++++ dispatcher.php | 2 + server_files/classes/Document.php | 17 +- server_files/classes/Tournament.php | 60 ++++-- server_files/config.php | 2 + server_files/controllers/ajouter_tournoi.php | 21 +- server_files/controllers/equipe.php | 38 +++- server_files/controllers/informations.php | 3 +- server_files/controllers/mon_equipe.php | 88 +++++++++ server_files/controllers/syntheses.php | 13 +- server_files/controllers/tournoi.php | 16 +- server_files/controllers/view_file.php | 13 +- server_files/model.php | 2 + server_files/utils.php | 2 +- server_files/views/ajouter_tournoi.php | 19 +- server_files/views/equipe.php | 4 + server_files/views/header.php | 4 +- server_files/views/mon_equipe.php | 35 ++++ server_files/views/syntheses.php | 28 ++- server_files/views/syntheses_orga.php | 3 +- server_files/views/tournoi.php | 36 +++- 22 files changed, 541 insertions(+), 59 deletions(-) create mode 100644 assets/Fiche synthèse.pdf create mode 100644 assets/Fiche synthèse.tex diff --git a/assets/Fiche synthèse.pdf b/assets/Fiche synthèse.pdf new file mode 100644 index 0000000000000000000000000000000000000000..af8ed1c09bcb31004a2cc47160405bbcd5031e1b GIT binary patch literal 71958 zcmb5WV~{36w=Vj&ZBE;^ZQI7QZQHgr?e1yYwr$(Cb?4jn?jPsw6LI3?kBrP!wUkj+ z&x*Cdl*_?opgPon=zZx{Xn1!{o zi6a5Mn6-hkiHM1jov{ftA0M=nv!jWD4Yd1uRhDktx)^Hc&5QbLHGvEH1Mh*J8fg^~ zt8D$IiYztfZc(bn=z6^G=X=hb_aGt`@^)8v^x7Wh$O8_-p7~^j8(NKT=N?Av4!vCt zk7{RPCg+Vvlee~HMY>|SqY#t6`h?5VhV|Ry+RVdF+Dr})T65wbO=?+8E8K-?HP(Zs zIARkVv0RKyN*fbQS8XrTrgGa9gQgXS!w3D;sJE&_*XIFu=Y|gbTzWsPO5<@$V*k%8EAihOK;r13UDItT1drj3H{prBF^{liEA>|o)9$vw# zatswZCQT;&MVel7H`~_7s9&sUj@8+JnqE%o5mV=jf6bCCFV4bJv?JQZEohXWs>tlw zbm-zs6eu;k$l~i;cV{Fmu!v2qhY4exT*< z{dn*=2xBuX6)8^|E_+UTdYVvLxzSk}@E)M15HZV(6IfY*9=wxWxisL;>-?4Z;6Dz1 zSfk6SSmVO&k#@_@mJ^vOf+iGSwwhilc}dADr9*f-@+rT_k63U4wmv7?H!cBIaTo5-$`rXug7etS6ReR%l0L#I=@gm!jD~+;*DQdC^pG)NstC>%I z0Jfmy*L+DkHRDdHI93wP(CY)=H&DDh{F$pF4?|f67@iZd+`Kc%*5-gMMD81ap0Y@J z8gam=nO?GEP~{hs5I@+G9K|>hT8`wE8_c|>@It;j+TWb-r(85TO?J+bcG`ba092E^^P+9_nD}h52dx2r1P|9)0(D-O#RS?uc z5=Dt(O49gK7$S+G!!VF3EuJ8y4b8vg9kP<33mVr!5=Vd`iqiCt8UhWAKtre-DlTAz z1#}XHU!ob1)Bpskh|~y97y^!tKz;HU6s>D# zlQEAA4?&cq84Nc>55#X+KI8uZ_&l(8N+ zjCJb_C3(4Zi2wiWqTA~OsGthYV6e{n(IK~69wO&!_1D8xrI>4`h(Xmdndy&?#479m zEXB<`su>ic-8&MiDUNBqQ4m_a0}UM=$yNSE#@OT+lBk!YPV3r?SaKHUAdQ#1Y=p0| z9YTkk<)m?mU~tSQjMm`<6ea`rkJ={0UJp(zU9AEGwTFq)^^ZCtiKW6YMCt@591-bm zMWj_|*Mk8&BS!s~Aesi_H)2MRroZb|^1p+giyy>@WI7I5@Fx`AzOZ=y-6P|D=q`SQjWWtDT6n8tb*3wF_NlL0DR0ecj|(lXYXBYeCzCjwziru&S>ts3T;_vU6(9V zQa9X^(JaWO z2HB091<@yq$-lDNW9n10@E$u}tE+f;d6@DD8%#vqr_Fmz&o+L3JZKlyXYZ-mTNAYX zexHwbYS%+yZ7B_=PUge0AFa6`d$ZQS9kC%Y@ky*U5b0}vskW#TW+@hw&*zxth@AMKG?$;sq%VtqM?9C2gOc_+( zysilwvyy|=pSk)}56qF`@=sgSV7pBJb&-*HsIz=*wCv33%975`0WcWS+?`qMM6-wS z|L_DOhFWM*c7Lvg4DD3Z5)`-by|93ybyxHRzWS8TF%yVNb5t$p!?$yH9`_$ZuudO~ zxq-K&B{U!Y5Y=WHm~R)IWXj>AYtz_$gGl{2NkE&}8vlRz`fv0fY-Z&6pCHZ2$ngJS zG{OHFq_5Itow67ZLvOy(+Ry(j= z5W3$$Q(a%Smd*`^rDu7GP8Y&iX5tp+-co*tLr;bnnsbRO8JKX)%k(D-Ec|MRqKoRU zj&$VN(*ke4pE0hZ8I}QW3BId4H28f`By(Shvm;wGQzK+tt0>c!j<_vQ3025p%y*bp zRC%c%E+UFZo|F-C%0ls=dbXmZ-JG>n=moOpf?jJ~@!)-=??aR?FJk`uN8+kEwoztd zcb758UtCW`@mPm?12c_nirMb*kc}Xhxu+o-x+e#tq5pklt)oh!j@K%2V)Iv?q&9o; zs>Bh@&1lmYkT)kPUK=?Ao_cd-BG<21v=hXx(Pmw%Hn=ns=bJPR)Tn*1p>#B zj^MN~(-PZ*P?ICWABUyWJk3l^JEc`o6#>51YRfH|Shy!v#Y?!JCeEO(Q%5dO9K}{s zP(_gp|7Gf;W}S2vl!j&?{dyQWaJax45oxdB*hODqi^v_} zR7IVdc7Apkt3gc%ahbhQC12G>()*RpR_J9m82akar$X9lO>{^m%o;CH35G$ZCD`$y zma!?IRi!D4+z8e1XqL1tiA^PYC@J0jP5yfFUms zQUdLPK|}$l)|Efc;Fgdk2r6N>wt4W$H^5S@@+DkAF2;Gm#=Cr=3PKDt67+dRcWMRf ziZ1Prhz0I3k!RA2h~qh>@OxV#xD-30sBSxQPDJOUA`S$RznB4vIJT9?UPz=~C}4gh zwXhI`k!>~I*Rubs3P=GY3VA`SG-{IlrZr?ix_xn%Fs;O?#iVn*y6y9Pv@+33L`l(R z`e|#vOhVh8%<<$#f(-YJ$6Uv}XT@pTrK`w7`=W9qPe^#hvc#fj@$5^kWTwgnVU|Ne zmEq-hB{|Q<+3%0w;cpOh;?BGO`F1n?&k~%GfRUAr^S=vnCIU`2PPYG^F%vNS_mF^* zf&HKMf7<`~BM{RFrtoJ2nHCll@){J9t+k^=cy<@j+dlx7t<}n&T*4mix*F=bFMGGz zfIz_B{cx4{<=bz`OLXbB>UycG!>eYS1+^TD2Kg9KIi6;4IwK?~MHi8vn5Jx^5B|5= ziJ^(viAa9_94PmO|95lYta%Vlb}u4#pC4lpj-bGaSr*IeTSh5t9SBA1DuAOEfYTX> z;~jW;36OJj4d{tL6c_YonMJdPS1<*m5V#bOqhL`&^gg-)XxB>w);Mldl zMyJm>2ZyF{4k6w7aPtUjK;5kn>OYbyAISrL-LBXJa4Kh@a15|s5rhj{ajMa~F~kr^FWT@%W{2x2fdO9{Xzt^)L zl25-+0qxqD5&dYhqjnB{y8xy`4~)z2v~rMlCl^vew&S0RBsXxro50}g;wgS3Q0}q7 zEy3gR-)0Rje&a{-9m_YO4L}=1CZ=DX-W9y;emMAPe5w@ISM|z z74?7sS(A1P_!9mIz2Kh^4m=#h!YwY@&mIXlrqySvcY8J~7KZT32kl9Ist`ilvDOowzMKR68R}Uy7A!=Cl;S zfkc^E+WuxV1Sf}2(-cWWbCg`CGpF_Zb*LZ79Yy0~%74WXcS3VNt8yCNob;?twsPch zK~_XLLrUy!9sHG1^pv>yQzXD}qpE}1M8=dmgn`HX%3I3rtEQM0KChlK%UBvLO0uP2 z29nm!yfHPh$Ls-jFWMhE}b6Jg2e zyEpw;cZtq&KQ(#!A5*7KfMiS*fdC3abs zgKUu2>3Z8wSqE}rmbGoWc+t5&O$U`Em(tSJN$5J)e?d`e2Ngxn9o>8Kk8{~lAIcZT zn;a7fF)dG34)WyQ7!+9%WnAzfxXwsyq}n|MW|be6eVpFs6xnoNrNjtpp6O)6-F*^O zhh9nt^}X8Hfg~jZ#@vy|EZcoihTiV7EA|cX-qhm*V3f+|%QA(dYh61#2X$^Q2C#v4 z)6#}3oEyXH=VgH%Rn~35*!QcKk%XtGDw#;Ob4+kOJ$9Y*X;QEnTOtpwKU+kSOC*vs zNbN|vADU(&B9u~1e5Oh4`My~W$p$&vP)rAc)&r=hqv*;Sd?t`81;y@GA<|~XR_$e? zIhZYlaE9nhu~)Ee7sM(qpC*n8-a26zeOj1WSF(srM;kr8$V5ewNY}0^mdxdj?F8yW z#+++1e`UMA%$1MMM`TJ6d|ZEoyTg6Tbi%HxR!R zd^RDo_^$LKdZDwrd@1J%T{rlR5U0kf~br~(NqQ-P7amsTT^7X$4y9d(C)b!b=lI@ z{jyV&_a#A*E!bzWDz!1PM{hpbN?Djk+fYUPmA;5oE(#6?eQji2-RS(Vj<{Br1s%MK z<;%%y#Ao=Sr}O(ZHuI&4PuV|J22|D0DcSLQ!^rdTPD}0V1FpDyN=Yb4dKm7`N}jI0 zKxjRJWV=64dHT>~FdQBWl-*kTxd;+FPbtO!3I~0G=*~jYv6@4Xr+}E6g*wSyvOcJBYXvzg-T= zQGqGmcsoM$m1;U}(Z~)$NJZgrVv$k7dHP23G;L)%GCv+di{I5N_{Rl>7e&&1cGt%_ z?^0AfD~8YA4IlPLRI*b5h4Aq`z6oYR29O$VM`(vnb*1j~HLb)e>FBJxRYtWNn}=!$ z-*J8=4FT9&td43j#kul z5Oa?+J)TkD?q0jPIBrIBt8)|*MySm4AOdi@a{fB4Tt-f|8Y>HsiX0NxyM(( zDI4k6?41~sJX{&O>@mG%azT{G9y5Oo$BRoMb}ucq-03mwy2f-T=C>uT-D|7?{ISxF1{7x1j^t;k66TXSJ^%N4Oe?dKq}4JI#jfM z(RO{X-qqpeUfQYA&_G}6&#CZ@;D%H4zOd;2xw78f>LU&8y2&=;0=EtFPM7M4atdfv zj-5OXnm}Bd&OoDy863&B_KJWK7B$jx9nb>1=XfMHRrkn@%xdm9o6HukwBBZ-@~LY3)2ppEPngBmRnQEm}| zHBlW)C=?nC=S#dKD}E`+2BT6sw0LL0rGyo=!Js#|TOY@C2~Wy|h|XLD(IF$Rk$yP3 z)*e(OW5-G7)6xQ)rHBXcVWC5i6fqHp8J!vw&;&3QG(YGM*S;b3@E{3FAo^||$c8(U&NeHpJ;+x6#zs>daLBQYNl z)Ri}Rjvpo1Of&93vq9Db@#p3Rg!eOGKDpIfSHV9lcxBIi?pB zI!=rh^q^thGMLqW$v&W8Y8W$BxUR>cdF85U`6-^*9a*&!pnw&I5{9xa`vb&q1zmn+ zP$_$m?At8eI6O1UmOql32yduoq?nspH%TycUmh$=2Y&W2D5)oH2yU{sq5^58ZJn$y zUcGy~>nbAjQKD-JiEPFt%r$9>Sca?7p4_zvy5JKd(ryTi(I%}BR7{+rvJ`36+;R1E zBG6MnFJ6}=m=_Xywg^a>yW&X5jE? z+kiO%Y2)Po6)%_GBwN4Qj+k%}4PHY6X2lsoWNudOkK?4`2AqKMD)Sf`3FX-+#+iQw77BoS1=hug{=Xyh|I$$xt|tzJAd{u=D1xr(fq7 zhUq>8^|-*_p*}~^3v*{yyujONgSTF#3cD93LbJb_u;l5g>72=Pgf0bewh+|SZZ6o{ zi=dU8VNlWg3v!0i6uTF-4qoY=3*E9H;)muyuo3k+F1&l#>VM}A2B}EPu9}M&{~FGd z`nGCx%9F6;B~)H3DMx*+HR5wMMkaZq!yUTmg>fdD!SBGMP-q|*nz-6RUeifNA$8OJ z0w3%tlK*+b>WF$;V5F39tmevu+L*suF|0`gCQJFeculWM$m-fLaVWA#;fr?1p5d#9 zPdORv07h70bxjO;Z8R6F4AHZu%$JnP{KKJr@lIOJXxb42?I6c}+dbJV!nPVYHbKQv?Vi1XF%&?OL-#v+iZO z+P3hQAq#0`8w!nt6NW<)+4_u0QKHV;?Vy%o0=TCi#<Tg=0FZS~+jh9lOZNiRF_jMMtbgOeVVz*_Ckaz|$y3YvUKp52Ee6EqXCOeTFgd zs=5`#LJM#&zo<@!=g>Lvc25&3Z{f)j8pkBYA@N-n7K4@B_W@9~1LHDm@)xRQZ~GF? zth0#58b0BrDQW5J0-frwFf>jrOg68SUR$h5l6lemNcw50j?>z)z*@!N=Z`S+Fn9JX zKHG7N*Hvo`m{!h=x$Ml8_19#87N-&yiJ*wmV zSUWJ+YV$Rrze@7)=$sD*le>vNn4ioo&pas0U=hJ}R@HfF(t`EuhohYF*9+YOm5G&C zKAfa7aRyU2-uxjZsd-s(+3ova*XC zW@1M6oCT9NOd66VH>oHO1`G8Tzfq1nA+_!**E1{(>W%RJB8#UKo2x`? zHDg<|y6uP-;Z@1>Gk2Ys!3`B+Qk7$TybfLk^)9kAIVWTRv!-EXOrX8Hh>)#p=zXp6 z_w>leNfq$rFtilGbA^C8##y=cni=YZb9zfA=)G>vx!pscckL@Ml`Z3h$XEM(p)xc(iqaFay%QJ%}I6Y zEM*P8uTb+}&(z0_5X$jIwcr$$X}NMR3-iyC z^g-X2MQ1B{y$}C#aTD#0Sf_fTD6@vr@d(CWazP5gA?^eCKfs0`9BRG5&Q}^1Ix#o_ z>oZl*v@ZEM{40vcT(q^sW)n6`M;T(4cq0-X#dI)n*p|BhEv-EabP287b{04_#W!X9 zHAd11FGC%~Ot-|c_%B4Hvy-H5H-lxrpl1X;#c9Zhd`@WQMRAzA+4d+OQ&XgsPidQG zsH9L3WHVfJap!L!PtK6x2a)Pcuao3EIn4!6JRhj60c5QrgwORKAyhjq-pEVr^%^dJ zO_{4=n3QCv;56Q8!0(5>eu)x4kY>KijpxQ;B~(WG6t6XId&B43HaH@Pz?`*cE?%tf zB~i6q!NjpOD|f>G0lz2oy%+e9eG^?@r9- z9P*SG`$gE_l(nZQWQ_tDgYxS-z8#ZxiW)eMF0fWfH{00cYRD45EO8F|e$Fl<759S_ zy>T)K9L8z(!NmZidE4lx*mH~L6Pj_`ee_jwCiKtULAl@b*Pkm3;Io>{W+OCg==Zas zNqL2*j$dbM^qQeG`L*gB0MAKGU`OPxJ~<@N|P2DOEybF5)UQnB`qAgii>lHKVr42I$Ps1kBJL}~|n@254f zI=1`sDXxT|jmtAX{_RlwI!B{yb)FgC?B37orzq3C+I81;Ddva^K-P@#%Xq@BB|wuj zmM(Ih>$9gcg5UG3S+uS4zn8wGxBPSK5c7)0sdUYQNxO!e-!-)JHjcmwFz^4(<5STm z(y$GIt3Cv5T+mkx?WVisOU240G#LWP(1HP*qkLMX+^m zvQiImwp_k%X8PG`3yBvujO|P{WGw^iqt*E4*uMqSz}JXF6r3y6e|AiJsBz2NWR>-W z9OVolL-M(ghi8c;PB*YRJLsT0GeWZwBue-47G+;cB0!K85Kf%05>vg} zHkH;}gk-~y>lBwliU&5?+CJuUaYX!FIA*01v)ufGMIA}IF$X*K3i)mP{m@ceGmwO3 zohi%yM=qiQzw37#=uy|XtT_l!oZDQ1!P{M8|a4893#MxS?6>3QdN{O*8O?hz6xU z1=Vv*)f_xj?#5GJZ#Z_EAZJN41&C?4CB*}K;Clnc{-LQzn;OP6gWtdv-(!J^;yOgg zoOUmhi$FJs%khWm9n(04&l?&{N6;rXPLo(AslyV(p>Uj+eMl)`G>!x94J$b=A2N>H zcM@&r!*{WvOpf?z%l`1vzZg>;M4Lw&LgB_;b8{0Dbj~V@t=7)zyQwo$4L)#1rnBsX zFqWu;QxE5d2K}LV*E7?xi3|`ss6fpq^A9==5P_lFGMN_`GxE2Q&F$@m+6b z;*ssVqNNm?@llrJVodQdsC@x&kbP$sczT0OU}>cnCz|@&&oLOH{Cj&4a>yjWNP*lG z(zp!K|DH#=ij5U?h=gA)*I(gyakw?H7&D#JU|?CbjYul{Bs;Da9)_^AJ&e3yLu619adZ>Q zL_jIccubRXEs8{#oiM(Cpy~Ry9SEyLTduT#%A!98OiTJBoFIWnNN-~AtHoy;J^ zRUO*63`A-BTM}fX=&iS|dGu(KSE}7G$zCbyh&ct=P>=m!0ZR1f`4=La8`SGciHSg@ zQeJM?g*bAr;;C}|RJvXjAD;Fjx91Yc}vj%~}@>VhwpXg#@J|RxibuONBuixs5 zann)WH!Nz@8J^mb=jhn}AbMq=tlE!AcVx281wYH}-(WEo2j8N=6&G9Stg7$o`HE#t zsdubk+&%i?&?!urs3gxjhPO-yNWyLwV2z+`G}xAjiJB>h@qIXuixWTI3okBl_{KFZf*9+v7GDd zMjyoN&<+CBPLn ze0b6}3PafI$5o|BfIqDl&rhO6DVj`P?Yng^<)=AC1uViqsZ~2oaGFUgdimdG9~hVh z&s^pdOYK5KrjRg0`2DScD!5U%fs=xhTK1L{>*#-YF~!;J5ItJcb?KN3nXQd}u1>Jf zRQgO8)|T^n!8M7hk1G3Vj6A<-1O-vt5NvoY_b=nz!f&aOQtO#xye7`@r)73Z&(wEi zljE}$7ll66=M^apPTOo|7#QwCQm5TSmUh#O`9Lo&VfyfOo*C;BOf*%DJz!w`-k$`< zA>o_1Jl||`x!`I>q#NWd=o$j&{D}~wK(b91ms|eeLqd-dV9hr6Ff*GM5W}@>_K#&% zy`qVIFBt~L6|e@a{-DXaN6e-l-Iqo#!1+i77P?HmJDbi#taH-nvWPU3@%KURWrTDRPse!peVoz7)%nUk`EO5n@0&2l$x!hE9m82Xb-5<%Y&a zCU-|1h{?cq)>E;pkDG*tTaRvi8RXfjNMVty!MNl`AJvQ5-s#h2eqh|_tJWsd=MAye@;4x=z6;)Kpq3@_hTG^s3WMn=Clm&+U%mn{7Gaba5lGFm zg9mUt^&;lAa5yEy1s8aGVjN<$@d%?;7=>-#I)I_zIBN~K4bel8*&;4w*WV=)ND#F+%0*I)?xaHR`y)tGc@k;;$D*RYXOEZ5QyK2 z+um>zl1;Qw`R$dX{LHLsia0^Ae_(Q8x*OKOyz9Ay)C@Y8>Nqt3j#`BGVoUBA|Sq zl~o!~jczrN@H8VYM@r$xmvA5|rei`;IiM0G|0=p}gV&Sr=s8YMK z*9De5IoweN4q}tHs?tJ!Xo+QnkXQKQ+8CpkXfGI|6ugyaFQqCjihhl`=555hPlc?) z8PgHS;+5*@RFCredL~s&_de;q2#ECCG}LH*!e?)=#=5RLha6oOymbIA<56i>TrH~W z;BI_l&w%1Q=-bVQ5klnQ71SNtk#QL$ zFO10eJz^@S4%CS&!F|;wcQx+H*YwGobLcv!qt=WMb9`Z_Wv{*#!GhfO^BRTLx$)En z{O(G3O_~8o zzJxbtjq$z=Xs4Id#1;?R4!N~&O&a*-Xu#gEhOufkw{L#=9#r|vojBq(;9gvS$VIh3 zacEZ3d>mRJS@QRoGbl=s&Z3n&X(WDO_FoBY0xYlYu=Nf}qE1x4G{T-}={AD9Q$p{}h1 zUn*R(3QmR%U7a#|saU)(R_%5?;69FCv_R-0N15JOxt05M6WYUAZ0)Q>UNpJ`&MGYU zNS#z2Eh$#*0j)4hbY4YYV-et9tb9E@vOAfN>mm{rk({i-ZA0tXnJ#+62h#z>t$y93 zFbaU*eDTY(PXKWv5jJCLZc)v$S{x1sUe3WDGJ$Fc+Ima%piC^NZB6$#!9}+}862)D zPV>P~!mTL0r|%30e^)5G6?ffp%BoV@myLpH*2=sqW|qK_pR420z5d4O`me0fAL{6f zrIpKGVcIxh)sdVX4o;lD7JIVwDt;`~nj4+?&YxJy3&de@HB0o)?t3CT7w|VN_O6*k z-?|FWGzdUmvS0|Z+ULGApi+J3Wz){Eu8?Bxq1F7wEa{Ngv`}3~M5?2Ic6q=ZK=dB< zVTmfOW(u5bZbWJ%U*No+k`L*te_Ix}7%Xak`Am32FRa8B{|cqY+fSUo^zCO+pa9MCghZA}d_pynV)=sT&|k4mcguH_tG0Z-hJ2T3*`1o*ao?b$-7= zWvM#HoIdNyydd7&7?^uu@U1{WAVBS%#S_%EG#~F?q&>Ae|At>cYdBVts;%`(r`}Z13!B(^Vp3R6EvHMO~S7t90?&eL&jq8khthRLKvvaX*ZI zGJBpOb5g#@6g(1>XcpV_CgA+dLZO#Yn2@l=Xpn30S3cf#Uh3Iv=h(tV+X;ktFi>@w z^ywsTtqGppD5sz2RIf&2T=Zw?3-6?yS<7-6V}3*yYqd3r2wd0_{-ff|*#`9^5JJ zrf(_^%eU6)8{$+jeU|(HRN>G3RSw+RnwiU7yLAbpmm`CpgAy&ayFA4Tk7?YbzPi@- zM-oyRbCb_Jx4$M!+D1oFlEfk2x_jhT#NCi0sd-q0IJ491x;B5$>!s5tL+8i}2PUi# zsT;5??JwFJP3AOZezoM5nIi3byB62;_|$KbUHOFkIYnV|KGQ|K7>KI+w*fi}65j40!3s4g#Jg$%yGbC0M; zGTzod6jCs2FI9}(_?gy~KxjhNK-z1^$KB&~h2PGehn&yPbq+rMz? zx;Z%Li=*XZux|Q6gEj&m=Olv+Dpl}F;{HPETQefULQ7ETF;_1RZ*HZZBYV@mrqYM& z$QsmCwSym+xr6!m=cI-zF^jqNYU}OXM@@c_@LOHKbyL^~O-73k157XR2IcB};wqak z20z{{FH>}2Z@%*`aXLzaqRgCi;9ySXJEXwbEGo1#wF=$pwHWUS)A0A@#O)- zR7b#TL3fa;$ICh`8vUH6F|UL=N(6LUu++?W!XLo9^v9a~vUr3z;>yC!{Y^uO_MQZ{ z?<0AHg9#ew5_pu5;F9{!zmc{hT3--dToOL4>=bQ*7<%YJb9Bqp=OM3{P_ zNp5+o5}=M8F_29!=)vmh0eG|)JwY2=1sBl8wr_u3XIfbiuh_-Afk`zVYWCbcxYTB2 zJ&3QrMqEeb{@)zf>vg#%8ui&IRO>iVyc!W+;A=QVM)`jr{ zf2v+jMdqNUzxtMGJnTpLgd1@^_K8H&-;MDm+bcSJ9hwHZKdu_YcoFH*@0_Ef)p=fU z_@;`wg3?H1Zdld~@|@da2Eq)XP6&R0BPv_^FwiWw;;vsTXH|`mnJ^ z2&>k%e8l}UkoU8XrK4p!FISiTj85Cf9my>yr2Px7t3RJn62^7kSc!$?nk*d7jN?LK zu$-DH6eU}s5WX@qtVd~=`3-HX8a(yw2aq?rdGWs?m;O)c_&;(fJ0tUdb4dS@OIcYs z{(JVnl1tf`|1Zd;DyZk^Y%*@_z)VGtv!vPcTSov8SXgET7U48tWFi7WB_doYHwm{i z7HEojS_1qWr)$oW?H~P%kL5~M=9$=&Ew7##-?emSIQOHgz2@I&9Fs}v{&D)qd8Ng_ zsR$rko%$lU8AMM5%+K5YL5z3)U=3>*NQ>nZsA zBMJzpC<(|U=He5K&d}fG3UCM^=Yigbu7Wha0?zF*S3%-rk*<%!{5iNhwsRkHdjRm< za{m6o!I(4nX8;d%24F*oK%ho}9J${sA1GG>3jRQw@W9WHAN0`hl;raA?2-htBO_r5 zhv$6|;vD1l_W*B#965kbEd=HsTr_e;kUEo>}lK;m75V&O~0GFNNa_09GKZrZP4-SH$m;9D}OMk5=f}oZ^QP9=Z zUY#9r5&_r=ltUozw|{ITS#C)UIRXH*;RhEo(6jgEL2#P@64lrX|5p5rz(2AR58%AB zr~l=#N=RUvgXfKhczS~u&|`5uQVH9j9^BC$Xpn>F-gBWGNYLy0;`DF-#ifmop%nr4 z4gU}ju*UsqJFqJ_k*{2kfGzV~J11nLDW^7{5RBti=K?FLv~nTC4(00{H5 z-{Q*!>>PjK0Vmknv-=PDVDAcqgS>u2Ae;f+gM;uO>Fo*}{)b$83knK&M&y?Fr(Hz? z9{33R+J<#~McLWm2i}LN-R()s1^EBGoZR@Sy+AjF4dnU$1phb;2^a~>g1HD^_h@}@ zl;r_lzz94R!T6r@-5+vwxMKi>#HZ%<*Pn0Y`WJny z-B&9?4xpc@Vz?f4I?Ud?xLMja(buc%9?#sypDVW2ic7)2WyeVD{>;Hl%=TL} z>ugm1!ZM|i*8|6)s~6VaKWliPtiP<|7JEwDbPwR)4~C9EwhFvcXa1fr2@S-lnBXIaXIHSp8EiODqVenhh1)XVyYS>aN9$Wxq?w56*jsMX4$b8LX!?> zCoe$0d}Lci1@9JwtKTpmbu1r(Cbt8#zQ5ynTyM53`!t#;*&*mR@zUjaaR$pR_LBddpLE)gY1K9p`<2_Zj3q9ar z1%IPM$$l>1PMFmK_C4rR%T>ni=|V8>af?>Q~Sqzi#Jt z)o+4PRoq;C2syiayb0IiDLT24rr}S%&-{mUiQ52E7;A-*CJ@|16@9FOR};F~xPHJy ztJL5&JkBshlwh`F@w8JM0V{_y2VL)!Ng{Sx234MK~}6IL%teQH~!n;`bitQ zgXkG%x~Sxt06~Sy=%K2wILprMt7Hcke#)uN5KE9sCSlcbFT$}_1|%pPgiVI42L928 zN??qAs!WEb)5)|`NoRo8HA|sBUy7S}mODFZWrRLojGabxmiYrEx;>`67M{7C&D=?& zD=TCIvVq*h1fH;s1P@nKQ-SjZz0~c-{ud7HXXLWkhRuqEI3I7yt)YF?4e!d|>>@#%?-65OHx!i~r2Kf9UJAyJ9GWMc-G>KugD}y)7%f3Zb_<7Shi6x^;qm*S?EJx8$!Z2t=HG2Cq6QTQApFi> z95s+JL|I}IPYj&tWtz=4Yuj-XdknG6Of|R?N`3PY;?bG;;c0vulFf&@E)Zgi7>AoB z@CSYTkF+K>hMU^g>c~EG0$m8#G{*k4Ff}z0`K%i&5-(LXC;sNI$){r{G z9C|7kWz0L1e(C1juR5hA2DIv{eu6M-!82035nXorkidYr@S}?fQT#~v&Z7@hE!TX8#IIe zQ0~R|sxYEdNWJC1dw5%D^F|zfHl|q6fypYL4`fD8W`R+t4?Hqt7ya^~t%2>@@L%fim!K}^jn86VVmNGusJxM z5qUPX00Sa>OSP)BYJ&h(*uZl#JoNlzx~p5&Q-q^TFA15ZCn_SOaJLD57MO#4Nj6isQJV&Yh%{2~RuvatgWpvqQZNg0CYfs3Lqc zWJMDJo&DFIUqXSr$JjW7OOS2;AL3||xJ%cE6^Kk7AL9KX8+cmawNeAyrEW(TPgP)7 z4&TLj#Cn^(98LZ3fi%{N(Hl{_WVgQC!j!JV3p2boC>?w~Q`v;RZ{)|%P+>!IGfF7@!(`4Aua-AxCsnOBWbS!A zGnOh#u$r@!_KBQhIe{bDa#zQwCcLKtnks(YrPDTNk?i9VHF93GQp~GILehBr7g$t% z(Z#X=_i~msi#booRR`oJ!EuxgNy!=&cL-B>l#2oi^nd3CI1YijkIr;`@8!)+_-N7f zqH5u(zm5Z3pQ_E6!%6A>AI9z>xDqCA7kDz!OgOP^+sVZC#I|i?V&lZNZQHi36I&<# z-p##Lx4zBY_M)qI|E}ua^YmJ16759fzHK%6QGCR`v@hhn*_X@#+9sf;ObY+O^)NtW4eq@pNw*;smcb2 z2bsn9h?yq-iyE`6oSO7e85rtreBW+iof+et%!6gcijSleZsVGEObfNo<7dqFJ&tKA5&^2 z&RV&%U9n!8Qx>u+IP8}909_i;p(&U4X-qDlSPh~4-%#SKNOxOGI$iK!xmEsCOmX;F zBU;Kdl)ZG6WMe&!{Ddt{3?nqu$|Ji_-N>U;HB8AW-@)ap5z&C2_lkaPs`70$|33moO#Dwhrur;905IED zSa6*?3YVhMqEj3%fugYHY_6i0e*WF&fvR&ns;_g7U!KEi+7kf=U+CaCaxR7)EbQ4O zM#+fW9syK?j-2&*uoflQ+cbX@k`I?8U2-7U;efHq?0br z5E{=?zWa4802aj;*~)`h!+bM`?|Hfsha95cHH#(pXm z&_w2TCM?Nb*Y`Ww?Okca$nHl~Q1Px7G`%5<`LhzDy%~h~nDiK6!Zb53CDzcW7!c;Q z5l^72JUu((K*n+HYEii_t^HYU5W;*l32Pg-JPx`rKG@^n2)Pw2#T?DmJUj7NQ7~y} z&EeGm>Oi8zY{U>;D6zCo;RnSP&UDlMJ`C;bW~r8-%uk? z0WE`=&C@K<*2XI{*WrAB@IIl3*TA_##|Qxp_>dFvO{+KahYgF2{AXW+L%U;`s>*$=02OAEytWG$3JJ^ z{2K|_ORK)}F_tmkWw>Mb)_*KGm^~hBMMn7PWb->FKte6N%6L(o?nyE!q~;TG$OVP; z(6#;cC`ZCb4c3*z=286%h7Vd~~7Ue(&ef5Wk zcBxQg>GX#mygf#R=B@lmaIF=zJz>TKw)7yxhS!EzSPERj{|hK&o$)o6Xem~WruJq zmq;CAg#nda7gDy0TebrY*;UF*W8Uw&8s5#-;ye}H%Ij1h5dMqf{P@YRvJdI(%AgmA z=))pqN2~uHQc&ij5T)Vxu0jfmFSt{6&%;@jMraN^NQ=(335}fwqcMxRwQj&2k4Zvm znb_nWQA7UWnm7`s-om#(HOsa~^YPpgkq09uU~v=LsE!w`S{*j21K^6^%oQg~y>(cy z_OI5s3tYZ9u_Y{mUk{lX`|CH>gYAaXcDqM`I}I26x^As}k?`8Gx<~4|f(U^$);NX~ z__l9hgmqV$Pz}@&3x6I-C?e`KAWz{}pmq3iR_ax30m$?&E^D z%We9xkrU_)n~`kK9Lw@L^E?BPpV@9oU+|9MOAW*)P9BRGtLVIg3)E4^^kKL-i#Ku6 zT~law%*6#{v2Hg-^4>jcdeSgr*%!&Y6J`p8piCk`i%Bw5Qc^1nio<9RbcLn9RPe2VW z73_>iIfz#R(GC8>NQ7bL0goByeKI$qnq*48=WK#ie+gkH=QgkH*HqepcRJ-4www?} z3Tl{9j-i(}&qZLt>t{T$H1yiWr+1+YpuVqKYD_YO`sO59G+2{!pkz?~X#gYtz2!Og zK~eCAt4!YE@L>BadZ76L2ea+t@u?@-xq{aEM4H1^;H!kYXO3F5_%YVk560w0a`;~N z;MOd(cT~&&Wc~$0B~W5!b=5aoG0!e{j8dxz`e0>GxV}%JdP|hA%Blx^Z9t!AO!_^} ztk`!Zz5}qVlu*6T2%Y3{Vqs#e(+Ve*zm|?iWq%I-T`h(^i2nsxGx%1iJJ@bF^c{^x zja?sEf16S<$&}ytrR&WCUnIx!U7toT59VyVf-7S%KCkV@E2`0?MfW)VDpR3bqEFep zQQDe48`)aK9cVRtiXH6w^#M&=QR=#%mJNhI%JNPQ69H*?m2SS zOzsofbPRZ?Wj7m4AX-7zfW+P^;FHC%j@ivblMi&UQ#TTp#9rMsambhfE^6C1Xlc@3 zWzD7{OaD>C7Q*TAhwM%lqGFf#PQ6J#Q>YD~ZNvK6YOr|qpjH}F+W==As}ngD)sQh( zYEwkF4SZvd`OhU}riL45!@ylj?M6(ma;Pj_F^Aphd(2gqLz#m@iVbC41HzP4w+JrCiFq9j1*A{8AsnEmT@!ltcP0nzmc+b{1Ov8)YOoWSXiyscX)HJ{&J`J7= z6Oa*11D7Q1YI{%uN(gco*Qo%13t^`=P?5LccLI`)Aoa;v+L4y!tLR zMRI(;xbpikW9bP$&W{BaLFx~EJf^bjPnP4Bb!qEGbEQub`>iWW^ui`1g*COoVBSf> zhJN((=E&Fe@1Cvic6lB#9vwxcu9v}FybYb@}#q3s3)!) zEed`$a+%Svesy|9?Xsfe_v+PKo#28^&J+?d_V%B6TDI`lX_zK8uXwpR0*b#?w?{g! zc2y-kJr?clJ90H-95Hq+D)7SZ_owwtjxg4OtJcjZabcHfDKNW-1N)*#gcDVYDo_c3 z%9ZY>6@F{&%$XHx%?~y_V;5^8#(f4)nW!`P6Q`e$AP~iViMuBW)ha&b>(S>CK{4`L zm@zjl2o+)-9B6|{uD#s2RNI2>Dg64>DMNJHcJ5!CJ)!?uvn$Fb@LG3~(1F$MVXOyg zt_nsPJXbG8cg;al#xF)aVcJs`ED0J$oj^JLn>2SaCls}8{?#qYF9@c#FVwbfYv@cf z8~ZuLI+^IEiOX}D_VzVMi)qx(koTtkWC}t*g_ru@ShQ5cV61t-fu2MlHVpK zlg`2!d27YuxHqg$v;pA={gn~vvBcH$BeG2)<>$4!b6i8Wt_YcaudBH)(f^|~FOHF| z^}Olb>1BJ?tA=M)P(NzzOO~3d85+J;?beh*VD7XW)x+1hUbk|d@z|->Y|pn?#E544 zHukJ&JZyVKt}sF|Rh@XAZx$bc;vO)X*Bwz|F)SefZnOCp)<)S-7GXIsj&A$i2z67K zwd*Gh3Ltf0ifKUURpluWiiM{t$yIz})JLf7moyG*nTX6S)5FVQ+=H);uY#6a`9QiI zNr!Ae4Yh92RkurR@~RdjA5s|=T6uT%ZLm?Z8De|27$b0$A#3NkiFp|dva;F|hoh?$ z@tyhDo+7Nk_u_cgaX(kzpQ+v(<*M2y0UneO?j*F{xBSuAqL|1`}5O zeJ8{}?OeI?dKjOYyi7r}kkd#(S)bS=9tiu{>ZC&gYh%w<0REhMOC&_)gt(p_?bVoH zN-fU35bG!I zja+3I{;ym$`i-u`c;AO)QyrQCU4w6nmNK~BiH$UtJ8dvr#;EYyGiH{V`&hy+jq`oZ z6U>bp5?gm)ZJ^R~oNYp~waP1Mv@a2{O$?GgA_c1!%rGD61{YS+7*0+Lh3VC~!o-

    {};s-OEXR_gv?+KGr6Dyxh9({MyxtxJs&>`A1z~IG*Tw zzQhKMO9O519qg;1Jw7C!FW2eM>Kg@I#-tBI+wZp(lYQ;4TNqaKNQ#8xi-PlgLYB-= zk3*)=SdQGZSFXY$q11~omkj%ID%nKVkQ2C+&8KFpZ3x?}c$WmJt>Y(w%gmk-_trN- zS|}-_pMNxusct^RSHUthPw2p|b-n26vBY zg$fa8^G%$jx5xVI?=i`b1o{9v8ufeWw|$f@Jky2W2OqywOC-ODqTcuo8_CvB(mDkv z+5a(nh8k%8R0^Wapu4)QYw&OpER+oHAcMa=tJZ71!oug_T+=m+>-Mlaz5wVzYkWxc zT>{e#CnYtRQMw-xUf~ZnRHr^!<%Xd()h#r)XJ?BY;iqLpxKGB9T(5L%=by|06W!5N zQ&@Bo(s&4SB3SN%bRB=qUX{D?fVGxNATKvTX(37G<|7mjK+Jo-|aOQOCAjh{MrvX8>6{NFg{ z` ze0}S2?KEbY(A9Rm*3GQ()T=Y*GI9&BU7gI7+^j}ao|?vL%Nizws@H>Gb;~xVnJ&2p zo28|Zsl!ydFxwc*_PB~KOpor<=U5>rFn=cHwZbjhgb9 zQ5Ea^)!D}7@zHX(N+Rfy;e)$vdMViRGHQ(0jD5cm++(M?UO1=4wn({4@xA3t(`i=^ z`dlmL)nhJ*yp)Am-thh%ciO$7EGNU%HRxZYe?U4eDwF%j$~O)Kz$E0*k|>=-OR`H!lO@0XtcDHWuJ{`%wcoKHI9RGeE|q>OJyj+2*OFv5BA<9; zBg9lQ4AVw#o@9LTPf<5m66B`XETuQ!lns|A8EF_dpY7Zf=k=lqo%}&=87DK0UCVUs zZoW=EJ2D)w>PjV#j2P8x5W9OHOG2#vLJdUBzw&c3=WuP}7eot_@-tZH)HRvUC|4jO zKdCG%%lKNc22yl|POs1Ivz3UhWXH-w+lIrH0?5mK!N+33CKGu?CzN1GqKdcqa zl4i@q_x*q%?3*;c(7i*PGR6fvE?<2fa*cBV zP$(CG1b1enIRn2jX3G8(OhWvA(N&?1N1kvbe|{RcTD(UQ9<0X46PHosI8Rv$by(}Q zA$PxTx5Eef?cnplV}*8Lrt}Ru18u+|)jo!zw6e}bdrzcRE#m`+|9&xl2$q3P$ zX#K*Q=@?-?J~`BKF3RU>p9BhY<~LNa|wgQ+;)2zkdg<5)L0Qc>GXJPwD zQUr7UinRX9iNMId>`+@3g5;}f+&EZH_#u{pWdw7Z5x0#$E;;ZjGYA7br%rc-GW}vw7~Cm(pW+&TBCG*a$b(B z%2h@mQNlX?;G>PM$qC-+8^j({TckiU7DBiDI`I5Aw)Mo6zGAz+344hNa#Fw=BzMgM z2E9oJQM4Gvt$FHa#;)AccZ{o@Zo?PKW_vvNE2+ntr7(g{qihRXpzX_G1@Xn7ZIo*K zrN#FF>xOe?9~5!-PTcLC{&g|=D?F?u(tYPam9u2QVs8lz`e;XE8j9WZrZrQm)Z1Ln zK~`R(AA)_FYB7O|A^_1Fn8~cAlg%}wCaULF4CxMD_W$t4jIso-}V=OvIo|H0%%@Y@sR7x zG_t^AyD;58zNFWY|LWs8+zG?nkH8z0)sD=dtfJMA*L(AhGs`^C%2Xk4M&n^eL+;8k zCmiy;iKKt5b;H{0XC-g7w&vpZaGE1 zp{}_xIhg~oeRAE>^6#nVBKZB=m`Jf}d&S{ZWNaHTR|<;_YsMMo>#0vf`#MibXJC2S z*D3L5n^u+x(IWdE&Ra!!zjy%-Sf*9>9|_fYJV&{oqWtll6c=XMx8mW~j*ERCYn^zZ zDG6C7%V9rNlc>6c8^%t8NXj(owfURGPp{o+z-5VDxrak|NK406)pgBtHSljSXI z*Pu_DQtjigHC5_0U~D+tpchM0FZ-r)fnyD3t;8DN$}X7;BBrRF_T@JAO>*^wL8CX( zi(L(reng)bezoAo_w9ED^mVfc%f{3Ft%7@B4qQ0NAdrQIWkIkX{pM~Bzu^a!V3x%l z00&8*{?0xrbMZ}d_2xlAG!SGr2n>dz+VXCBPq~NSxbPn+r+3{PTJ^PJG4lhd>UE$HkyU8Y|oy)1BiV69g@=n{=#%Y2#ej{ z&J<51fN|X<>n|pGvDjc}X;;jo;#FXDIK*DAD4xnbnHsWypbB`DsxRg399=QIBk=oV z2@G&OhZJB)U;$4E#I1V?@*N0pQ#6&z!YD7la%V<4^zv(|Qun=L-NdIq2k>{1r0Na} ze%9j4Wy%w{#sc69TAQLQ?xENjWVC-)ti}7&|gci2oIJYg=`d~}^ zozzF5?hjvSS&!&6VEia9e&<2257SNUtqoGng>2kT?&`dzP`mc(v=C0Ryl#%`1ycE5 ztN2?`Gi4BEq106-QOl-Nd72T;x8}jSCHcGF``MO0wo`Yue5K$$k2(casv& z{pa0m=<-xbnyo)RsU?y!NJOz{Isi0tt@4x#M&w#63ztBnMd1-7COr=Ld5hCnaCqe=)%o#v$T-cnW~+KKj+Uu4;~y?v(;~YAMw)+tJTW*Nb|*}&n~Vg%Hf%yOo*HdXCN|8rZQMk6T>h3(xd(ZOvt0<_sn{%fPF#? zC(#6B?ZTpx?EFbI@64Bx^Sfx!G%j&MFPD&(2{-|9mTpk-;HZYI}nrdQaI#C zH2X=g)1SZS_8~UJ4PEbi#?W*jC}HOS7(O78B% zXlkjjnV72zPU?kX$oqD3FP&T)Fm16Sq?pvh9KyQy2Q%i%X8qp;l$Gg!wFfg3v9Pc( z{~z?p@*fE0VEVrz^#3uST->Z&|DOe;(Jv4xK_)9hzua2i>amDqm9vm(JlOyg#OIpFDR@~vFeOiPGYT+N zR9XmBR5(2D_Kf68`rBO-E+>S%#;D{V{#gM?(d>UCHH2);#;Zu&o-p14(V6rC>F9k^ z{ex5EgF}!8hDHZpad|drdBpc@tkhWkQ=@pZ0s#iWjtwG;JV#kqmbyi#g&z$NTh{fVK71U z*>FKYjUiy{_9~5S|Gk?S)sX{0y2t|CwosT5P>xWBQt`1 zF#RhNXcjm3`TJ(}&@RwETrg$Qli+Ch|DL~5Qr=U+@b`9`!I@Z@zE`(;o4;91Out(j z>dVW6vJ30GQ#l^`(!Yz)L?mXSgSq?w z^)0U>oSr-=jC_-D znVAKoCzsRqL0TA^BE5{h!C+f_F@DVZnA0i*Ff5K_W%~Dxt^R>k2#C~-4$YXn-9^2AKa_n}-+$W=d^g;G za~yqh68+-T-t1jh@qhUCUmI~#Ytj400AXoyuEs&dyMr_!-oI%petoPiOh8OmZC!pb zs&6cVjFE${=xx5W#c45r(JJJn1ClGtk9$jw^_sT-NOEB^MUdeA^JTUPDfpEA!s%IES2(01nC@xL#=mr0| zu$(Qzps6K=U)zH49+S0(HrTu@i1}MEE8G$oZ{I~q2@=e46R=DAh{1PT` z_)P*tLK-O{r2iQF4(~fcdfUtV5+Y2It`A?;m2VF_1e~B2r%iJFB zd<@P@bYe|^feQ@4d_njP*?+&bK#I+~C6M8=P4&iTQeH-qH3>_eSgpUoZ zuYKkc{ISvc`gL2Fn4%Y(BKYnv=`&aL-yRz#pGY9Xg=fOsLMAu=y-@_ikFfH%!r{}~ z(e<#)(adM0X9-ZO{~BROEa6RLH~rk!6H@Z)?vnp@@Har9!0Dq667jq2c(iij^ihB8 zZGU=vdf%A#TO#4Lw&1JKV2W_P!);LkH zeF3#^E>F*cWO{pNx&SEOgE~$&H}IN0)PV7RYEwVNKjU4iUS8kkau~mVYJeKBTM#R! z3<}399y6eSOG2+jVDM~tKu0|$StzcVCuPN}H(AjtA6jdDUha&ecW1siCWjEFzJs2B z2Aof7&m&|@p)p(W!W+-&Txi+`KuYKWNiMS8arl8NS zOiVGZl&S-9&3%>E^aFmSSKPa#i7tdbV0%35NL00zEOfmSBT4%Z{&Vppaf1^7^W&k!w9p_4vEk>IyO{*9dvY=fG*&Mj8v$bl zKZ%(5LCZ3i$U|X=$`9vGU9?5=5aT}SYxk3P135{BWznsOE3Lx>wq;PR+i0hZ9^WZV z(eM~`RO&H|iT|A#h~a`U0{vxw2@2Lwe7gm@fz3zVC+~;Qn6O?P=`4>16eat|pM?s? z*HGHP(u!wA!SimYg;p-s9+?kkuhgm07OmQ(>RyDt$uDmFEslSI9*&$$hhB-f=gyCr zo-UiA9bpcOuztS4Eh2{p6AyUdV6-=0TGWodp$N3RvMd&Bk(xA&PhVo{QLj;6?b8UV zo|xVdv06ij&lJWgfPSquZjz0%EYsgl&da5KI0>ig=u(rOhEGLuJ#n^~998<)fmOVN zVM{Jrw<46Iu-wBTLrZ^qB5@3-8Y>##aQsu^`RIcF?zh+kNCa=57pB$;J zjfd`yNEuxk-_(g@ot<@cOZI-oChW1BPcTz-?Q0Me**UGUr8v-e&c1)+_> zqL463czI{$Hdf(2Fs_`yyDI&btc0JUpk6%>J=5&vWwaRx;q+G)cIuWZeGu%n-$h(Q zTi=RsWkt9t?nPh9=3MD9fG0>B*<-OqQPCTpAbgtD@hwyFBFH14&K|{$_xWy<8)Kf@>dEPt>{z_fBWda^c~G z@qeXB@w2%>XdQa&3g<@5h(^pn8TzL;G;!vBO^9lm8Tc8}pwIl@1Cqb|j{SwM#!-iw z^3Rl;5xM7GzD<#Gd~Y8Go>Q_(R^>TV+ex|%4W%yaG&GtOlRGk=11FLc*39ztVP~%A zUE>vl4?em9#{b5ti}X~|T4DCh-lwG78<(p9n&giDr?D60ps}}crr2(Nfjz3CF^GoB z_7!#fib{XzTJ{HQRB8Gv>eSyzY}wa3%u!#5mkHXxcM5x=#~91zBGnEj1hx z3-9^S@0=XpOr{3}%WKx9k5R<~%8P-sIV3cD$~dfTS)FHH_|QeF&QhGiOc5XB_MLwD zYSXW`R+j}R<&2XwD|!8ij;6(mm4Fh1yM z=9d=e1>6H6nJ?=tUF?4ZI`_*Zd+9BOHe>|J0ewROMgM}GUd!mX$qF7HD-D&du&wk0 z(tq|sjlJ=V4dNEiPnB2|*!1jE`ba!(Bno(){H&U)1;Y zvr^`Ykb@#4` zw)24(w6io53eW5Ip^?FP4EB#1GzB(m}tB3Vz^b-jEOs-<(SNw(yHhhG2elttzjML8F`e!4ve%9qGH&q29e^6P*LA*RPPs@ zc+Sy1Jr44$ZX^e=s~V$LqigZW4f768aB7-MB{_EO^*>;XNYKRVY{fGF7;|VHIvKaQ z74mQDQh0V?>~-hC-4a-4P=q<3mTgZxKoXisJO2{b#2OJ=Hc7e7;>+Zf-iFlZS|=ak z@V4^U=BUk+HBUTE^m;cgP2uU#eeWBN2UP*;8745sQ*^wfUo;wqO)1o=2>m|-3K;9Bj%$) zY7u*yQv;CO#T$STsRn+%pgS00;zLWQ;|ln zveNWkNL3a#hX0s~tAGxq#TJOwMtzFNZMy45RHtyXxT%MstshH2q0H`?QO= zx5&GR19rQQtOr&F8gX0bU{|g(w!`u?EaaaClxk5GDsEX4Q<`pism*uBS z|Bl^pe+3BIiZqCc+}gg(+8pqB8DX6%Smv|mV%{)-p-`%H3&edou{Hf5PD;8F`Y`WqbfB3 z9H@VO>@m(llE45->^*@9lfcF z!v9nejkfj2^X9+-(p#B7u+>ebt_a%@WK|dBN{AE=yQ+|~A3`PZvua_6*doxKpuXE; z`SSB(6wVDH;nl2ZE3Q~k1_3tc_(gG?lNl-FKz zLxe8>`mDR6s|6ILiZm%iNTCO_ZS}D+!D}}QD%d>F_TxpL#ITc8W%AG`qDQQ??SVbF zK2{+wQ#AGe^5Jjz%)d{pt8K-AxzMs07Vq`G1EAxsYZ<1f7TGmU1Fi_f}PHu7V_!lHqG`PhaP8-Aa2 zFZ}*bVRqqu=9sa&!mn z9;Vg98UL>v*}|24wf;a|OXc6hs??EaJ?>*OL##jZI{ANMYALpeGWG1#i2Fia^ffy+ zGu5Z6pD@fG)6sjyQak3KK$%F_jTe1v3NLXKwi8~MNdxa@0r|Qpeb0ZXjhJuTsmi)3#71;JT#&*AQ(TL z`bzhbQx62Da7!iymUP*LA#$QoUl@#AcMF$6-k zaL|99$0CqpTv>NmggdAy1yF-SFTZa6u2G9q|F#j>j=F^9TbR@`?TxTjLAhh^HQt-8 zdXCS3_o@X(u9xXHBd~AbV**ClWa3$60b!T4?UmAg0lE!VoIVCNivxX<8~m~_q0O(& z&zB@7cMgvgK00ayazBG#=6vs^vTJafCfVcO`XVLHX=-JdtNfEIMt+xJJw^!%7hX(T z!on)&O+ZiuY!4BluA}%dgcXg$ZNyV z3b@6r+@%h2{k`*4&JFh4Ncz+u)7Qeq|YHuPfn4~O4dZ@p6u&9y z?6s^FoTpb_ks{;{Lw?}pTOdu*(zVf#|IC?y7JLesIVOxrfj8SAH@)##r_GP#3ytL^ zdM?V&o(Y-Mm<|czY*wn;s`%l(`tnxOqmY|Bm1o6E`c3k?v->b2PM4W9SdAK5ABOB# zX8{r3qPkDMNa@b2nT`_M{j`%gK-;}$=?Y)`>360!2QnpEvA$f(mPVA#?4S`@xfrvk zJIoX-^sFUS(Hxv`2F-EzB2Kz)O_OlPX4CrYDxfZtu3y^*M$Wh4B}yX9jqd7Yl?Fd2 z;$iS>yx<=lkWhWP1$?s4u8UZav=xS!Nk>1t0+l2>q0D+xrhp zp(x0C8bk8*(f9plY8xAccZR~BTq|2B*NN_0V}OK`G2{kfyL<%R*>MSVC|qv;tZ57+ zn7EwjQMWiXl=+2#xDE|uZ~ONp7TcV6M1je^(sL*UuBHmm+F|FL^;|Ae=4;Qmzr1D;{SKTR(?!=c2;#zBim7zR9|Bul=jZZXP zP3=8|2xlC_JNds^j;#eP&In-0vF73)?@eOuY?H+#xz+(?G4auF!F>oYL4X<)MSU;;`zXcm#>= za7}`YuX!dFKQG!8WO`8-Z~Kime0(3vVtkTzULpUGOMe-_hjxR-z=qb{>O2Um9isVz zFF@r9R3@Tvj8CI>O%vSbg(NyXHpLInM?tA80WLPNZ6w}Aqj~7lVR^pnLfd6qg^y3Y zm-xMxgdB0|(wyV*N3)l4(DC^|+Q)vvrl_TXRLA2mSu#vol%MTVTu6lIYo8K_J`;C{ zuP?g$bx^p#8MyfDd2Cv5?9l_#^!%9$k~Z;1JMa50RB%jNST5>*)lyn&;~`(LC!Av` zgf#z}IHU2*td#x1R@i6JbMUT-@vm`2T#+%h)K8aJr4;OG#?wxr(J#;TnUt$j1he7V z@GA+DktO?w7&du^s%Mj4cc4?;WAf4#Xc|qaH4kUDd=4TuaE8; zcANtIp)%*r@!doE*^>u#3@(Vo0IbveVtaU5Lz9+Up!ZWEd?j=D3@Z&%(ey+hcZak9xL zLuFVA$YkOg+iEncI%?5a^+JI(E>@4f#+TN`%ix~18!d*psOqp{5d=0z~r6^6^1@Rer+ zX$oWi8uyh@WdHIS!N;LFN^=xXPvF)|`AAkGe zE~StbQ|+9W9W^Pw7_+w?)_4xm3fgE z-mx%FESc^}_hB4E2t6jY@V8o;^$W0Y-pV(#eRbo+OcL7_CjlR!E z6Q@R6%+t!x=k0OS$gluh-{p5TfVJ2*MzE3|L)NzoX=3PPA06s;Sns0t9F~Me;d#>Y zh-+eRce6Ja;!3zMNnzOTK2}C(+e}kjdT{A3zep`@h@l~*(zw|;mBC89EBvzyPRlri zB-V}b(W&inp0om3pcQ@**)Sbz@$^tX?hX%>u|vu#csm_jAiBKyXzou&Xq%2BGfAT2 z^|{BoUEMnj7ydH{&Cc*8UTjQ*y|IPq%q#?E%>#(PDW$3+r15k@vajbcXV{ppeqTn}9$yO5&r3As8o(k5-|8Jy8Q!=x(gyPo+y#Yd7gV4)D{ z%)}>wJGqV$v?tU{TZPv{8xDlheXyQ*KAxFkgka862T3A^4V@>a2nL-VHtww_RSt~& z#f@eiZnVyd)m~5AdPBtiyfinvk^W#4hh<5{6_O(GGw^k;~B;k z(R^Oa2`P0SsgEY=gA=GWNiA)r6JW@M4MMaE=B<%wlWl3SrBEer?yvU#K#wu)WUSEY z__6s!9V2lRbAX89Vz1t3v?he$DX%w+VOXZ1!v!G@KMB+%a;;R@*mJYv2P2kjuILJ@ z-@_CovBkEfL{Lk~i?Lib6Z3s2r1J)F4x`y9`EJEDlpcbhn;TGGw9uEH7tbuDEX`_M zl;KRIButCzzhS+D#7B${=DRZ>N$+X{F9>`-yU!h~uHGCn@={lI_}mu8?cO{^pX}s< zv_fkBvpdLkN(hRtcwHuwNZvL#qtai)cX+ykJIOBiwx&IGTUkR^@nYUG2WQ@Dc=hp8 zr9Iqia;|F)gV^zhk4uJJ*_0$SAXN*`R%&mcE1Zz_#^SH(B}YW6 zWuF6rjjwi`eq^`eVCx5A>*T_t7b0|5voV}WN+@cEIVeYWi{@?O84E+e^J$s1$$k;SV5(c7hn#1v7$wmjh zuPLo|H{4(svDbq)Y>eY!Ka(8 z%f#61?ewvhM_68HpXVl{h4NP89|7_9cS0lcuCGi*lUa-nKM0mxy9^_FdS7zl8@%ho zF;84kv$UJ>cz=wpFq#Sd7Z>yyf!MWPSIMv(Qm<|&l0GIhMc9!oJpbX*HTvj<@kCSA z4;hQH;ov|SieC2VonJ8;6#s9p;x9dn1=fz2^#6;fj72lR&!Y>r0I72PP4 z`|EuwW@XHNdQGRsz2F&Ds zj7}|wEa;r18F0#&PA179nV4~_M`)D$R!8ffWdc&9p0{oL;6|AyOjul^Sh(XgdrhIt zL>uupOtIbNy&!^|gugAowt}!?k~l=5_((GZYGt4}0;>k$1vx zo|?24iIcKb^8CZ7N+56H9?qAA!am=dF$YY#@_*Pmr{G+eaLvZrv2EM7Z6`an?R>HA zWXHB`+qP|6=dY=nnz=Za-PLzp?@jmftd%b=uDMN0)_>WCqww+ zBYr%XzKf5)yYN%9P*v?1W-U3iKtRGpxS{wx8e_UJ3@0V{QlL#gLBU6!4^(SmOt^!e zoA%5FP1R|eP*KU1@s*|rZdMee6Y!d};^E zMmK#W8x2cUR}A4z^|B0jEg0@78~C{hY<-Up^?AQ&SwOhF{S^RuwdW>AcCbiC}oZD&Fv}}p>MdE8bz1ZDJHOcIh z8$Q%bS}}0!3ZD&W+0e1wew{dl=B6*pl`}1T6(1}ibSQ;sVB$f=clM!DX!14cL%W{_ zoT*sl>=U5jT>(7&p0T&`i^pVw2mV+gFvN(qt$YVRn+L}><@CFyEwNAGlWyDbT^WpME-Ci&q_m=QRtUc3)!ZX&xD*I>#!6i0EsgqzUsGken2?N z5i@QLj++At|2(3YL9sH+;l@&~8I-w<`pH|Q@Ctv;sQ(o~6w530)0#F&b#4O;OGU-i z949BQWoNN+@83f|sAfz|>K#yQ#k8SJ+Bg|ygWyR;XD*RFwCX1W%W9p3OCxG`m7%@MI4-1 zI;aWHyhZ?d;Yz`}#f#=|k2J5>b(mX81siTY45(r6kxwu+i^r1UQq{% z9J_2n9GuVa?s}S5x&KBw&v(z@BM_0iM&Kr+ZG^9*vfCCqJhcxJO;GH;`pwe>p`5;N z7i1otlU3=D)`p|b-f2u4S-W`fsXjd*_1Ul+P{jJht61;w&|(0yHAr3J?$_mr@c}J# zcN6r}e)cc+CKWItS#=iscAj2Q3(@I7=ttfug2vCo@$|73z8GvX@#%iv*_pt)3d#Xh zY^6NC?pAK$Lf#jls9xXd%qe~oh*Xk^Z`_v*DRYxETdGA&H@9Ui3^4EH{{<54l32vT zLPq)^M{xPrI~@;m$!+gWddUw`P1N9oaPwWI1XT>Fe`LN>B~LB;4BHl0u^Wzz;@Yb* zhg8AjljGPOc;U^BlV!McvA`l`>a$UzWh;75ojVq$=f7QzJ&Ov3V(krXgSwFmawyCh z6y~y7B5*}&62WDKn9TCH#Px$l9TQ_%z++oSKq-Vp==J$8akP2X(|6%RgR3sgDOvF> zXO{#wrWQdHwW!5JCyUUkx3`03Ro0ZpWi~il4HszJ*{ZSEw6^@8FItU zO8YXXu5TjAW#dshR4A$tr&x1I*5z!&{Rki*m6sZj#jnuhHkWP-XAWyPd8WqMp$yx8 zi}F>d(?Rl8*XsQ_?A({u?y+wExn4?p~=d;{Cv^m;`r-?_iLg{w#=t`mpQpcmrq zu5D-BW1X<7(RsneHkei=K0?nSy_aY%f1Ed+5T%@k*$kynLw1fdmaEHoCEUV(%FAbHThd>by#&vA!`rNh{p!l-c`Rdnqlemx%<*LW8?koxVemjII=4!B zX34Nspr>146pis7VN0S_NC4*qo@d=t%EveQf(s z(k1vCH{?oaGS@TudQRiLgiy0Z@_lQx)yYGl|K$PoN3)FTaflJumn;_5tl1<^?Tq5@ z1&xb*N+-XHxBr+s=`-+1-kw5a7U!jo-?%Q6&aLH$dA0>oQEdUK50*~$3)QQm;70?E z1yzn(Bu1vEF+jJLn^h$o7w6{vl5Ie%>c7#@qS6S+LjxyFIEjsjU%TLF+e{^oDC4{` zJO@eza3}RsINm)bV%+eIk$!19<6}1b`$z>WI>j@c;33%#AK57dP>t5>l>wWqA0(%{ z_u-@2@;?hdS}3J@RR}@ktq2At>5FQa>NzyPKs{8WfRY*(ftJDxDBpq9t{;W9w%a)2 zOL{3J2S|U`a~xSa_up&G^&4#IAmjzjhztEY2$$(Fa3`bke#bgk9T6L zY9<#GTX~dP6u7u%(ILYa@N5T5ZB$dW-@84wgqkKeiS0l5sT^?r=bplt!?A=xRz0$k zF=YPa3-J`b50nM*b$oA zO{liy*>oB?^q#IoDyeCpF``f=&)M(%4D+33z8S$8-^0s>lN`)9TxBRT63*gSiOZ_- z*(rZ68cUdxKxG!row)TQT}p^cd>%=;rvp`%3V5c1W9^a_vx6)g%q2Cmf@Pp5Frlgo3v!fS$LW7)P7x;_j0Ef3e8M0xlf{Kou)LUT{hFOOTS_Aw` zo*#{9e@}ZC>Xsz}V)sBPAl>W)lCO)>cSQjf!ys5rqy*KivhJXF65gDslKcd`OSoQb z$Ks>lzO@Nt_AGd-J@A`p_vJCv{WC-W>1Tj4?~P33^@=ED-RdN|eoe*dUn~Jp^e9GT zJ%qYXhHzD~Z`udi*<1uAsw?785lwZK6ULnz?CL=4+=;ob*H1Y*XTupCo*%g0T3{51owVZmx>spbz zXyE&h-7b#Il@=+_q%jX^$vAD$ z!mw%nZRQ}lgsxv6rLUkqkNM^1_zF`7e5WEm6D3>tkQlxQ9(qBA+)PAX6^&H8nZ@bB z;QJCO@6{e`=hl2vGL5V%@QOJB)@wHM*DCc-oHu|JmQza;xg;pBwLhQ56@tWpH5Xe2 zV#0pPDN6#|QD;zJjs6gYyc;Clt}SgEo)iN%-zL!ps>$qOEzvaF@qA;JUT(-;qveqe zIq1c5ed)<`a`2|Z73)mei716@CsRrRZS8W^4(i*d`c0#wYXe7JgZ+wIcaP4D;-HMp z?5|U9e?&rq4|#t}bj4HI-GAvZ3*5TYbqN1|Gj&|m<6@n~wmj1-khGX#%vt>Z2%rB; z5VSdtM8-7^Rw;D2fgQ1qG^WAAiSm%(%t7s4yFUt_bLaGz(k4}|oBUOudM+w{1iT|q zlA;mIEy_VKQ9K5=7S8;~;@kT=x};>3*-|CK7yvF1BgK@$C6>aMwc(UI;}=e}>2_2> zMhwVrbU==I%x@n0Ps2lMLG}qijz8CHx*1uk(1pP4zP0f%+jD3fP620OD#}gT>Dc3u zZ}Rfur2~lW^C3EC-|oy>Lom)N;4|zL@02)9df_K{bQUTtM+#ciAuZ@xCqe`%6{!wde${hLXkky=@A~5T!Isk5bf#g>p$)ekmihf*%q%LI94-TUjyE% zBuHXbhMJK1nPK9|f7}p_zG1Ls4=JhZ33MEJ8-%RiKtr6i1wqzS{0 zL-a=D`LMWC&)U5AUBn7D7fKKWe-%CET1k7li|meYe;=S-4BS>`4AjMZv$JM;`C98( zJ1+dSd6XEQyVAO*+<+k8j^3P!+BQ)}3ESMI>guMWt`6KA?uQ6B>Eg*d_P7+%OBG&D zXD1)@`~|k=pJU8A-&tsHicG^aKa4-La5H>uI4`&OAW&3+)3}b+P4~r(pGzwUFa>hk zyBjjeePK@D^Ds400vZ~qnADGI6mZax7UV+tcxx{N!Rwfv4S`~&b+A3SA7`)7j2ssW zjjX{_7$7qX43-1Jb9%HgjM-q?83JN;ghUN2xFf-^7qL2QO zR(2BtMJMW8)_pH9^a-uz&{v0O*!)YI@?Df5P?p4nF$R-xJQwCiNf`hF+ySg2u!xr3Vz9uRrX&jYPBwa3qiZYgQ(|2mG; zGSW^^MRL|aSd-ZJk|vSHx|5VHJsp=eGpa^}B&^SIa(9v(;JsAD$mleHY#`#VnGox9 z*f0~AIMpA!+OA$byu60$0Ch$|LW5P4zUh zhe>vH;gJKM@}ZrLqEI2;RVuSK%dwOz2#G`vrb>MRdmW29o{%kDO_y8A=>F2LX;yUe z9-9mZ7cc#H4~{dBS;L)RvvhH+O1I^fV61az>ZI3i;E2cj!y&wFP$;9by^`?x-8s(x zHT8nGs7zZG7skIE`g{6UB{8EU>5;^m{?dl|%v1&EYBg&__h-zQ{#ot1dcIEP-FB&> zMpH)2h^4fW{D-=Oe#kak#D*64N3?iaZ0s&|kX<+$P-D}{OQ~h@ozaKI1yHOXU`~fs zx+7A=l4YMoVbV^oo~sc+{J3Y#q@gPt^>UH@J$-2E-EDLgObBFs^|u#w*VU_&!*aMxmGL2x*~xs5*fzR`K2UOi4N5& zP|8XV`B|v#R67K1N)s47A1%*Rk_mvdG0f_R%wJU~JDjWYTN!-AYxVkcF12Fyyqyan zIV{q%*#Nv=PBE+Ft%fpjLHj0>5%E`gkNyPP;`~0rJzHkN9OJ;)!pjKZerJz_9{qIa z)=Pf3!w%AYX2sf1*2|VQE42bExceED#YGIm=)Kz7&?Jk2!>}|FwZ1;Z8;60GY;S+% zaaeW?(&7El8SYcT*+y94ORV~)7bOWxl=Ks z7CJ1OUhu-YD_wFrNWxgVdj3nfot6@H|v5CnmA z){xRv$)U&cE+jysWDJ6%SL+3W=f>sJxz@{zdNP{c)T6AqHhUSE)9LN4W?IBpc1;z* z0pns4!Zn_9Gtab!;^f|w$7HYItNiqgqpmg%=}S^npttr7)(8z=v+ZqaJ+HSSOPdDA z@b&VPtDPeD@L)7YF{jyp!2cUIi<6KKnRVwi|7M++Vu$R^aXkvbB50g3W`#X&YSinJ zxb!PPN14`$AIo%;k^sbd+6fG_;rg{O2luvzj1l#|Q3r%JQqRtB>Ae+uT;W@mLA{xw z%0^5J;NW~gBATDk6-I8eJBeS0R+k?qL8{s%o+VrgAKlMUo}ZC}^%{fK^Fg#kB+@5i z11>yqPlb}`v;4#N&@u{e{?%H&SR@~N)+r#Ugq9P3Xf{+T2n_Fj@5V`B2Q;B74?DM? zI6yvuf3R|=4<$D$-tN`%vYM*emw2+?*aE;;&9gUV4whEVganX_#^8&SyXQ@($T4i4 zj%~RAh_>zAxCN$BhW<%)!5isTsZn6ji#e)`(s!m$YmZ5GBIp6M5&QT|JpOzJh8H>0}PVZkDC2-&2Faq8sz_1lvi zRSTO8# z?tB@Arw#~hB$bfL1)jDh*kEBwh{P@TRSVAtU?6U|U-FWa+;ITFx2 zD<0r7_i&Jph7NO?&xnfh6L;22mpRIqUA4%On1m)-Eh)5nahx@BaV=apNKjhEa?AD} z#|EvUa}Ngl4Ra#|BPcylsS7oujzA)oQ9*FlCZbW5hSW=#K7or+S)_WTyj=8=KY{B0 zFjd_5s9?}~DdgisPhb%c%$OAqdYO;hiGszm!9Yq3@*^(ii{30NrWKJXU++xfHrBjo zT#Hus=lGDu^LOL29tH&`EoqKvy80(R%8#8N^A4!Fq9er=iHaYB!YG&Eg+J$(dkQdw zsD{Q9MTZ3F1wtR~wZ*Nqn!GL$SkF&Yk2stLx1rjA zS`W30%qCh9n*uzlDHB4>^j}Gm)l^{)rw<*9)4=4idUI>0P0-dCZq#9^PR+OAz~S1r zQr=A`C_oxg>NFP6+qFs4*uhwwgVP1tLQxj5`*$OrIkx(4I{B4!zhE;=&m>s7Kdi=Y z&~k7$6>DL9FK__2dD|WToOZ5w{oAIk3v`Dz5v@K@In#4gvi%E=T*=g2{QM3@ee3Lk zQC10`cu*<8qDqJJnHRyH6-*;=AWIoBv}TSh=(Bw|%?lsqLm_jtV2kf>Z9f2wa^O%{ zQy|LWx;;>e-C8V)Gk*F{--c+`AArHzVX}Y<&JqQxfOi>8Z+f@N-`I`oNNGGo{x}o% z+5p{GIVS7P`KW_0kJ8TUtp(J_#;V^8SmA%)f15*v!WfA)gb2B+?fPqjoPVE2QePGM znC!oRtvs_5>L0a`t3i3EyfLQXC}X_GY1!)|K)-F85#Wr$DD{#bX^Fz0=$xXAMMkki zTdgsJ0n}_>BK}bAd2IR>1V*}9>qx#zBbe0~0wgxk!4ZE#EDp8Q@)tU`0IC4yG5I=h zHB2}pzU8o=b***L3^!f}YI=vwHUNr^UMC1Ue%z+u^r$L(adR>nCzBXlP3UYv614#s z;ksX6w=0j7v++j`@wm8=&Zm@{V2`}zv5R!dmCIQlO#eIg2PU`lWW#1&ACj$VjokOu zF&*%Un49wC6;Q*4Icm~+2S|2TPzOLQ^zUf#np7lC`ea+&Rs*hl4wgKhvl)8m)Zx*2 zy0x;dddALy?;h;}Q_JgW{;P87K8v?1{iOODX7v3Dn|aVNnyP|1@4+SoMyM#D#E_wZ zj2ycL^%f-L+j44|!9v$)|J<0GM-A__s)5u9)%M3FTzmcpax*AOy4!(+o5#M;KPit> zS|lh43EmMgVAjp&H8UFDYQgZ_KA+ub%#fyus9!!W01}F;@JJ~qOr7@;`8^3GoTFtg z=1a$nL+8nbT3dT*GVGPh$6+gY`(;y*`4?<7z-X}A2Q2&5L_Wb}cDi+ELU?#pX0#Iu zc`X@{!Qw1|bD%A$_$L4D;@l8ql7Xr2^T>B7ow;g*4?_GeCl*{M%5$jM;liGzPTdzq zNK_6@x|j_8wGe-?Vv(cTx)R-z(f&&qo8SiG_B_6u50^8-ttro9R;JISmRJY4t}_crQ+E?e;QE%4AAE^!qS!FH#LlOwZfROEhmbXBz@e4 zofHu0Czg)-oPJ)Ojc&pMb!~`14jNhMT7IB8K|kHSGX}O9^+POYWt$9lz%HO(czA8b=E!fPz^#x~Eb` znBY&5G$~iGU?e}YxO{fUcj<}@rhTn%5bbYkH25!iIMjbG6E|Nk3Da^s+GzHAAkyR_ zH=4nVt1mjzy}@5&lu0lyZ^5#HxNPr+OggP*oTD#RSZ`@#rp74!5C3HP58V zV1;zl%A|w-)kZ@2G(Z3<9(2RGLCp;jqq%*@e*7VyDY4B)IUjz{w5^d>2&RDcd$ss) zSY2KQ6SQ}#2Bw`WGhH3Nippmh2A)E_WU>B1v$YfSUe)cjq3DQk zE`UqB8j!AYl7yXd{~u!7ukQM2A-?bLvjVSYi{FxLKGeb#m~t>M??6mIc;2NNC1>uD zpQk~`f~SkP(#-`){FBIrsQo_b$D1~EA%IBe5$sPc2+Ah1vnCwQRZe)= zEwt~a+$^}rXhB>=zEbkOeo!G?9e2HIwLeso{TJJKKHkF@_lMs>6gvW&W>ICoBGZiy zl#lPRyk`X|Bzl`mZLV1UdmN5&mJ|+IE+Mlybn;FK@aie%Dy~3isjn4o=@>gJ@e*=> zG|_8q+Ge6ci{{0jZJ@PoIld$hdIk`9#HLlcHAVwUd|uR8Z}xPrreYDzR@wS4xJ*1^+%o*qhF<58?;!ROzW7tDBr zcq?0NtTd#0&che#+j`5c`p14n%a1maor+I*njmZtBSr=AZ}&^BGx$}>7H8G}$$i+& zFc6bIwGAMBpazCrPjSF1sQOvH?aMtf-fFDB>J%mpnSg>U-69A1vz*xLUq?dOfuzuh zD+k)OtPD02#*GO5imKw-^>0uD;CJ$U~L1hH|tErclMli_DY9P7n=G@>Ptqa-EEofCjHDKx2g8_ate}r#Edz^%%J+j+4!dJFyIm&yu%7kYutdXJ8+|~g&j8B?CgJ3p;u@I|RZB6@HAJTZe~}~|4Pa4C z{~4bmq77{MAl|}miqG{NRU6}FiEaQ4qk-w;i`nWQ7f7GLAQovWh7CMZ)R1YZ&_K<) zd?;QV;JLOgI%Mzgg%NnWlL$ChZ)zap^Xnj#R>&5NUp_zW;)eL>tWnClehTSwzbzSu zW1ix-*^au)v3DT9vHKpH1cAG19zB|u638qV8YW@83b%x~Z!Pg5ZM39DhKIRL2r^Z> z(M)r|oN;Z`dMsHTYT761d{JarCSm^Y9fIqY$()UGHz%-LDsJVOf{H4KN7mIWQvES$ zqtSQQ<)3UKJrqje#|?5vWUKD1auEz;yP*bIlJnK(o@d)cWrx<_>#^UfoI{4&`3goK z^`I33)1jmlX*)!JNMK*>i`N{bzoymu&ILMLtKT9){16O}OsEs73MSr$w-SMkUQ5bI z&=|aLvwT0f^9eY&=n8Wp#hETM`x2&8tD*el>f;dSYs4n*Hw15gsSg1nR2~W) zdHYZ^m521l)N6@X`TL_KF>XLpbpzzTbb~6+H`xy5_J=EdVITVzjliP(dcN3;)i=ic zJdwk! zZ#~?$6|w_`q<+u!@3Z)7?${@4h+tdPUtE(cLA|lJw#)J{-lvC1Kz0gOjgxc==HRZH zB}V96(&93Dh<;$P+uGx(b^iozaNE2U65Q|>HlEwZ=V<`+M5Fe=?VM{?4H8VTYX8S^ zOv=IpB6TghT9%&}tP zh#}8c>DFZtGTO69wEfJ@n})morJmO^rW)uW>*d3(Vw*H^Q=2g)lSoOUGa6_DlQSC(y1W6)!OdC2;cq-ui$-ZAd+&X+09)hsIIXaWR}danMb zf`M_M?T#+|#z`Ut1tK{MVJ<>wZ-uIrwCCAgTAw*`#fNx=Q3iCyeHg1I1aGTxgAMB| z#^=#`7ddtKhEap$aHkV6#^r`iqQ~9VkF6ym9quvi(SeMMa3R=0&>0KjTGKyMMSrSU z9o$G15*JF;W@+FVzRY$5g-Bv>As zj4ABObHNlEN=AooBX@BC=?rm**z5lPdV?j<`v%p)#mgz>eM*X!NP^X^)OEbC(9W*E9GBYS$~$3|v6%I6Wlq{nI-=&t zQR{(rS~b+1?y|D&^xq>cvc~aH=%62)TdBRQzf}i8E=Y{Ffpw)rukZg0af(BQh3mNtX2^rKC2BAQm0EcLSR^`1Q z`nNPdFn~ntLHHY__J$LBV~lQk#N$9&AvCm+ebwNCDW)!h``h7sRq|ml;$8$h?7IeR z{8}a4YW&;$s~)ID&B@IvXaI%rrTK0N)^&{5Kw*PC~7)l5Hj8JP1s7{!+;Tw1Lp7FDeTkr(|WiIm77ao01Zw8gpO!U3HzIS)oK>LOyJ}F z=0J&j2kTME2LQTTeSFP5ukND7Gkn4So%73O$gRn${})QXnj8E3GCs*e46Mf+C=7%T zYzXjgOUD#c#e}+hcSpxVe5$4P{|&C_ufhdB@Qdu;F8)QmdRcvM{AI(z_4hknaOy&% z1MB;V8_5L?3E11j`2B5N@C*Ce1^c0y{FOQU{Tts<+5K(L@oE42yAQ!7c+K}iyk)h5 z=2+<`H@ZpX|IM+C`Cx9wMwF_k5%&91K_uAfObFT7^6QP0Pd}kZI;0F43AFizG)d68 zUrW>&HbBT7OFyUI3gaI}0QJSNdu+8Q=1wf%68oXP`puNOvYm;5)2f~l9 zf*_$J6sDiq1QIQli4Mw=n>v}q?M&nS{yf-Zs3SFG+$wC>_H!U6M?@hrivcu%I*oP7 z*Bu}i@h$3>dOu;^+78drL?+bwT>5$(#o1jSqyBXsr}|x3>wawYiFtQ(k2z-NrO)M! z^S)`wUg%!dc*NZqiFA3Cl-vGVL1_IceWFODg42_Bj?QLfre!-gz3Dx`X9&Iv1T{sv4M`8j6r4e64n* z9A(udf~3M5tGM#h^?|H>t=P0a5Te6_?^S5apiNUHLD)0znxJyo9y2MgWjugYVJ?!P zItg`&1aB%hTW(4QPqS8s-xgh<=fe-AhpCrWW{*t4u3=`^>=E(J-0Iwg(TTY}^^wkH$)4yf2ert0}v3aa@EWjxo+ zdeq7%cPt9Mgaf7aGQTaA(rarV;`&<-OMvifq>=)c5$8gKxp=5sH1m709WF?_V;kKf zHE>I=X8yXZQ%H zF*sl%T}^%a^0c@=y43!(UWLEy0h*(gyzV*KoOlPp9^hne!F*Z1((7nqOen-$dUV7& zQc|czpbB3tZ%HL4o~`LS93Z##*qs~`QY_h&vV7v#ATo`}N7g{aQ4IR~9aKKJR@0Ow z!ByU~O(GqMGXgv=iQ^>(-P<|XjLj}%$WAz!C=OK52fBFXNNf7W+%ML~q=h4D0;k{S zZxwu=TEwd%*@yJi0b4>>YdCs}Ud$=!4Iu-jfC&d}Ci-m8Q2;ld@vH{7`uW9e{IDGv zX~?>1*V9($)wK8%nnkYkD{W1=xx~uEv4e@9BpsaZN>tdQws^vf0p`x*8O-LPH)_ls zbg{|-AW1KFKdwZ?X$9CoM~2DM21ti_)@fuDo9Us5DR?6WHxWgxuWNwSe!477s_>#T z&aGBexporDcGhA2wh}h!JCkxcqk#$7+Ufe5OE1zONN*nOUlhdaJeWRwhS`*G2#-wr zxHvj$fmx*+*1EmI64_**=$m$SM3#goixTxK_imS7&izby?o~U1+1m#MuX25IuN<$c zjlg+lA|bO~5`Ew|tb&1A`H!*umG4ODq+RIfdF6{O_YN(tIH=qZ{3l(mOe5yl7=C?A zz+LM^S?qG5x2|%K9wTa=)xlyNUxBarSy%TH$U~v1*JVSP%8`nZsO>UfZvR6i>;tX@ zrfBZ(avOaH9OHmR4xioNi7I=~NQkTx4%0n! zd4gvMv04T)shUZ=Bs8OSc=>GRSj4f3EjqWuztCFZLVAs0qV!j1<0%_S<|`9~C;hwv z4otMG=_v+zVkueg)Tw>BUeS<+?UwZK;zay;oRYzn+oWV)6P7vjnoOLL>`Wz5?4rr7K zoh(q~DX3K>dpJ4vtO!!GZHsP@l#5AaCFk1hD0>sPB~i0nHiT1}C&f#ir{rT&uw6K% zQonqXkJ?EMW)|>&xgMOo6g#EFnbUmDVTr*=-I7vdlDljlOZRHlw8ZfMh=e_dQe`_o zl^k}qVi*1E0=f^XE!_|z!s~WeXB+9=iXUp7E@T7gk=GFA+rJnd!6}8WN>|B(r0HF? zjT7Kq_u|MPySkiD7lQM*4N<}}7CP|qtEQjELB}Fv{;D=o(5AGJ&<@Gxw@pl}r<;?X zQ!5T}Z6T$xEJsAWE^Vy*Skiy>zyop^=yAo2|GiksxaYaoQ>*+B z?g>_pF};a4?!rZQH9*`WJW`$Z6|n+I|D62OEd9Wbw4!@bizQ%O48=Rv!|Ou)&ZHdz zUHFH$rTTzPQ-N5J2fBFOjE)QrZ8Lr9zUpRD*%21yR#c9kv5;Qib+PmFA1>C#ck*~u z+);KX@>!$W^IL1ac-f$wS#mrgU#?il%CrW1N0Z9bsPlFp&UF!F7|-%g@dkV0g%had zd9&?;nV89e9T!SHe%4c)jTL-&NdyeEOm*0<3J44`8~GWBkk{B2e#xGUOo;P6w64{6B)^!9Q|CE;hsU3jia&)x0rAKzq7CtJF^r^kN@_H)JC)is z>SNX0;WPs+x{{sD(pI_plbDGC1TH8A#or-jFGR?}p&V7V@xG%LL8U3(2~yoX_vbta zNn~9wM&ygqv$Ky4xt=&*J2@)IFt;IvF%LtelvYd7z5cUhc2~(fI*_Pp58Gk(Xy9Ah zE%@b2hEg6OV98p5bIBXg6Zwh10q&p5VLIZE4-C1Q^mUMq(k8iF;#&X0j!!2o_0BZG z#6s`-^hQH&REg^jBdJnn^W$BjUy`H;B4qEFs`<_ zhjh;M9rAJ&77Eg{QJEJ$-LY<*^4Bt13-9@xr!T%(z0hi}lR0?(foRfOeJ1{bn~A=z zys3plr|~5i-x_a5ARKBaQ0x&FRgx-Xd9cDJDLF;P>H%{lok;N3^8OBt-2a5k!4C4| zjw(D*w_nhe7ESj>iPwsLjQdL~d?IZHX`mi8;hN5=$c8frX4bd(5KCZ+e}v*wlQZ~C zx33c<2kM44PcpkveGe%vwI|q(hcK#?Wl#CCSqDzL1VZH`ORD4?A8+#M);Oe{J6&j% zcVbDMwQCD4nJY0(xiWX}K{m-fX%AR;!7$K4AFj5cjF=+GwU^)=Y>=RyNb+VX7!>Jg z@(6aHUb`UxAV=byyRE)@p*cGm~!<+dMaF!ukt^<;Jm&8r}M6}LMTBf zY;5sPV1fZJ{iK@N(X2Q1XDV>Rka>Yc#+7nxKL_5-NiE^{EksPv{4bKtHYr_MTDrJR z`(6p*z_c54s>J1jHC_K&?^OD<$eF!2R(`(=>$rC()bC^AX7QWdWi{E5 z=qTFnOo(trFjW3XU2;BsD)C|?>m&%gQBIoCD9Rt@ogeX#B3l!@C!B&tgauumIC6?- zOF>piOJj2VFvIP2vJR=3qXxq`Q-N9*6tMB0fU-{0Ywg=p+}5(f}g zAu<_WGy|X-ap8PZ_vAb9j}VLz8nPnf9kX0azLcJb->eG?f$sk;30p(si)%i20~gRE zM}Ou^PHQ&9vwXcAKA2CXMndT4$Zzve;NI3>+v>tg`g>VF+EGPx>YN!jwLOg=dX3b` z79*@MEtme$yfyC1=_o>^>gnX=Fben+TFT5$Ff;sLIT7V^f=@Fr1d~h7rC?r9nfTM6N)QTZ%p!i>1A)$nBsG*;W|w`RCfDeag3`_E=B_n zNj6d%>YiMJ!R*HPKDq#FNNe=T$M`H{uUK++b{U}nhM%>qQj;EYR+KuH#m7MB|y zp!^0SlUKDd7V&fFYLbzbn6_vb@238@n55pe+E8S9;%ta*R8DleF?5r|y*3K-R#Y$} z_2B!E4M3gCG|~ZHzg<&;T8@13rmZB)#BP^K_!z8caQEHkRWzu-aOH4;$)Vs5#T#&9 z$i>BCVkcIm{IF8E@;%gx*LOWL=&9SDR6t(6){4B5N0277MW{Hcqo26vPrtn6v-b!T z)1BtIscDw=Emp)cZ`~Kt`*509d)|ld#Jn#{wV>;ZF^N!!`QQ&|K5_$5T#THt=Kd*d zAOzJDR?X|_q@Eg=sK;&#^RD;4a%_Na@WMOO$fBa4EOf!1u5{;+$iei5_8t@f$Kka) ztM=8LTDBSM(}g7PW<|lq*AYU9>aN&CW|tsCb6}{wle@|6Ckrt>8wx9Zl`3*&Y38rw z4LN{FrTZR>Zj^_1^g2Rgz7I5EgySsdCZ7K3nOSc0Etp&683a;mH7hDXfigEXJyI?zu4CdSyBD5q+D< zGw;U@2vNCkbwOR3g0KE#r5~l|B-V3##bNbGW7EhEC5C+6bHvq?3?vUts}Xp8$Ug8x z9wITZBWP)91Cv=%Kp9}FAWyffOvSidP(<0kM%=R6V%oY?zCfH>W}Ob6Z?OgkCu7|l zzF(dhp_llNvj3LmO(t_}PIDMm%%l5~`rqawHL10pg4G)dl~*jRG(~adjBr`u1v%}w zHy>Z!8D8;*h1a!HpP~1`*NuSeOL~@a!){Ii-TFa}xboKjvfePN;k*Mmy(Q|LsuGjO zcjkXDT;^cS^GCHO#a#DF1V$4t&pyJrQC*cOC+X%WiD^{R>>+Zp5_3$>x_KEK+K>`p zqv=PT7qyNFHOjkmH|O#ViOTDlO(W*T-#$lJ?W^Y3behN4_iIiPq!8qe!D^RSK3K;> zyD@F6v^x6%-X^mB9cohn-*;bw=Dih9W97NJo=a0A^&pvZ7?$?OjlA1+J(;^KYHL`G z;Lf(6?{Q)+V9SQi5b(LH8a5USpqZP(fFoZ3KeI>7;o2;xJF4%|oKf&^YUkXZ)+UmC z{}d|a8IKMDuh+}A>|vOMZhIF`IL7ngmJPtZ!mhVs^O08bH&LhY<`mpaQ7_xyf8EIA8n3}4 zB{k)Q^u3b$rN)!%+9=+Um|`dz;*noAXn`l6=pg?vBj;#vfD{dHzhfWG9gEg{R?(3RO@@2Oy|p?EU|GD z$@^{sO%3p}6_ZT6#x+#&y?20|Yj&xvTBn>RSD)eTvwu@Te# zn54GwN9vohpN3I08$Cly{a5sz9`iUy?2w^Vh)V*H%3G!h+sf56f&qX^+BlIxMwpf} z?;cdkMqq6d?&s|0a}TzUwAno@0G2-n*n4rS_84iF6ohF+-Tht+b5&-Bnd-C7R|#mA zZ}QBe8O_yO!XP-zOTv1i%Kt;zIRs|{HCQ|B*tTsu>Daby+qP}ncHY=FI!VX2t-oh6 zHM95@^DpoIR^40mJm;J$r`mZN-YoB+$P$XVtEI3Z)rDz2ba}BFKBNoEKSem;t z5^X;o(pny$X!VRA2dOZVP?q$66MoYds>RDUjif~X(Oe)n67cnY4r#2Uy929_2^{-O zVr8b{Wx6&XjjL>k82h-2%u6KK0h>$8TxLHPuk;2Fp)W7xwTjOTUCa5W1Vb)l2H4B} z%lzP^_4sOGfFA5L04MbGjvW(vX-@ee7@ojiphj<~Vy>|ev0iUoZ`9>zftnAySx7jD zsBOe54w$5SWLmX1YozwiUnnXK1b-rghv)kWnBty5+`nIxA2`4%O*JL8h!6AK;IUjy zH!8c(ii(Yj<6f<5_wj%tsztdG(5Yf;>$q83A5z#aoDXT{~Iw%W9 z-BX#kyyLVUypM(&9eOiH+Xpe6t=P;wzbOZH;OV!^$*@CzeSN?*9j^tE&pj)b;{v^` zoHuq!naX(Hn6GV+PbF`8cA|_zBW3j}J}^Pf?Hv26=@@zF%d7iW20#l?d3vI zmndx_7ilr!oRd%R+xy&1{r<|}V3Hi&{nxNt!Uzqw7KAl8FQfs=8Yku>3*#FQy#A2Q*K@D|~t1rd~59&=Znsq9^*_Ucc`Xn2_La3GDyO?7nL z+LGODM}_Xk&5n`5Kpyp1V5}4sc8MnX-b&esYE+<^RaESN{*d3(^D1}tbs%d=3U5t@ zOaUd|*6Ggj>Q3=h#t*VQ9f`7S7Oatj1GU}1m-_iA7JSU%&+r_9)Y`PX17CghwlM$p zI=!|rvMPO2#*EKPY~f-m%nT1Ykcz%9VJele>ww+#6N|kb3XXHW`bQ7#xeqkS*BAM2 z3@jy5cCZZXGUKg05$S!JzB;Vmx9(Pd(E}f%v7%(*mJx?RA}0?dyC=<*rnQ!vmx^eUmWFM9q__= zbGjVS1OfiH%Iu`xQQLXiBrnU9S5@N8q8Fm}%!eUInr1A$7dU0o#yNsApxb*DwIZw3 z)bSNd_pPbXnPurh*8`VA`h#U0k*C>ie=G;dma_#3QYzSL{eM!tr zT5>Wig$RD#$Q=VW3RU-4uIvVMVcAqh0z1pG4QB@_TU7L$^Do4rd4gp)V5SZG+dhNA zg5P?|=8EWD8G=gid|w`7hI3`yX1pwyU8jR1JnGiIXl?TF`hWNb3Lwtr_E%W@aLX%3 zd_Xly0GGE7o7QbpZHVBp)`+YL{!6vhM&7&CWvhb|Jxrwnw`zxS19yQT)DQ2_S^&g} z!cS^%RVL<@^5AO_=ZVwH3J*^mh?*g~kY=^Ych}7t4IXuoh_>LKD=TS~buE^mUr4lk z`LkNG#<9y-U!ULDY4u|+i89{$$Dq!F#omh37Rcb^_688{Y`%-Z?5-4Sn0l@Z4M(7V z0uEQWOcyIxX)eK`oS9O;Ow?)ZXG`g=Q#0z+O$eGI%1kLv3>>#|&*qwwdbmc`F%6i~&Z z(-pq743nB0*fC|2!&-o{5globS;^&O)}_$;=1sj3)zD|`i-}fxlRW4Pl}!&}+0cE2 zfE87{x%u(OY5ikAQTmuUWsX;;Ujuvb(Ho|g{~c`e@t$K&JWE_s_E6iB{8DHkKm`=|nx6kme_C9wnzf zp`wkmNdL2g<jFcow`Tpr4xGkS$=ZafzrMo<5j z^u>@Exo!4nBBx-b&3((T+OzVn4a66Cve=0qKu;)U5m1Nq};HSmAm!73IN$LxM1hxV*fu27jEDx zD)uk*Qrr?GM6Q(Jq`wf)uCHeeF%1kdh{CSz5*4t)RD=@Xseq{@&l2E4p%T#(elT}l zzWjH3thWHOTF$e8m*yA13n2eQcWAbzc#gz6yeX8bFu~%VbkTrGSYJ8D02?q6)NRlJ z6p_0H6ergIoh5iF#^{c~2~G9f2XueU2#Ia198kc-DT|7%@E`*883gnL%H(Ir#E6Lq z6fF7!F47qd42{UpfmbjAQ&E_}h=2&-om^SNyWWi$wRxzQ4*;Enx{Z#4cK(5fFwr%* zcAx}M zcrhYm05GQEUso6lz#Rj>&SEfz;W0S}`M&==DLz}+NASS*VOKw@7okpku92wKo%CC1&nuy43N0MjUzyQ>hQoRCa%DcWdnUzp1-&D>MRiS5IFbMqkZ}o z4dgVDEGgoh90Q3K@C*Lg7X4d>3e$}r_g|ScEXYT(k3WEhaFVM_e>TIDvq|%a5P;{P z3fi|2Bl*0)4Ll<&A=t0rP|;AJ3>=_`K<@i5Df`_E=#Q(zAJb76#M7H7C-6%q*?y3{ zXU1um!yDkcAYco3d5wafAGc3u@ck2r%UuOl0~qH362YH|IHsY?pBkni_wWy(V*}Wi zSK!T5Kw#oA|_%F0~q8E z1~|x1rYHo+k2d(LKw*`HH!9(KxyCfrSG7TX-^0mkHJsdTerJmU=Hehw+>gUw5L&P> zBfr<5zRYi)!ymC*ea&xu+@G7E6keo=9lN-l@1G$!$3POF9}vczClTY<`pCfwptl_b z<39v5R)d$jdGtS5s-nV-+zF!Ggx|g~4hUo&2-9*9abeuwME@mPFeDP~N@T!Kf_`79 z0eid-?Ec&vrhvPS{>8<|6#I4?U>tlqNsE%8oV-pS1Pj3jLUebJV1SGvN(x9o+?|V0 zEW(>U;Rpxj*CU0Fg#u>00tb1fbf2$}G`hbp>{0BCDexx^^XdW^mppktX6XL3e%Bgf zPDA_xpOGyt*hi9ML#i!TZF1S>%_d1gxy&BL%HjQXzP8O1h`1wgRyz)%0}xE{`>ly~ zHPnqelCsRXoc%nx;`zBaSJ_Q@_J_JQZT~TYv3TZFy*X{JZ))X(aFU3k#-mxZ@*19v??B{vckTv7B@h2-1!Mp8t_u3(3oyeXmW+fp~jbU|P&pY}n6F zOn?nIV0d|p#D0qLpNRHYB;OVc9F%U=nYz-Lufb*sUojik_Af_zlJg0@I!Nu{;cuvD z8;GYM3iJTm`ApF|x`5mlz!uM<{&10E2b?Yz|Ld5&6RJ&#sver-l^sF-Hr}_NB)=+fta8pO#o%-jb1%7;>v~XG zTl`U&AK&S-iaVyAej~odQsE`wNQNzuIIfJC`E5pRA@a3OQ*D2_Qc6v7BYFsa{$&(n z7+YGlxcTck`lz8yM7^w+ljGob%FezWO}UXhOmvO;#WE z>oBh1W?o)`52_N7eglM+xwdI4nfiKMgqt*lB_q(N^^bscPidjU20VQKdxpu2wyP%s$sLaQ#spQuj#-UDK8q;Px@HSz7N6zQ>HUhlc*br#Mr$notSs z;SA-JXgekA_Q}h-Bq;yu&y46UMtsILM)DLVk&@JX6T~Y~1|@(mm1W6gQ|acNX?AO< zoqHJjQBeNTynSoW5<@LABCZLdqLsUlKqAWX(R2FRA%u|imnxJD1bR^s-(SCatZOF4 z@`C=6REB6fJ|z+@SluqF)pr&g{4e@NgI0%Y$)S1e`In2qD!<6_=Yf=j!w5J)#4E|M zR4Lmu#cJi$5MgT_w5jnG3Bmq&ffWtg$(CMmCeShMVg+2!2^C7b-b<~N^C~)@kPh@} zG|A}b*xG)`zm4bte5s5|C1-dEc|Py4Nek&cu$`SaSQ^H%CQsLz=mkSEydgeKyINgy z4r&tlw?j1QuruviEi%BkqBIAF0DJY91U^5_Z%v9PI|g}45wCwl?~Frd8@`v{El$N zl+r7n_t~p;Pc0YZ3Dz;fiX4oz=XI~GgOxN2Ebd8b@ zi%xE|@Y6joaI&#o=$^vr!!L_6`ygcE{%t!Ao$TWSa?r?_93RoVuwcb}*~UmSP0Kv7hOPBbLz1eeJ~h^Ut0d88S<$Fdda#_C{- zU9z+b^(;@un?koMZ4XW@0BRgn+&Xy^A@`o=Y{>FE5xtl9y93LCh<2mnA;>G#VOx{* zWaf9-6kf1GOApjX`E(%oR|O8UxBt=@+s~mkPH4|zI41!s5NJiP%=*Zyv*MI}1iTuI z8PGe@I}ZFKD0!Yd6Uw*y<`B z=TwJP^7~;VN0g5ix|(>}=y&50?b|h#+6>|ZJqx_Nc`%GB5!#bJTxfG_-9sxZFSX7( zV`HU!^^>`d7pqp?SEr+1ushAcYiyqo87UE5HBEDMuEA_*{7F zp5SP}CkJ{&zMT+%yNy=5YOc6FouGDoeyE;sN*lJ(iHZLSPIl;7>3QGI7ZeQ^#`yzP zq+a8Gc1s(DBmEF@0;Mb7HkrH<5~8QJ$MtFmBLMBHpjH`ym3ji{%gN!$ua7Y?rCdPV zC?w4&BaKY6SX9u)YHr4(jZ?#WCS2=VZi>M}d#@XBdDC?Wt$8yNbBUhF;D^F@8Jw7! zG$mAHvS0_Md>T(s?g2HTIV;>f=6#Y4&A{1D#v1)%Dnlwf3RbwIU574e_3MHiDo3+R z4lkuFzwI{_RrlA1M^+ua_TLfueJQ;G=AwZ`?`Cq3@5k}WYYh1ukuA8UyxIyHSL~S$ zT%Lq01vBk(i>Frdxn&Im&?Ol0m7-Jwv2+P(zzBV$I>(K2lCny-05y+PRQjjp<2&cv zL+eCD3I4gkVj1SolF~IzadYM7ob4aVe;EO6o6wVc`WtRvrP7guIMZPJBK{o#0__{C zliYkvWRFoQV;w~o^{LwB8o_o?KG(7T2(o`*Tb-cWRuFnpxQ^wH6igrI{2N%NU#1;lSNLZd8_#(pV_iNiFHkbuUw270kPpHdsXlU z?Ja9hXg$-&*lccLFJqyM@;Z|(Nw#g?)|jf8S$a&TB?(Mpjn5cYBHs7Ob3NV3MY)~X zDgI=4rs&1tVrYo8a~*_xtJAI#=xJ7NpW|;TSECbnbGrjr6^Mx|)%1FLk06LY)f~-L zlD%-Tc44_KwNdXcQQdn+Pia)xZOk$!{XPMK+j&p z7nKWt1~6D9s_+!%IGPw^XI-#ljsl;#7bBZ{?f!lc-MfqgdEcE>jb3xzZrHybgV+u- z{w1#trw*P%-#6fn1NZcQB(+|LcttYwzKhMOO8&VSnKVJ`)6hH-04Dsp`d` zX7RT@ZK7*XblOktcTcmiOTx!^B2!+G=3qvv`O_Jiu9tTZ!Yt&k6kKvbLco^DjV?FaR z4h3K|;UidA&`sHfS(6rFq{FKvxnF-=cX2x6ffE9%e}J*FArX&XAc&}Wc?yX^Mk85`e`%mIzwD&J8UQZLy^(w=0Y zk~@mM)iLFzD{GMW(lGj=zL{i!ikX>hPU=p%V*%7(alBR&t=-DfAEYys#1%d!-9yWE zfojrZwM>U$7>Z%(sACqPL}cE;Z+!19vorJ$c^tvSchK=3?1^EYlW=d?As>##U!_to z=~|20zBkuGrC2qMIMe0b5wiu`zxIdx*!)*>z-haGLzZYCt{q@^vN7Ym)F#@562Ods1rPj zvbInNn%(j@w=%B%3|eiaTcJK|lvMX=yhgK}Z7-XpY4LSsJBzrdyUJcGeYkGf^UIS! zXts=&6Ht)W; zbHg`#RS|ZocFE+e<>ZEodZ;P_zCq0X-6mJ%O^sLLUd_l$Q=#8NM&(U zG0b~suA{?-Ht90?%@nygxe@k~dr7TjeI>F@HE*wVS~JLlqYqsdS$e@*@?wn!S)Q+h z;ozaUs$8f}q7v)i?F7iI{Gc>s5c0BeGIM(B60q_~b-bbo{Br@Ge#*mP#zMT~ZP!C= zm3GWmY%D`vpwM}tHY?c+2on<)hw8KdFpdeL8oZ}*{&-B-uOXePw zK6_~;Y42LM;btxY4*YLBc!UTqMK*}^FKQzcg5Y2C3R6(~MJOj5shOys8CC(p(n-dz zS?+NHY9K$uM2Deg(GK!>9-ayFtH!b7Ho&>&K_}MoK4j?#ADc?CNc(BX!+R|!OmM!Gwd;OL$iP^X)O%wC#6CvFsB!T+J`cJMOe01 z1)6dbSb4p!@24oW`56Ux(Xdx99x|v%y_v(6IdS0HkilPhpwDfiWR7n0Py5w*^Bw!S z2#%W~+_K%4pve@e(UbS`fJ#JB%fYVtP9y`_;!_xfnpr{;HY}F<&B+oU9NJY*N{L7n9i zco!FnmRm}_|6V1tat9kY=4-UYu*GcBq1nBrEM1O&9=o>#y-V%{vHh=TtCBvzE9D1c zpQ72V#>_d+-c^LYJwLHg3@+6|*pA<>RS^k%iAQEbfUUe+x-#4GEBVanip$>bS!l8l7 z<=&%{XTL*mtgf&&+E3(nwYii>&KU}txiymaJoZI;o=4Dy zerw-V2--wyFB@R%lX0r*reP>&-VAG&k|WulOQ7ynX+@CcU{nQEp^c&u217xr0ySiBea#(C#2<^ zFi5}wT20yRi^h+XksoHG7$v3j)bUB#dZ4KXr?b@W_8T5s{$gC2&dQVSgkQM8w|*jW z!9rI$$x*C?B>IDHd>PcZ7h@X#Z}cr!C9hym))y_v!)h{g>kP+vFAbcGd=LBaW!DZN z5nhtWhi9X>DJiE^GW$qF3eF_dc0_0TPO(EZhud318zIfq6LTj!sXzf@N3eb6h%!kyi>QGA4sQMJ{A zQ9a?l6W;uL%zfGm4qIA`M#StY`~atrKkh7gS(WPfsU9_VViCQS8bXSQpBF4><%-3_ z_@f|kSvLaENKy+jFI_P?BlKaOA690CsapUoI3n_JC^Ipijl}-L$r6v>T!3h$0&$ckP)p7t)K=RKaJFubFna z=bfFQG@13dsLkv98>y>M^$6DWChWX}$Ul4CfA0e2VGa4gPnM~#+B+R-x-9lN z^VuA1jiJ|6J0A0szY;NWT;CzHgpC`I-j|_^Za&O76fl#A~F56lXwcEs@RV( ze5I2Fo`z^LND2Foj+AEB;}yjL!kMK_#tX^DEQB^m^S|>h<))V&l^R1Tj20pe>*2mL zFYcOZJ>Ka@TM3qgX+t&k8Me@Rj@gYh{2k`!c&;%HU2t3oVI@{%u(L#2HZhltf*1Y& zrbn;4UoiBf?_KDa$ZrbFp|zo;sGp72cv~Y}kt3HaE$(&7dz7@D@^q_aE+ROX+r@|9 zrCsaw6WLFZn;aOC^~oV`O~GYT|BgD<^CsJ`4&LPYG|ms1aRp7EZ|q!arc8Ck@U!8h z%1K4mlZcwn(TQryQT7~u#$LE6Q)tZ-`;$!(FAp`PXX|V5WY9sW7gAAFG|}W7Sz9l*C-$&KHq${( zA|B>y!~RyTS&|Q5YJ&wVr}Ax9Zz_yOxIwl8w&tGvOgOr2)Olb3)-`4P`G{|wObqoe zTKfiTT!dy}#c7uFMJy#W*Yqb(Q`Brs*!FRz!RO@;r_3$qV@}{x=82Y5Ip>jA3C}nu zH?MD`1pf)81*4TE={||ED%6Ux=mJY8g7Qeg81l<7M?U-9HXrZ%*I=Iibse>OXLD%@BaV2-{cxF9v?W|L z$C*?w$-((K+nUMa(Biy3AYE1)#yz*Vcv|Lt*pf!poA@$x0t>$QI9 zR{`L69Q?Wte+Mg;75|D(Qd{8;8nR0*lyV7vkUZ2%DmR~n1-3=!lX*7U^qF#P#!7pM zn;a|qQVuuau(RMN-@`8{W0T81H831m#3$uEF5Ind`9wq?AWb^x*7=0aH<*1`B{a&{ z(X53jd&!lGa1UoDI=vFny`J|S;3?`E;W@u$yOT${us?3u&xkXU@FJ35MNI1K%$ki| z(=@@M{LH_pzL+hY%T9o!@$aA)P|hok&1mYWt$GroO=hl&cil5-Y;nP7W7w25#58$^ zL`UHxezWPWr)mWIptKWnh%W2xz*8WB;zu03;-#8%k70A$N~`|(7dk+-P*17cRmY)9 z9D)R?ZQiwMj|>qVj6H=|v#d%rZqr4RsW>|Bo>PFX{Ok{Ywm8TXj3foMb`D=Wqct~x_WzBcG|TZ%nG z78*S0W2oPJC~q1|UO0Pn0VkW}ny^6%ynb`VxxSy|!?acv4-c3-bUWW^`BVC%V^|Gx zx^-6)0n$1aU8L7j0w_q`@FBdi<^e1^*GBtmZPqR$h$C?8JQOXmZE1U7yFo{Ah2=XY zLQWOM_8FxI_=e|f9;CyEYW?FHh9B+x(54K&>yy+aQZ8| zHy2SZ;D2;efgi#*2kQJJd>0TAFoA-d!rwl=%lGmrlpGy_Q0=0D|MXw(K`#1>_XQcc z`RCRj#|L=>)BaY!M}Y|N^ZkA@aV=$}MBcmnvVXrpiq1T>++yjb_$)v4$5K^E&;!!v z3aCh#PSqhJ8v))|@A~!n!xBRT_DvD{u-K}Ck_JQ|16AnJE!qJ zPO~=%1oE@mNhX19;{8PS?XUJ>pZ=3S?l1bL@A|!iW!b^Q^V0_NDf;SviHOnB{Gt!* z>TZsC-UnsY(D$s0@GBGm_-uco|K-#QG70H@;@^r8w;JF*P!Q%2Q#+(j{T4e^H~b^7 z?;1jf{BA8xT4D->hzh+g3*D6z6w<=lul{M3TfkVqLk$)Ij3hCg3e&%WcYx3!TqNNi zD}qcI=H~p3f*^J>SjiWu4}3B-~6 zma9F66?W@$$aZ(aOOrY0mYBRE}PxHEgOJaYDmA;XkK2X z{`9fm`JFJqcIy=y1HbNhS7DK2Sz@ZN$7vro6AeX9FBC(G(};Mb&QNtXRLrzdQz#98 z#c8PYlS?__qyIn_d72EBAF6}`<-)^)(9DH`^G#&?1DRhxY1YJkkYca+?X%XR4!Y5p z>2u6RXivUUZ1Z4gB_9Ng68Zqvt}M!q|u7mx8C zYcbzT%BodRhKv|beQ}Es(4=Moi!Q-m*JWgRMXhk)iH_K?IM4i{GF6U;GF1@pyGP#N z#?3|ijgFVl=o^`|<^dgf5Vm^1UxGKAQrA)Pn&rEcv*NCMB-oNK7Vg}Ei9mJK+Acrx zmB++{#JK8q2#d8C89gQWmBb#wGfAuH1Jt*G(khgWEBYCl)gWtIG^ZtbJYrY0hiF4D z=_Ik!Y-r{)zjzTB;rIqr4X`szKtI-!{exj3ST!H3@5Tb(UL|)>hWl9fDW1JoSC#DM z{T)dB*O5-9tfRN{uH>DN<9rpIXNJ)LJS7|>x2KsH|JulJU37wKFg8-TDlYmsrk;h& zxK8aG6@HOV)bz;43js^>cP>`Ua*Ez|$11>Pp(s*;k1#SAKU}@J^ZQ)0vxZFZXrZG1 z+CNrciwgYcHzHbU92DgD(6Zh`=&-Ddg);rjVH?F(R5+t*QG!8k;O4niR=(GeeP0c; zyEXkKYV)>$VBPkRoZ4$(MEqtUqY^9}k@89YbF2)C@EF&%5#$7Xa3Zw2y-W{mjNK!x zcx=33Z+UT}mRYU^`>~Jzsi4HMn~gDSi0>mI$4E5ks1nJWf|js#T-MZ@aWzVQl;3T4 z3}_L+Y?rx)+OHw+R5eGO@w2*q6{SZ}-B(`gmeE5BqMG!sBHFI-|L9z&M~Q_WW-oVpd$nU>(AS?iOZcwI>O2K zeF^FsZkNrLit2Q2Bj*pyuw6zm`uFD^PxyvOpIH=QvO$3`EfYq@#ox9=S;t)v$@j%~ zZae(jBg=RhH#FNl!6<}wn?%TeTyPfd(3NzrUT&zDAAOatxflVv{UfG~l}~)%5{Ydq9~})`?WQIUVcV zog~W*==@bowlF8Fat%UJbhEyxh8AZf!L{nh7b6+a7Qpf3oxQyR6~i(-8W>W!&IubF zi*J9FVgC6-OD&JQSy7HqNt-~?9Dg?4v*F`l~EIja{Ie$_I{2p$f;$AAb`(H&ARnmH17)kT|fyj=#C zKr;R38y*GN-$WlI0f%&1H_2vhVq>G za33P7H5?YyM;pI}2q-U=CIc5*Dw@~EN^k}V*p1AO^!=wmQ%y&?o zwpMfG1iqJ1oAZMuWNXJ0QIQr7vo}BZy>vm#DZ^Tw-3lWN+GnzdH+F$@Q9HV$-b$bj z_~zP^XsSZC+ab9dFxB+#_Z&GjIu!?;^b>zq z-+`vn3QeUyr!z#I;gi3-m$Z~)PnV}c(4<*Tim(?+IrdtX#wTEAX!3MTTAm|*+yqmQ zgqS{|?GMiu4C^VjqCSTzIX^r*8Dtx2*keP8A64!hL|d2BfOz1G9#g?#>l&KdYRdTf z44RSC>-(@Sk2>=fae&%I^(MtFy+tHEWs{N7zue5I##6rEO#^P?^nJV09CMFFeWK4G>`pU|uFAVVY7v`# zM=mSE`QLYEFh|-Uo%G9qX@p+G=s&W6q+#4nqSYN0v~i$WTi%lq6_R?4ZG&-Q+@3j> zxd9T+y{|%fIb)5tHLKfCsgX@STh?4zZI@*|kUOG$LCV%Q@&Vcda#V!b8hd-JCVD41 z51xGo_$e7A3VkML0R*f)Lrc!`1CnP*Q=?kTwz1SXQg|_ zarE81>S@>gl#>vx^)Od5T$quQSLk4pvitettV@{PF3?UGJ$zwkm~g_`(rfE1`fmW+GZj|l0t z{+pBsNPbTJ6N<;fjnd-yXiDlmNYyw39#bC~iXzL3AohO?Lj%TLi`>9yjH?nTs*#$W za`m~;x^i7K1o&HWT%f}luh>kpTNWG>=&z~tMQ<(0%Wl)BLgi0-(r40$J5jT{z4b4AuQrrA0w3vD9Q1Ym! zjHCJT9KJ2~a$sRpaO1Y2wEHqzU!3cFi7Q@WWQ+%IXI03o=VNp{ZU4}$W?|Vn80-En z*AR(fXSst;Ij1?gnj~y4McxjHLSPc2E?YdX+SYrFEZ)31LBn~2H{q|X<-!WsTl3LTEynWwO-PZ_uVMewSHHoZAKf`xfzHmVFd{I4 zX;RYJt>;Xa_k08c@>d($EoU3y_boFF?-4x6>UVvsnlYQ*Xh-Ub$*3hH0alXBKr=%t zd%-sd%}-rB%3K~QL=62sU*owZ-XSvoK|=X3zL!Bc~kI5{_S`OUSbC7hg=E zr|8h1%ATm+0*W`9V3(&XE8)aymC(z-)<{N%kvzqob6Ij znWp~rW68QKC@(XlXOUf=u7__2UX0Eq-NiOn_ywKqnp=alSE+O1;pac`h)Li}i6&~o zOZIMQ^;0X)K3T`14x;Jir9%Iqz{M<{+K?~xXwzGj>ovlO=^a5S-hEL7lucrSI5AaF z;r*%?kb0Z{$|LQipJB%v+Dv-&4YCf7>i@JG4SSrYFg~|KXyeD^DKzc9KZo*sA`T?8 z-=71=C>O>R&QAFqjsdGS7AQR*zOskjoxP~vd`H|K@Yyv7^G@UYnZN>OT3V@hfij4J?hn955h z5(g%GaDfXFO*04=*DU(CfMx7THJhmN^_~rpD_&$Asb6zi)|c9j?%X+iROCtg>!96* zL}#IRNQXD$I_ZSMwox%GA2$T1#ainEdD||xbybvfH@=xOsYWwJR6{#P40>Yr@jc1* zeSjE2atC&_1foyh9#Dse_5!Pz^_h^)A$ew|p{w%=V0OE3g2KI3OPTu@m=JeB+Hafu zpeGXitB%|SUJofwKg~m`y{F@{U?+mUintwVba&Ib&Y-6;b7({67<7A76#Br-LT9QU zgcaQj-H0@mJnXhxM=Slox(YHe4S)97qhN04epE_9y)g^LNRfUW#pxnRTYUA+-d)#D zk3aT^Bqzzr|KTwPyiwfXinZyjG?^HXzk%(iF0EE^Wvd90mjzXuQSrQO@P1T{(Z7Fb z=`e`h7)<$7W|N?7zC4s*ljN;@0X&pRw5)92PN1AN?5u5zqcsOe%M$`liAwkHfEgT2Fjiwn{RB z`hNQc!at3T?Gh)zMWn_3+LE!jXvRp@giU_L`94$PDwK0hW&4Zv6UPHcU`Yxk(w}1H z{b<(%lId%la3R3hJ$~upI0-~Gx6P9XH;g#NS%~80B#yuKoWDHrqI`ADuT06>pQbgF z!i!`Mo6AnQmQ2dy&@PINsJDS2IAvQ`e zXwZ?$y{qJ-7W6BHES116kv!}w zTP?=S_CG8tJX!>6$# zuR~5g*G{^|I-v}_r4=6pH=!%F^Zr;e~O30@0ivOnMee8m5$K~>X!Y!*$59%fOCV&Youq# zZV4gq)2wgT`E0UE=Xw&PccK~`e^jSAZ=3T(VVUgkNYjP5vELBz16Bz+=2q2m`5^pl zChXD+U06in9ABL&Rw`CXu~t*Pv|s4v9%_Qxlqqf-?d3GySGtg4Y}*BlaL#I0JmX)kkPfd#ms;%rSaL8MiU_+s>M}vy<<;kKeb4g?AMio5p^#MB^%%#B;~sbO&4aigwWl zl!w8)TPMw(JG^+C(AMBGe#x+qvSF49{_*gpq)}4aPdIwllhisH&lsKKI5sx{)*qn- zxWOx>`h&%wt~r#I`rle=>^v5xq8_-JVxNgq$Q>zFe7}m>t~20eVpN1NU^bOGwWlP= zfv~jS^)lD8kE>F!tQOnjWSh=qQHM5ml+-^7N_sbn%bM()eIW59RJW^}W{BAlbs{uE z@$029IAk6K_MHF8%NIgs2Dl0cW$PDrCV^z-A+v^%fjfZl!=dNz#Ir;^#4=CGVEc~O z8!JC7zxW_Y$Z7JWKmR@i#}IVgld3f~!+=XKPM*^>@0Kd=g}{7wHYZ*?Nt~f=sNmh&eESks4j0 z1iBnotn5zaz`Pj&&7&>jgxCGyLZQU)mq>^TBZzK8DdmLW!0V&+v-Mqr!M2Gh)SvEa z3uZXmH`R7uT!@~K>XYqwyiP8R^#MVac<*h*)=s`+KPRk|xFp?iUeKDHH}laecaq<>q+h}WFMBp*7<@I#rP`L{U35Gm#DF}` zT(#^Ryj@-Uu~>!V3}FxYetpo~>t~GafQXU!TmG_S8y@z2%H5Bj9{w4Rax<>kA8`iR zymA_5P6M_fr8#uqi4bQX_d!~`eqxv$`}MeN`$m;dnUf}*bNzT-&~`D zJ&)dp5eKl7LAnVuc7jrfnXph-C43rC!YstaUC3|U@5H3(hJar?f!NdZPK+xkmSPJM zJ_qR>Q=kd&myao`^muOG)sHoy7!jb{A^qosuWdvzU=+aY6#6{2#ozsiG@1`Q1hx%Xc*aN`d_V2>r zb~dsL4ofn4(Phyxg)}RtHM?qPBA-g=s4@6mBI| z3=mbLcr&=RP8=xe&pEIL*NdcXO;Lt9>|9hfHPxn!Yk5I~Whx$O&kiK^(&sKz%ozwM znGXQ=VzzkF(FQs==wvPGzdUB0Zx%GX8~~&2PkHEz)J|y>0T1U4&h$lg_Kf$5WyCMh z9Cgdae69kEmH-FZ#ThdBc9i5Rhp2Plha7@PnZ6o=BzESzX905#p(b!@a+M>qkLq1a z?O<&|dxmToG-GSO9I{>q5>~wTvQRJw{h=NoX|YW)(;0t~#2nx^C3;E$s2X~Q*x1&D zY^rm~nqxZOT@K<&{9;UIs?3G$G)M`IH3h#c5Cf-t;hqw@V55)RzR%C!5TAj=^2`RJ zi%j1ql`wL9Pg}O1xfGJR+BY))>>9MoNNooxI%(RItl}%Jojg39f_lz-0Cn;0{O>o5>WIy0`j&V}K_JdFXhJ!0_l%x06laPz27>F72o;(1BlRSAbtA=vL`0a4Ba7Mgp6Rjg z7;Ofv=woPzL?XJPCbVLuU5GaIgj||PVv~xA8{Sw*Yg*_6EnmwtGjkD8>d*bRks*Xi8zhKn5Xb`z5+w5?qGi`2oC#U>!FCOh z)Yyg|5KKGZ=i&>?Q-&z71{I?0hIzx5{UDJKRnvt5xaddd5K8g;*m%3}b&@A=Jb+dv zA%c-r1zSR-2O{aw#7h^;B1q6W!J}1-j=6kN>iWEAEm!)s?K^dxIdc~jg@r*Q`iZPX zN#Q0r(%mFwVZIx-^wB${+@T%^zA=$h~-8o3b#fz3a4d*|pBHXQG4Gw0{(YxPCImp0x}R zEGw+g@^vqZfrOs|6E1Z_pe;2uO(2RD@oT2W6$H_}M+5=TAX$!XPDMq~5c>)uklqfm zPfEOfo$7*bKs`I3vHW5dFLJ2(Kpz=Oe-IW*yh?PgLKwboPxfd8{E7X< zoNsTTX#LRTBPybLhuR{Rn(f;LxRz3{oJcL~oE)`7l+|alH??kjYeSc{R{oQe-|8Q0 zUYHlw1aY+Pz-j@_H6phk51oFCopjf&oH{t&!0l#DmtUL?QBr*Ko;?2cH- z{ig7zm^TnR=CSkRVtDGAyy%jT3!@01ISWIZxtYmp5Fe|lbCTta-oQd(Su5`0i^Kkw zlfWcdr)ACUPbE)RcFN<;DL6Nc%IBAJr3U?F14lNG+8(-@x(xg0YP435Df#m$^4eTj z+O@o7DEVyNwnlora=w4%y3wd58F~KOzwvQka(oNy+k4H6S@+0=xuRIIEA61UhS@aV z_pC?S1A&Vz@7C3-+R~6;ZfOpuglzOuJ=3*&mhM+7 zn(;E8_vNgWdNNSN*^azzHqh2`Lg7vR;N6_BEE+r=JN{jHzQMO%(~U+^veuqG*u^bc ziG`IP&CLXDk|@0Qtb}b$EU5pW%H|O;Us5ag%b@Ewk{d-cG}RXbjLjHC#Pp@;wm#0W zg$008EdxHe9e);cnxeEi3XZ+iHZ8%Tn8a7|-8;_U9Y@E=^fF65#TI*qbn22$yeZWlZ@2kInSxR@B@Se?O%zRIGn-yygpM5y5~ zErE<#KVi9LrI9j)_&XPY37XxAoD?*>h3ba;FD^s!PZhi4s=(s?X-(Ir_ZPi{R>Okd z(xXIme~#$d!4XI76@)YM;?lz@+YJQUC~;h3`_)WYBVLR-rzw+>+ce|xhsx#=jSJPc zWPC!O5i;%{YsS4j8l^<6H~MQYrY>3b(-QI9lWeb=PQ7JFHhB{JIDZuk?ps>e+e98( zP7wViT@N4EeIIzuFsLS(&px_iJbkxS{}oRkV&dgm!G0VG zz^QG0zj+E6!2T<{+S+V%?e$mRfE@5yl3iVzRi@vfY;?!1!nzdmt2e~`iB&-cV@R=Jm1LCevy;Owa4 zxb4H`#B6OdVE?U)2LHnrZ||(*#k{#YDFtzAvaV|!=YZ3lOV%B|Gtc)7RMBoP52>1i z&a0?~4EghB9+*>WyKF&r^#gt#%`mmHvXp7-hv%vF#?k5WK9C}2>vk8oJpd7#o*VZT z&A;yc&a+iH{xv9h?FasqdyiX}AYF9h?%o^{*swPt_0%7mNotfx(tM=0_o}Av0o5-N z%W@1TWKl#t{{X{AQ%t;70iD zW9_)?{g>nmT5d->u93ArUi)you&TAabYjOmY;Zp$mat%-pk=(?Ko14(dnadIO`z1o z-;OXg zN3n-2RqzjxvgxH#{t}GN54)H`WTUIY)A_jknHL?YU�FYRkCZlZE&@3ur!j=l3Ok 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 = $data["file_id"]; $this->team_id = $data["team"]; $this->tournament_id = $data["tournament"]; - $this->dest = DestType::fromName($data["dest"]); + $this->dest = $data["dest"]; + $this->round = $data["round"]; $this->uploaded_at = $data["uploaded_at"]; $this->version = isset($data["version"]) ? $data["version"] : 1; } @@ -207,10 +209,15 @@ class Synthesis return $this->tournament_id; } - public function getDest() - { - return $this->dest; - } + public function getDest() + { + return $this->dest; + } + + public function getRound() + { + return $this->round; + } public function getUploadedAt() { diff --git a/server_files/classes/Tournament.php b/server_files/classes/Tournament.php index e404e7d..6860bad 100644 --- a/server_files/classes/Tournament.php +++ b/server_files/classes/Tournament.php @@ -12,7 +12,9 @@ class Tournament private $date_start, $date_end; private $date_inscription; private $date_solutions; - private $date_syntheses; + private $date_syntheses; + private $date_solutions_2; + private $date_syntheses_2; private $final; private $organizers = []; private $year; @@ -98,8 +100,10 @@ class Tournament $this->date_start = $data["date_start"]; $this->date_end = $data["date_end"]; $this->date_inscription = $data["date_inscription"]; - $this->date_solutions = $data["date_solutions"]; - $this->date_syntheses = $data["date_syntheses"]; + $this->date_solutions = $data["date_solutions"]; + $this->date_solutions_2 = $data["date_solutions_2"]; + $this->date_syntheses = $data["date_syntheses"]; + $this->date_syntheses_2 = $data["date_syntheses_2"]; $this->final = $data["final"] == true; $this->year = $data["year"]; @@ -224,17 +228,41 @@ class Tournament $DB->prepare("UPDATE `tournaments` SET `date_solutions` = ? WHERE `id` = ?;")->execute([$date, $this->id]); } - public function getSynthesesDate() - { - return $this->date_syntheses; - } + public function getSynthesesDate() + { + return $this->date_syntheses; + } - public function setSynthesesDate($date) - { - global $DB; - $this->date_syntheses = $date; - $DB->prepare("UPDATE `tournaments` SET `date_syntheses` = ? WHERE `id` = ?;")->execute([$date, $this->id]); - } + public function setSynthesesDate($date) + { + global $DB; + $this->date_syntheses = $date; + $DB->prepare("UPDATE `tournaments` SET `date_syntheses` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function getSolutionsDate2() + { + return $this->date_solutions_2; + } + + public function setSolutionsDate2($date) + { + global $DB; + $this->date_solutions_2 = $date; + $DB->prepare("UPDATE `tournaments` SET `date_solutions_2` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } + + public function getSynthesesDate2() + { + return $this->date_syntheses_2; + } + + public function setSynthesesDate2($date) + { + global $DB; + $this->date_syntheses_2 = $date; + $DB->prepare("UPDATE `tournaments` SET `date_syntheses_2` = ? WHERE `id` = ?;")->execute([$date, $this->id]); + } public function isFinal() { @@ -343,9 +371,9 @@ class Tournament global $DB; $req = $DB->query("SELECT * FROM `syntheses` AS `t1` " - . "INNER JOIN (SELECT `team`, `dest`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `syntheses` GROUP BY `tournament`, `team`, `dest`) `t2` " - . "ON `t1`.`team` = `t2`.`team` AND `t1`.`dest` = `t2`.`dest` AND `t1`.`tournament` = `t2`.`tournament` " - . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $this->id " . ($team_id == -1 ? "" : "AND `t1`.`team` = $team_id") . " ORDER BY `t1`.`team`, `t1`.`dest`;"); + . "INNER JOIN (SELECT `team`, `dest`, `round`, `tournament`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `syntheses` GROUP BY `tournament`, `team`, `dest`, `round`) `t2` " + . "ON `t1`.`team` = `t2`.`team` AND `t1`.`dest` = `t2`.`dest` AND `t1`.`tournament` = `t2`.`tournament` AND `t1`.`round` = `t2`.`round` " + . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`tournament` = $this->id " . ($team_id == -1 ? "" : "AND `t1`.`team` = $team_id") . " ORDER BY `t1`.`team`, `t1`.`round`, `t1`.`dest`;"); $syntheses = []; diff --git a/server_files/config.php b/server_files/config.php index 00b9ff3..7fba1c6 100644 --- a/server_files/config.php +++ b/server_files/config.php @@ -25,5 +25,7 @@ catch (Exception $ex) { die("Erreur lors de la connexion à la base de données : " . $ex->getMessage()); } +date_default_timezone_set("Europe/Paris"); + session_start(); setlocale(LC_ALL, "fr_FR.utf8"); diff --git a/server_files/controllers/ajouter_tournoi.php b/server_files/controllers/ajouter_tournoi.php index 4efc6f2..6618de7 100644 --- a/server_files/controllers/ajouter_tournoi.php +++ b/server_files/controllers/ajouter_tournoi.php @@ -30,8 +30,12 @@ class NewTournament { public $time_inscription; public $date_solutions; public $time_solutions; - public $date_syntheses; - public $time_syntheses; + public $date_syntheses; + public $time_syntheses; + public $date_solutions_2; + public $time_solutions_2; + public $date_syntheses_2; + public $time_syntheses_2; public $description; public $final; public $tournament; @@ -72,7 +76,9 @@ class NewTournament { ensure(dateWellFormed($this->date_end), "La date de fin n'est pas valide."); ensure(dateWellFormed($this->date_inscription . " " . $this->time_inscription), "La date de clôture des inscriptions n'est pas valide."); ensure(dateWellFormed($this->date_solutions . " " . $this->time_solutions), "La date limite de remise des solutions n'est pas valide."); - ensure(dateWellFormed($this->date_syntheses . " " . $this->time_syntheses), "La date limite de remise des notes de synthèse n'est pas valide."); + ensure(dateWellFormed($this->date_syntheses . " " . $this->time_syntheses), "La date limite de remise des notes de synthèse pour le tour 1 n'est pas valide."); + ensure(dateWellFormed($this->date_solutions_2 . " " . $this->time_solutions_2), "La date limite de visibilité des solutions du tour 2 n'est pas valide."); + ensure(dateWellFormed($this->date_syntheses . " " . $this->time_syntheses), "La date limite de remise des notes de synthèse pour le tour 2 n'est pas valide."); $this->final = $this->final ? 1 : 0; @@ -84,10 +90,13 @@ class NewTournament { global $DB, $YEAR; $req = $DB->prepare("INSERT INTO `tournaments` (`name`, `size`, `place`, `price`, `description`, - `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, `final`, `year`) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + `date_start`, `date_end`, `date_inscription`, `date_solutions`, `date_syntheses`, + `date_solutions_2`, `date_syntheses_2`, `final`, `year`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); $req->execute([$this->name, $this->size, $this->place, $this->price, $this->description, $this->date_start, $this->date_end, - "$this->date_inscription $this->time_inscription", "$this->date_solutions $this->time_solutions", "$this->date_syntheses $this->time_syntheses", $this->final ? 1 : 0, $YEAR]); + "$this->date_inscription $this->time_inscription", "$this->date_solutions $this->time_solutions", + "$this->date_syntheses $this->time_syntheses", "$this->date_solutions_2 $this->time_solutions_2", + "$this->date_syntheses_2 $this->time_syntheses_2", $this->final ? 1 : 0, $YEAR]); $this->tournament = Tournament::fromName($this->name); diff --git a/server_files/controllers/equipe.php b/server_files/controllers/equipe.php index 9e9a2eb..d50748e 100644 --- a/server_files/controllers/equipe.php +++ b/server_files/controllers/equipe.php @@ -37,7 +37,7 @@ elseif (isset($_POST["unvalidate"])) { if (isset($_POST["select"])) { $team->selectForFinal(true); - $team->setValidationStatus(ValidationStatus::NOT_READY); + # $team->setValidationStatus(ValidationStatus::NOT_READY); $sols = $tournament->getAllSolutions($team->getId()); /** @var Solution $sol */ foreach ($sols as $sol) { @@ -49,7 +49,7 @@ if (isset($_POST["select"])) { copy("$LOCAL_PATH/files/$old_id", "$LOCAL_PATH/files/$id"); $req = $DB->prepare("INSERT INTO `solutions`(`file_id`, `team`, `tournament`, `problem`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team->getId(), $FINAL->getId(), $sol->getFileId()]); + $req->execute([$id, $team->getId(), $FINAL->getId(), $sol->getProblem()]); } } @@ -86,6 +86,19 @@ if (isset($_POST["select_tournament"])) { $tournament = $new_tournament; } +if (isset($_POST["delete_team"])) { + foreach ($team->getEncadrants() as $encadrant_id) { + quitTeam($encadrant_id); + } + foreach ($team->getParticipants() as $participant_id) { + quitTeam($participant_id); + } + + header("Location: /"); + return; + +} + class EditTeam { public $name; @@ -136,4 +149,25 @@ $documents_final = null; if ($team->isSelectedForFinal()) $documents_final = $FINAL->getAllDocuments($team->getId()); +$emails = []; + +if ($_SESSION["role"] == Role::ORGANIZER || $_SESSION["role"] == Role::ADMIN) { + foreach ($team->getEncadrants() as $encadrant_id) { + $encadrant = User::fromId($encadrant_id); + if ($encadrant != null) { + $emails[] = $encadrant->getEmail(); + } + } + + foreach ($team->getParticipants() as $participant_id) { + $participant = User::fromId($participant_id); + if ($participant != null) { + $emails[] = $participant->getEmail(); + if ($participant->getResponsibleEmail() != null) { + $emails[] = $participant->getResponsibleEmail(); + } + } + } +} + require_once "server_files/views/equipe.php"; diff --git a/server_files/controllers/informations.php b/server_files/controllers/informations.php index b45e68a..cdb0047 100644 --- a/server_files/controllers/informations.php +++ b/server_files/controllers/informations.php @@ -23,7 +23,8 @@ if ($user === null) require_once "server_files/404.php"; if ($team != null) { - $documents = $user->getAllDocuments($team->getTournamentId()); + $documents = $user->getAllDocuments($team->getTournamentId()); + $documents_final = $user->getAllDocuments($FINAL->getId()); $payment = $user->getPayment(); $tournament = Tournament::fromId($team->getTournamentId()); } diff --git a/server_files/controllers/mon_equipe.php b/server_files/controllers/mon_equipe.php index f83957c..e165dcb 100644 --- a/server_files/controllers/mon_equipe.php +++ b/server_files/controllers/mon_equipe.php @@ -47,6 +47,94 @@ if (isset($_POST["request_validation"])) { } } +$DUMPS = [ + ["TKT", 6, "PGA", 3, "IRD", 1], + ["OUI", 8, "LEP", 1, "REX", 7], + ["ASP", 1, "ABC", 3, "TDP", 6], + ["GIF", 8, "ETM", 1, "LPC", 3], + ["MST", 6, "LQF", 1, "WAL", 2], +]; + +$DUMPS_2 = [ + ["TKT", 4, "PGA", 1, "IRD", 6], + ["LEP", 6, "OUI", 5, "REX", 8], + ["ASP", 5, "ABC", 8, "TDP", 4], + ["ETM", 8, "LPC", 4, "GIF", 6], + ["MST", 5, "LQF", 4, "WAL", 8], +]; + +foreach ($DUMPS as $dump) { + $team1 = Team::fromTrigram($dump[0]); + $team2 = Team::fromTrigram($dump[2]); + $team3 = Team::fromTrigram($dump[4]); + $problem1 = $dump[1]; + $problem2 = $dump[3]; + $problem3 = $dump[5]; + + $req1 = $DB->prepare("SELECT * FROM `solutions` WHERE `team` = ? AND `problem` = ? ORDER BY uploaded_at DESC LIMIT 1"); + $req1->execute([$team1->getId(), $problem1]); + $data1 = $req1->fetch(); + $sol1 = Solution::fromData($data1); + $req2 = $DB->prepare("SELECT * FROM `solutions` WHERE `team` = ? AND `problem` = ? ORDER BY uploaded_at DESC LIMIT 1"); + $req2->execute([$team2->getId(), $problem2]); + $data2 = $req2->fetch(); + $sol2 = Solution::fromData($data2); + $req3 = $DB->prepare("SELECT * FROM `solutions` WHERE `team` = ? AND `problem` = ? ORDER BY uploaded_at DESC LIMIT 1"); + $req3->execute([$team3->getId(), $problem3]); + $data3 = $req3->fetch(); + $sol3 = Solution::fromData($data3); + + $req1 = $DB->prepare("UPDATE `teams` SET `opposed_problem` = ?, `rapported_problem` = ? WHERE `id` = ?;"); + $req1->execute([$sol2->getFileId(), $sol3->getFileId(), $team1->getId()]); + + $req2 = $DB->prepare("UPDATE `teams` SET `opposed_problem` = ?, `rapported_problem` = ? WHERE `id` = ?;"); + $req2->execute([$sol3->getFileId(), $sol1->getFileId(), $team2->getId()]); + + $req3 = $DB->prepare("UPDATE `teams` SET `opposed_problem` = ?, `rapported_problem` = ? WHERE `id` = ?;"); + $req3->execute([$sol1->getFileId(), $sol2->getFileId(), $team3->getId()]); +} + +foreach ($DUMPS_2 as $dump) { + $team1 = Team::fromTrigram($dump[0]); + $team2 = Team::fromTrigram($dump[2]); + $team3 = Team::fromTrigram($dump[4]); + $problem1 = $dump[1]; + $problem2 = $dump[3]; + $problem3 = $dump[5]; + + $req1 = $DB->prepare("SELECT * FROM `solutions` WHERE `team` = ? AND `problem` = ? ORDER BY uploaded_at DESC LIMIT 1"); + $req1->execute([$team1->getId(), $problem1]); + $data1 = $req1->fetch(); + $sol1 = Solution::fromData($data1); + $req2 = $DB->prepare("SELECT * FROM `solutions` WHERE `team` = ? AND `problem` = ? ORDER BY uploaded_at DESC LIMIT 1"); + $req2->execute([$team2->getId(), $problem2]); + $data2 = $req2->fetch(); + $sol2 = Solution::fromData($data2); + $req3 = $DB->prepare("SELECT * FROM `solutions` WHERE `team` = ? AND `problem` = ? ORDER BY uploaded_at DESC LIMIT 1"); + $req3->execute([$team3->getId(), $problem3]); + $data3 = $req3->fetch(); + $sol3 = Solution::fromData($data3); + + $req1 = $DB->prepare("UPDATE `teams` SET `opposed_problem_2` = ?, `rapported_problem_2` = ? WHERE `id` = ?;"); + $req1->execute([$sol2->getFileId(), $sol3->getFileId(), $team1->getId()]); + + $req2 = $DB->prepare("UPDATE `teams` SET `opposed_problem_2` = ?, `rapported_problem_2` = ? WHERE `id` = ?;"); + $req2->execute([$sol3->getFileId(), $sol1->getFileId(), $team2->getId()]); + + $req3 = $DB->prepare("UPDATE `teams` SET `opposed_problem_2` = ?, `rapported_problem_2` = ? WHERE `id` = ?;"); + $req3->execute([$sol1->getFileId(), $sol2->getFileId(), $team3->getId()]); +} + + +$req = $DB->prepare("SELECT opposed_problem, rapported_problem, opposed_problem_2, rapported_problem_2 FROM teams WHERE id = ?;"); +$req->execute([$team->getId()]); +$data = $req->fetch(); + +$opposed_solution = Solution::fromId($data["opposed_problem"]); +$rapported_solution = Solution::fromId($data["rapported_problem"]); +$opposed_solution_2 = Solution::fromId($data["opposed_problem_2"]); +$rapported_solution_2 = Solution::fromId($data["rapported_problem_2"]); + class MyTeam { public $name; diff --git a/server_files/controllers/syntheses.php b/server_files/controllers/syntheses.php index 38be9cf..804618d 100644 --- a/server_files/controllers/syntheses.php +++ b/server_files/controllers/syntheses.php @@ -29,19 +29,24 @@ if ($team->isSelectedForFinal()) class SaveSynthesis { private $dest; + private $round; private $file; public function __construct() { $this->file = $_FILES["synthese"]; + $this->round = htmlspecialchars($_POST["round"]); $this->dest = DestType::fromName(strtoupper(htmlspecialchars($_POST["dest"]))); } public function makeVerifications() { - global $LOCAL_PATH; + global $LOCAL_PATH, $tournament; - ensure($this->dest != DestType::DEFENSEUR, "Le destinataire est invalide."); + ensure($this->dest != DestType::DEFENSEUR, "La source est invalide."); + ensure($this->round == 1 || $this->round == 2, "Le tour est invalide."); + $now = date("Y-m-d H:i"); + ensure($this->round == 1 && $now < $tournament->getSynthesesDate() || $this->round == 2 && $now < $tournament->getSynthesesDate2(), "Vous ne pouvez plus rendre de note de synthèse pour le tour $this->round."); ensure($this->file["size"] <= 2e6, "Le fichier doit peser moins que 2 Mo."); ensure(!$this->file["error"], "Une erreur est survenue."); ensure(finfo_file(finfo_open(FILEINFO_MIME_TYPE), $this->file["tmp_name"]) == "application/pdf", "Le fichier doit être au format PDF."); @@ -58,8 +63,8 @@ class SaveSynthesis if (!rename($this->file["tmp_name"], "$LOCAL_PATH/files/$id")) throw new AssertionError("Une erreur est survenue lors de l'envoi du fichier."); - $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `dest`) VALUES (?, ?, ?, ?);"); - $req->execute([$id, $team->getId(), $team->isSelectedForFinal() ? $FINAL->getId() : $tournament->getId(), $this->dest]); + $req = $DB->prepare("INSERT INTO `syntheses`(`file_id`, `team`, `tournament`, `round`, `dest`) VALUES (?, ?, ?, ?, ?);"); + $req->execute([$id, $team->getId(), $team->isSelectedForFinal() ? $FINAL->getId() : $tournament->getId(), $this->round, $this->dest]); return false; } diff --git a/server_files/controllers/tournoi.php b/server_files/controllers/tournoi.php index 0cc0155..e34bb9a 100644 --- a/server_files/controllers/tournoi.php +++ b/server_files/controllers/tournoi.php @@ -39,8 +39,12 @@ class UpdateTournament public $time_inscription; public $date_solutions; public $time_solutions; - public $date_syntheses; - public $time_syntheses; + public $date_syntheses; + public $time_syntheses; + public $date_solutions_2; + public $time_solutions_2; + public $date_syntheses_2; + public $time_syntheses_2; public $description; public $final; @@ -89,7 +93,9 @@ class UpdateTournament ensure(dateWellFormed($this->date_end), "La date de fin n'est pas valide."); ensure(dateWellFormed($this->date_inscription . " " . $this->time_inscription), "La date de clôture des inscriptions n'est pas valide."); ensure(dateWellFormed($this->date_solutions . " " . $this->time_solutions), "La date limite de remise des solutions n'est pas valide."); - ensure(dateWellFormed($this->date_syntheses . " " . $this->time_syntheses), "La date limite de remise des notes de synthèse n'est pas valide."); + ensure(dateWellFormed($this->date_syntheses . " " . $this->time_syntheses), "La date limite de remise des notes de synthèse pour le tour 1 n'est pas valide."); + ensure(dateWellFormed($this->date_solutions_2 . " " . $this->time_solutions_2), "La date limite de visibilité des solutions du tour 2 n'est pas valide."); + ensure(dateWellFormed($this->date_syntheses_2 . " " . $this->time_syntheses_2), "La date limite de remise des notes de synthèse pour le tour 2 n'est pas valide."); } public function updateTournament() @@ -104,7 +110,9 @@ class UpdateTournament $tournament->setEndDate($this->date_end); $tournament->setInscriptionDate("$this->date_inscription $this->time_inscription"); $tournament->setSolutionsDate("$this->date_solutions $this->time_solutions"); - $tournament->setSynthesesDate("$this->date_syntheses $this->time_syntheses"); + $tournament->setSynthesesDate("$this->date_syntheses $this->time_syntheses"); + $tournament->setSolutionsDate2("$this->date_solutions_2 $this->time_solutions_2"); + $tournament->setSynthesesDate2("$this->date_syntheses_2 $this->time_syntheses_2"); $tournament->setDescription($this->description); foreach ($this->organizers as $organizer) { diff --git a/server_files/controllers/view_file.php b/server_files/controllers/view_file.php index 98c2dcc..cdc4904 100644 --- a/server_files/controllers/view_file.php +++ b/server_files/controllers/view_file.php @@ -34,12 +34,19 @@ if ($file !== null) { $problem = $file->getProblem(); $name = "Problème $problem $trigram"; - if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) - require_once "server_files/403.php"; + if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) { + $req = $DB->prepare("SELECT opposed_problem, rapported_problem, opposed_problem_2, rapported_problem_2 FROM teams WHERE id = ?;"); + $req->execute([$_SESSION["team"]->getId()]); + $data = $req->fetch(); + if ($id != $data["opposed_problem"] && $id != $data["rapported_problem"]) { + if (date("Y-m-d H:i") < $tournament->getSolutionsDate2() || ($id != $data["opposed_problem_2"] && $id != $data["rapported_problem_2"])) + require_once "server_files/403.php"; + } + } } else if ($type == DocumentType::SYNTHESIS) { $dest = $file->getDest(); - $name = "Note de synthèse $trigram pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur"); + $name = "Note de synthèse $trigram " . ($dest == DestType::OPPOSANT ? "de l'opposant" : "du rapporteur"); if (($_SESSION["role"] == Role::PARTICIPANT || $_SESSION["role"] == Role::ENCADRANT) && (!isset($_SESSION["team"]) || $_SESSION["team"]->getId() != $team->getId())) require_once "server_files/403.php"; diff --git a/server_files/model.php b/server_files/model.php index a292815..e650c24 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -166,6 +166,8 @@ function canValidate(Team $team, Tournament $tournament) $d = $req->fetch(); $can_validate &= $d["version"] > 0;*/ + $can_validate &= date("Y-m-d H:i:s") <= $tournament->getInscriptionDate(); + return $can_validate; } diff --git a/server_files/utils.php b/server_files/utils.php index 3fa8116..2bc4ce5 100644 --- a/server_files/utils.php +++ b/server_files/utils.php @@ -9,7 +9,7 @@ function ensure($bool, $error_msg = "") function formatDate($date = NULL, $with_time = false) { if ($date == NULL) - $date = date("Y-m-d H:i:s"); + $date = date("Y-m-d H:i"); return strftime("%d %B %G" . ($with_time ? " %H:%M" : ""), strtotime($date)); } diff --git a/server_files/views/ajouter_tournoi.php b/server_files/views/ajouter_tournoi.php index bf5ae09..2570da3 100644 --- a/server_files/views/ajouter_tournoi.php +++ b/server_files/views/ajouter_tournoi.php @@ -85,7 +85,7 @@ if (isset($tournament) && !$has_error) { ?> value="time_solutions: date('H:i') ?>"/>

    +
    +
    + + + +
    +
    + + + +
    +
    +
    diff --git a/server_files/views/equipe.php b/server_files/views/equipe.php index 3cdc9b4..6744110 100644 --- a/server_files/views/equipe.php +++ b/server_files/views/equipe.php @@ -59,6 +59,10 @@ ?>
    +
    + diff --git a/server_files/views/header.php b/server_files/views/header.php index b00d87e..f503e23 100644 --- a/server_files/views/header.php +++ b/server_files/views/header.php @@ -82,10 +82,10 @@ Paiement --> diff --git a/server_files/views/mon_equipe.php b/server_files/views/mon_equipe.php index b9eb97e..b86b5d7 100644 --- a/server_files/views/mon_equipe.php +++ b/server_files/views/mon_equipe.php @@ -146,4 +146,39 @@ require_once "header.php"; +getValidationStatus() == ValidationStatus::VALIDATED) { ?> +
    +

    Solutions à opposer/rapporter

    +
    + Modèle vierge de note de synthèse (PDF -- TEX) +
    + +
    + Les solutions du tour 1 seront disponibles sur cette page peu après le tirage. +
    + getSolutionsDate2()) { ?> +
    + Les solutions du tour 2 pourront être téléchargées sur cette page à partir du getSolutionsDate2(), true) ?>. +
    +getFileId(); + $problem = $sol->getProblem(); + $t = Team::fromId($sol->getTeamId()); + $trigram = $t->getTrigram(); + echo "
    getSolutionsDate2() ? "danger" : "info") . "\">Problème $problem " + . " de l'équipe $trigram " . ($source == DestType::OPPOSANT ? "opposé" : "rapporté") . ", tour $round : Télécharger
    \n"; + } + ?> + + + \ No newline at end of file diff --git a/server_files/views/syntheses.php b/server_files/views/syntheses.php index f423615..3b746a3 100644 --- a/server_files/views/syntheses.php +++ b/server_files/views/syntheses.php @@ -12,19 +12,33 @@ if (isset($save_synthesis) && !$has_error) { ?>
    -getSynthesesDate()) { ?> +getSynthesesDate2()) { + if (date("Y-m-d H:i:s") < $tournament->getSynthesesDate()) { + ?> +
    + Attention : la date butoir de soumission des notes de synthèse pour le tour 1 est passée. Les prochaines notes de synthèses compteront pour le second tour. +
    +
    -
    - +
    +
    -
    +
    + + +
    + +
    @@ -43,8 +57,9 @@ if (isset($save_synthesis) && !$has_error) { ?> foreach ($syntheses as $synthesis) { $file_id = $synthesis->getFileId(); $dest = $synthesis->getDest(); + $round = $synthesis->getRound(); $version = $synthesis->getVersion(); - echo "
    Note de synthèse pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . " (version $version) : Télécharger
    "; + echo "
    Note de synthèse " . ($dest == DestType::OPPOSANT ? "de l'opposant" : "du rapporteur") . ", tour $round (version $version) : Télécharger
    "; } if ($team->isSelectedForFinal()) { ?> @@ -56,8 +71,9 @@ if ($team->isSelectedForFinal()) { ?> foreach ($syntheses_final as $synthesis) { $file_id = $synthesis->getFileId(); $dest = $synthesis->getDest(); + $round = $synthesis->getRound(); $version = $synthesis->getVersion(); - echo "
    Note de synthèse pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") . " (version $version) : Télécharger
    "; + echo "
    Note de synthèse " . ($dest == DestType::OPPOSANT ? "de l'opposant" : "du rapporteur") . ", tour $round (version $version) : Télécharger
    "; } } diff --git a/server_files/views/syntheses_orga.php b/server_files/views/syntheses_orga.php index 477c143..9106b65 100644 --- a/server_files/views/syntheses_orga.php +++ b/server_files/views/syntheses_orga.php @@ -15,12 +15,13 @@ foreach ($tournaments as $tournament) { foreach ($syntheses as $synthesis) { $file_id = $synthesis->getFileId(); $dest = $synthesis->getDest(); + $round = $synthesis->getRound(); $version = $synthesis->getVersion(); $team = Team::fromId($synthesis->getTeamId()); $team_name = $team->getName(); $team_trigram = $team->getTrigram(); echo "
    Note de synthèse de l'équipe $team_name ($team_trigram) pour " . ($dest == DestType::OPPOSANT ? "l'opposant" : "le rapporteur") - . ", version $version : Télécharger
    "; + . ", tour $round, version $version : Télécharger
    "; } echo "\n"; diff --git a/server_files/views/tournoi.php b/server_files/views/tournoi.php index 52190a7..9b54849 100644 --- a/server_files/views/tournoi.php +++ b/server_files/views/tournoi.php @@ -48,7 +48,13 @@ Date limite d'envoi des solutions : getSolutionsDate(), true) ?>
    - Date limite d'envoi des notes de synthèse : getSynthesesDate(), true) ?> + Date limite d'envoi des notes de synthèse - tour 1 : getSynthesesDate(), true) ?> +
    +
    + Date à partir de laquelle les solutions du tour 2 sont disponibles : getSolutionsDate2(), true) ?> +
    +
    + Date limite d'envoi des notes de synthèse - tour 2 : getSynthesesDate2(), true) ?>
    Description : getDescription() ?> @@ -60,8 +66,8 @@ if ($tournament->isFinal()) organize($_SESSION["user_id"]))) { ?> @@ -186,21 +192,37 @@ else {
    - +
    - +
    - + + value="getSynthesesDate(), 11, 5) ?>" required/> +
    +
    + +
    +
    + + + +
    + +
    + + +