diff --git a/server_files/classes/User.php b/server_files/classes/User.php index 0fbb77b..4a4845f 100644 --- a/server_files/classes/User.php +++ b/server_files/classes/User.php @@ -16,6 +16,7 @@ class User private $confirm_email; private $forgotten_password; private $inscription_date; + private $receive_animath_mails; private function __construct() {} @@ -48,6 +49,21 @@ class User $user->fill($data); return $user; } + + public static function getAdmins() + { + global $DB, $YEAR; + $admins = []; + $req = $DB->query("SELECT * FROM `users` WHERE `year` = $YEAR;"); + + while (($data = $req->fetch()) !== false) { + $admin = new User(); + $admin->fill($data); + $admins[] = $admin; + } + + return $admins; + } private function fill($data) { @@ -65,6 +81,7 @@ class User $this->confirm_email = $data["confirm_email"]; $this->forgotten_password = $data["forgotten_password"]; $this->inscription_date = $data["inscription_date"]; + $this->receive_animath_mails = $data["receive_animath_mails"]; } public function getEmail() @@ -170,7 +187,6 @@ class User { global $DB; $this->role = $role; - /** @noinspection PhpUndefinedMethodInspection */ $DB->prepare("UPDATE `users` SET `role` = ? WHERE `id` = ?;")->execute([Role::getName($role), $this->getId()]); } @@ -215,6 +231,18 @@ class User return $this->inscription_date; } + public function doReceiveAnimathMails() + { + return $this->receive_animath_mails; + } + + public function setReceiveAnimathMails($receive_animath_mails) + { + global $DB; + $this->receive_animath_mails = $receive_animath_mails; + $DB->prepare("UPDATE `users` SET `receive_animath_mails` = ? WHERE `id` = ?;")->execute([$receive_animath_mails, $this->getId()]); + } + public function getAllDocuments($problem) { global $DB; diff --git a/server_files/classes/Video.php b/server_files/classes/Video.php index 25f0c52..7d46df2 100644 --- a/server_files/classes/Video.php +++ b/server_files/classes/Video.php @@ -3,11 +3,16 @@ class Video { + const NOT_CONTROLLED = 0; + const REJECTED = -1; + const ACCEPTED = 1; + private $id; private $team; private $problem; private $link; private $reason; + private $validation; private $uploaded_at; private $year; private $version; @@ -29,14 +34,16 @@ class Video return $video; } - public static function getVideos($reason, $problem, $team_id = -1) + public static function getVideos($reason, $problem, $validation_min = -1, $team_id = -1) { - global $DB; + global $DB, $YEAR; $req = $DB->query("SELECT * FROM `videos` AS `t1` " - . "INNER JOIN (SELECT `team`, `problem`, `reason`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `videos` GROUP BY `problem`, `reason`, `team`) `t2` " + . "INNER JOIN (SELECT `team`, `problem`, `reason`, MAX(`uploaded_at`) AS `last_upload`, COUNT(`team`) AS `version` FROM `videos` " + . "WHERE `validation` >= $validation_min AND `year` = $YEAR GROUP BY `problem`, `reason`, `team`) `t2` " . "ON `t1`.`team` = `t2`.`team` AND `t1`.`reason` = `t2`.`reason` AND `t1`.`problem` = `t2`.`problem` " . "WHERE `t1`.`uploaded_at` = `t2`.`last_upload` AND `t1`.`problem` = $problem AND `t1`.`reason` = '" . Reason::getName($reason) . "'" - . ($team_id >= 0 ? " AND `t1`.`team` = $team_id" : "") . " ORDER BY `t1`.`problem`, `t1`.`reason`;"); + . ($team_id >= 0 ? " AND `t1`.`team` = $team_id" : "") + . " AND `validation` >= $validation_min AND `year` = $YEAR ORDER BY `t1`.`problem`, `t1`.`reason`;"); $videos = []; @@ -52,10 +59,11 @@ class Video /** * @param int $reason * @param Team $team + * @param int $validation_min * @return Video|null */ - public static function getVideo($reason, Team $team) { - $videos = self::getVideos($reason, $team->getProblem(), $team->getId()); + public static function getVideo($reason, Team $team, $validation_min = -1) { + $videos = self::getVideos($reason, $team->getProblem(), $validation_min, $team->getId()); if (sizeof($videos) == 0) return null; else @@ -95,6 +103,18 @@ class Video return $this->reason; } + public function getValidation() + { + return $this->validation; + } + + public function setValidation($validation) + { + global $DB; + $this->validation = $validation; + $DB->exec("UPDATE `videos` SET `validation` = $validation WHERE `id` = $this->id;"); + } + public function getUploadedAt() { return $this->uploaded_at; diff --git a/server_files/controllers/envoyer_video.php b/server_files/controllers/envoyer_video.php index 7817ec1..4025ae1 100644 --- a/server_files/controllers/envoyer_video.php +++ b/server_files/controllers/envoyer_video.php @@ -22,17 +22,22 @@ if (isset($_POST["upload"])) { class NewVideo { - private $link; + public $link; + private $valid_link; + private $no_change; public function __construct($data) { - $this->link = $data["link"]; + foreach ($data as $key => $value) + $this->$key = $value; } public function makeVerifications() { ensure(preg_match("#(https?\:\/\/|)[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?#", $this->link), "Ce n'est pas une URL valide."); $this->link = preg_replace('/^(?!https?:\/\/)/', 'https://', $this->link); + ensure($this->valid_link != null, "Vous devez confirmer que le lien est valide."); + ensure($this->no_change != null, "Vous devez vous engager à ne pas changer le contenu du lien et de la vidéo."); } public function uploadVideo() @@ -41,9 +46,12 @@ class NewVideo $req = $DB->prepare("INSERT INTO `videos`(`team`, `problem`, `link`, `reason`, `year`) VALUES (?, ?, ?, ?, ?)"); $req->execute([$team->getId(), $team->getProblem(), $this->link, "SOLUTION", $YEAR]); + + Mailer::sendNewVideo($this, $team); } } $video = Video::getVideo(Reason::SOLUTION, $team); +$video_validated = Video::getVideo(Reason::SOLUTION, $team, Video::ACCEPTED); require_once "server_files/views/envoyer_video.php"; \ No newline at end of file diff --git a/server_files/controllers/mon_compte.php b/server_files/controllers/mon_compte.php index f6740dc..a539efc 100644 --- a/server_files/controllers/mon_compte.php +++ b/server_files/controllers/mon_compte.php @@ -41,6 +41,7 @@ class MyAccount public $school; public $class; public $description; + public $receive_animath_mails; /** @var User */ private $user; @@ -65,6 +66,7 @@ class MyAccount ensure(filter_var($this->email, FILTER_VALIDATE_EMAIL), "L'adresse e-mail entrée est invalide."); $this->email = strtolower($this->email); ensure($this->email == $this->user->getEmail() || !userExists($this->email), "Un compte existe déjà avec cette adresse e-mail."); + $this->receive_animath_mails = $this->receive_animath_mails != false; } public function updateAccount() @@ -74,6 +76,7 @@ class MyAccount $this->user->setSchool($this->school); $this->user->setClass($this->class); $this->user->setDescription($this->description); + $this->user->setReceiveAnimathMails($this->receive_animath_mails); if ($this->email != $this->user->getEmail()) { $this->user->setEmail($this->email); diff --git a/server_files/controllers/videos_solutions.php b/server_files/controllers/videos_solutions.php index 242b203..66a479e 100644 --- a/server_files/controllers/videos_solutions.php +++ b/server_files/controllers/videos_solutions.php @@ -3,9 +3,54 @@ if (!isset($_SESSION["user_id"]) || $_SESSION["role"] != Role::ADMIN) require_once "server_files/403.php"; +$has_error = false; +$error_message = null; + +if (isset($_POST["validate_video"])) { + $validate_video = new ValidateVideo($_POST); + try { + $validate_video->makeVerifications(); + $validate_video->validate(); + } + catch (AssertionError $e) { + $has_error = true; + $error_message = $e->getMessage(); + } +} + +class ValidateVideo +{ + private $video_id; + private $accept; + private $reject; + /** @var Video */ + private $video; + + public function __construct($data) + { + foreach ($data as $key => $value) + $this->$key = $value; + } + + public function makeVerifications() + { + $this->video = Video::fromId($this->video_id); + ensure($this->video != null, "La vidéo n'existe pas."); + ensure($this->video->getValidation() == 0, "La vidéo est déjà validée / rejetée."); + ensure(($this->accept == null || $this->reject == null) && $this->accept != $this->reject, "Impossible de déterminer s'il faut accepter ou non la vidéo."); + } + + public function validate() + { + $this->video->setValidation($this->accept ? 1 : -1); + Mailer::validateVideo($this->video); + } +} + $videos = []; for ($problem = 1; $problem <= 4; ++$problem) $videos[] = Video::getVideos(Reason::SOLUTION, $problem); + require_once "server_files/views/videos_solutions.php"; \ No newline at end of file diff --git a/server_files/model.php b/server_files/model.php index 4988ff1..d0e2207 100644 --- a/server_files/model.php +++ b/server_files/model.php @@ -53,7 +53,7 @@ function quitTeam() /** @noinspection SqlResolve */ $DB->exec("UPDATE `teams` SET `participant_$i` = NULL WHERE `participant_$i` = $user_id;"); else - $DB->exec("UPDATE `teams` SET `encadrant` = NULL WHERE `encadrant` = $user_id;"); + $DB->exec("UPDATE `teams` SET `encadrant` = NULL WHERE `encadrant` = $user_id;"); $user->setTeamId(null); for ($i = 1; $i <= 4; ++$i) { /** @noinspection SqlResolve */ @@ -167,4 +167,12 @@ function getZipFile($problem, $team_id = -1) $zip->close(); return $file_name; +} + +function displayVideo($link) +{ + if (preg_match("#(https?\://|)(www\.|)youtube\.com\/watch\?v=(.*)#", $link, $matches)) { + $code = $matches[3]; + echo "

\n"; + } } \ No newline at end of file diff --git a/server_files/services/mail.php b/server_files/services/mail.php index 5684816..252ecd6 100644 --- a/server_files/services/mail.php +++ b/server_files/services/mail.php @@ -16,6 +16,40 @@ class Mailer ensure(mail($email, $subject, $content, $headers), "Un problème est survenu dans l'envoi d'un mail. Veuiller contacter votre administrateur."); } + private static function broadcastToTeam(Team $team, $subject, $content, $from = "contact") + { + $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); + $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); + + $encadrant = User::fromId($team->getEncadrantId()); + + if ($encadrant != null) { + $c = preg_replace("#{FIRST_NAME}#", $encadrant->getFirstName(), $content); + $c = preg_replace("#{SURNAME}#", $encadrant->getSurname(), $c); + self::sendMail($encadrant->getEmail(), $subject, $c, $from); + } + + foreach ($team->getParticipants() as $participant_id) { + $participant = User::fromId($participant_id); + if ($participant == null) + continue; + + $c = preg_replace("#{FIRST_NAME}#", $participant->getFirstName(), $content); + $c = preg_replace("#{SURNAME}#", $participant->getSurname(), $c); + self::sendMail($participant->getEmail(), $subject, $c, $from); + } + } + + private static function broadcastToAdmins($subject, $content, $from = "contact") + { + /** @var User $admin */ + foreach (User::getAdmins() as $admin) { + $c = preg_replace("#{FIRST_NAME}#", $admin->getFirstName(), $content); + $c = preg_replace("#{SURNAME}#", $admin->getSurname(), $c); + self::sendMail($admin->getEmail(), $subject, $c, $from); + } + } + private static function getTemplate($name) { global $LOCAL_PATH; @@ -115,4 +149,29 @@ class Mailer self::sendMail($user->getEmail(), "Équipe rejointe Correspondances des Jeunes Mathématicien·ne·s $YEAR", $content); } + + public static function sendNewVideo(NewVideo $video, Team $team) + { + global $YEAR; + + $content = self::getTemplate("new_video"); + $content = preg_replace("#{TEAM_NAME}#", $team->getName(), $content); + $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); + $content = preg_replace("#{PROBLEM}#", $team->getProblem(), $content); + $content = preg_replace("#{VIDEO_LINK}#", $video->link, $content); + self::broadcastToAdmins("Nouvelle vidéo Correspondances des Jeunes Mathématicien·ne·s $YEAR", $content); + } + + public static function validateVideo(Video $video) + { + global $YEAR; + + $team = Team::fromId($video->getTeam()); + + $content = self::getTemplate($video->getValidation() == Video::ACCEPTED ? "video_accepted" : "video_rejected"); + $content = preg_replace("#{TRIGRAM}#", $team->getTrigram(), $content); + $content = preg_replace("#{PROBLEM}#", $team->getProblem(), $content); + $content = preg_replace("#{VIDEO_LINK}#", $video->getLink(), $content); + self::broadcastToTeam($team, ($video->getValidation() == Video::REJECTED ? "Vidéo refusée " : "Vidéo acceptée ") . $team->getTrigram() . " – Correspondances des Jeunes Mathématicien·ne·s $YEAR", $content); + } } diff --git a/server_files/services/mail_templates/new_video.html b/server_files/services/mail_templates/new_video.html new file mode 100644 index 0000000..6c78a80 --- /dev/null +++ b/server_files/services/mail_templates/new_video.html @@ -0,0 +1,18 @@ + + + + + Nouvelle vidéo – Correspondances des Jeunes Mathématicien·ne·s {YEAR} + + +Bonjour {FIRST_NAME} {SURNAME},
+
+L'équipe « {TEAM_NAME} » ({TRIGRAM}) vient d'ajouter une vidéo pour le problème {PROBLEM} des Correspondances des Jeunes Mathématicien·ne·s : {VIDEO_LINK}. +Vous êtes désormais invité avant que quelqu'un d'autre ne le fasse à accepter ou refuser cette vidéo via la plateforme d'inscription (accessible après connexion) : +{URL_BASE}/videos-solutions
+
+Cordialement,
+
+Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s + + \ No newline at end of file diff --git a/server_files/services/mail_templates/video_accepted.html b/server_files/services/mail_templates/video_accepted.html new file mode 100644 index 0000000..ca89729 --- /dev/null +++ b/server_files/services/mail_templates/video_accepted.html @@ -0,0 +1,18 @@ + + + + + Vidéo acceptée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} + + +Bonjour {FIRST_NAME} {SURNAME},
+
+Félicitations, votre vidéo pour le problème {PROBLEM} a été validée ! Pour rappel, vous aviez soumis ce lien : {VIDEO_LINK}.
+Votre travail est à présent terminé, et vous pouvez attendre les prochaines phases. Bravo à vous !
+Si toutefois vous le souhaitez, vous pouvez à nouveau soumettre une vidéo avant la fin de la phase. Cette nouvelle vidéo ne remplacera l'actuelle qu'au moment de la validation de celle-ci.
+
+Cordialement,
+
+Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s + + \ No newline at end of file diff --git a/server_files/services/mail_templates/video_rejected.html b/server_files/services/mail_templates/video_rejected.html new file mode 100644 index 0000000..0fc96f5 --- /dev/null +++ b/server_files/services/mail_templates/video_rejected.html @@ -0,0 +1,19 @@ + + + + + Vidéo refusée – Correspondances des Jeunes Mathématicien·ne·s {YEAR} + + +Bonjour {FIRST_NAME} {SURNAME},
+
+Malheureusement, votre vidéo pour le problème {PROBLEM} n'a pas été validée. Pour rappel, vous aviez soumis ce lien : {VIDEO_LINK}.
+Si vous aviez soumis une précédente vidéo qui a été validée, elle reste conservée. +Vous êtes désormais invités à retravailler vos résultats ou votre présentation orale afin que votre prestation soit validée par les organisateurs. +N'hésitez pas à nous contacter à contact@correspondances-maths.fr si vous souhaitez avoir plus d'informations ou contester ce refus. +
+Cordialement,
+
+Le comité d'organisation des Correspondances des Jeunes Mathématicien·ne·s + + \ No newline at end of file diff --git a/server_files/views/envoyer_video.php b/server_files/views/envoyer_video.php index ee43da7..eec76b7 100644 --- a/server_files/views/envoyer_video.php +++ b/server_files/views/envoyer_video.php @@ -12,11 +12,24 @@ elseif (isset($new_video)) if ($video !== null) { $link = $video->getLink(); echo "Lien de la vidéo déjà envoyée : $link (version " . $video->getVersion() . ")
\n"; - if (preg_match("#(https?\://|)(www\.|)youtube\.com\/watch\?v=(.*)#", $link, $matches)) { - $code = $matches[3]; - echo "

\n"; + displayVideo($link); + switch ($video->getValidation()) { + case 0: + echo "La vidéo n'a pas encore été contrôlée.
"; + break; + case 1: + echo "La vidéo a été acceptée.
"; + break; + case -1: + echo "La vidéo a été rejetée.
"; + break; } } +if ($video_validated != null && $video_validated->getId() != $video->getId()) { + $link = $video_validated->getLink(); + echo "
\nLien de la dernière vidéo validée : $link
"; + displayVideo($link); +} ?>
@@ -30,6 +43,16 @@ if ($video !== null) { + + + + + + + + + + diff --git a/server_files/views/mon_compte.php b/server_files/views/mon_compte.php index 7d4d3cb..2b985c9 100644 --- a/server_files/views/mon_compte.php +++ b/server_files/views/mon_compte.php @@ -60,6 +60,9 @@ elseif (isset($my_account) || isset($new_password)) { + + doReceiveAnimathMails() ? "checked" : "" ?> /> + diff --git a/server_files/views/videos_solutions.php b/server_files/views/videos_solutions.php index dfe5c4e..bd8eced 100644 --- a/server_files/views/videos_solutions.php +++ b/server_files/views/videos_solutions.php @@ -2,6 +2,10 @@ require_once "header.php"; +if ($has_error) { + echo "

Erreur : $error_message

"; +} + for ($problem = 1; $problem <= 4; ++$problem) { echo "

Vidéos pour le problème $problem

\n"; /** @var Video $video */ @@ -9,10 +13,26 @@ for ($problem = 1; $problem <= 4; ++$problem) { $link = $video->getLink(); $team = Team::fromId($video->getTeam()); $version = $video->getVersion(); - echo "Vidéo de présentation de l'équipe « " . $team->getName() . " » (" . $team->getTrigram() . "), version $version : $link\n"; - if (preg_match("#(https?\://|)(www\.|)youtube\.com\/watch\?v=(.*)#", $link, $matches)) { - $code = $matches[3]; - echo "

\n"; + echo "

Vidéo de présentation de l'équipe « " . $team->getName() . " » (" . $team->getTrigram() . ") :

\n"; + echo "Lien de la vidéo (version $version) : $link"; + displayVideo($link); + + if ($video->getValidation() == 0) { ?> + + + + + +
+ La vidéo a été " . ($video->getValidation() == 1 ? "acceptée" : "refusée") . ".
\n"; + + if ($video->getValidation() != Video::ACCEPTED) { + $last_validated_video = Video::getVideo(Reason::SOLUTION, $team, Video::ACCEPTED); + $link = $last_validated_video->getLink(); + echo "\nLien de la dernière vidéo validée de cette équipe : $link
\n"; + displayVideo($link); } } echo "
\n";