diff options
| author | polo <ordipolo@gmx.fr> | 2025-08-03 00:23:11 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2025-08-03 00:23:11 +0200 |
| commit | 547d7feed68e89957f062b8ed9b988f28c5830ce (patch) | |
| tree | 7e07ea2b2065468900201cddacad5db559446a7d | |
| parent | 9934a32f7e02c484d6b122c9af860ab1ca9b2dca (diff) | |
| download | cms-547d7feed68e89957f062b8ed9b988f28c5830ce.tar.gz cms-547d7feed68e89957f062b8ed9b988f28c5830ce.tar.bz2 cms-547d7feed68e89957f062b8ed9b988f28c5830ce.zip | |
réorganisation 3: classes controller
| -rw-r--r-- | public/index.php | 4 | ||||
| -rw-r--r-- | src/controller/ArticleController.php | 169 | ||||
| -rw-r--r-- | src/controller/CalendarController.php | 79 | ||||
| -rw-r--r-- | src/controller/ContactFormController.php | 44 | ||||
| -rw-r--r-- | src/controller/EmailController.php | 91 | ||||
| -rw-r--r-- | src/controller/ImageUploadController.php | 184 | ||||
| -rw-r--r-- | src/controller/MenuAndPathsController.php | 189 | ||||
| -rw-r--r-- | src/controller/PageManagementController.php | 264 | ||||
| -rw-r--r-- | src/controller/ajax_admin.php | 636 | ||||
| -rw-r--r-- | src/controller/ajax_calendar_admin.php | 54 | ||||
| -rw-r--r-- | src/controller/ajax_calendar_visitor.php | 39 | ||||
| -rw-r--r-- | src/controller/ajax_email.php | 105 | ||||
| -rw-r--r-- | src/controller/password.php | 3 | ||||
| -rw-r--r-- | src/controller/post_functions_admin.php | 231 | ||||
| -rw-r--r-- | src/controller/post_router.php | 120 | ||||
| -rw-r--r-- | src/controller/request_router.php | 256 | ||||
| -rw-r--r-- | src/model/EventDTO.php | 2 |
17 files changed, 1281 insertions, 1189 deletions
diff --git a/public/index.php b/public/index.php index 09af532..ba0e354 100644 --- a/public/index.php +++ b/public/index.php | |||
| @@ -53,8 +53,8 @@ if(!empty($_GET['id'])) | |||
| 53 | $id = htmlspecialchars($_GET['id']); // nettoyage qui n'abime pas les id du genre "n16" | 53 | $id = htmlspecialchars($_GET['id']); // nettoyage qui n'abime pas les id du genre "n16" |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | /* -- contrôleurs qui traitent les POST (formulaires ou AJAX) -- */ | 56 | /* -- routeur des données de formulaires et requêtes AJAX -- */ |
| 57 | require '../src/controller/post_router.php'; | 57 | require '../src/controller/request_router.php'; |
| 58 | 58 | ||
| 59 | 59 | ||
| 60 | /* -- affichage d'une page -- */ | 60 | /* -- affichage d'une page -- */ |
diff --git a/src/controller/ArticleController.php b/src/controller/ArticleController.php new file mode 100644 index 0000000..e3e4edb --- /dev/null +++ b/src/controller/ArticleController.php | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ArticleController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use App\Entity\Node; | ||
| 7 | use App\Entity\Article; | ||
| 8 | use Doctrine\ORM\EntityManager; | ||
| 9 | |||
| 10 | class ArticleController | ||
| 11 | { | ||
| 12 | static public function editorSubmit(EntityManager $entityManager, array $json): void | ||
| 13 | { | ||
| 14 | if(json_last_error() === JSON_ERROR_NONE) | ||
| 15 | { | ||
| 16 | $id = $json['id']; | ||
| 17 | $director = new Director($entityManager); | ||
| 18 | |||
| 19 | // cas d'une nouvelle "news" | ||
| 20 | if(is_array($json['content'])){ | ||
| 21 | foreach($json['content'] as $one_input){ | ||
| 22 | $one_input = Security::secureString($one_input); | ||
| 23 | } | ||
| 24 | $content = $json['content']; | ||
| 25 | } | ||
| 26 | else{ | ||
| 27 | $content = Security::secureString($json['content']); | ||
| 28 | } | ||
| 29 | |||
| 30 | // nouvel article | ||
| 31 | if($id[0] === 'n') | ||
| 32 | { | ||
| 33 | $section_id = (int)substr($id, 1); // id du bloc <section> | ||
| 34 | $director->findNodeById($section_id); | ||
| 35 | $director->makeSectionNode(); | ||
| 36 | $node = $director->getNode(); // = <section> | ||
| 37 | |||
| 38 | if(is_array($content)){ | ||
| 39 | $date = new \DateTime($content['d']); | ||
| 40 | $article = new Article($content['i'], $date, $content['t'], $content['p']); | ||
| 41 | $article_node = new Node('new', 'i' . (string)$date->getTimestamp(), [], count($node->getChildren()) + 1, $node, $node->getPage(), $article); | ||
| 42 | |||
| 43 | // id_node tout juste généré | ||
| 44 | //$article_node->getId(); | ||
| 45 | } | ||
| 46 | else{ | ||
| 47 | $timestamp = time(); | ||
| 48 | $date = new \DateTime; | ||
| 49 | $date->setTimestamp($timestamp); | ||
| 50 | |||
| 51 | $article = new Article($content, $date); // le "current" timestamp est obtenu par la BDD | ||
| 52 | $article_node = new Node('article', 'i' . (string)$timestamp, [], count($node->getChildren()) + 1, $node, $node->getPage(), $article); | ||
| 53 | } | ||
| 54 | |||
| 55 | $entityManager->persist($article_node); | ||
| 56 | $entityManager->flush(); | ||
| 57 | |||
| 58 | echo json_encode(['success' => true, 'article_id' => $article_node->getArticleTimestamp()]); | ||
| 59 | die; | ||
| 60 | } | ||
| 61 | // modification article | ||
| 62 | else{ | ||
| 63 | $id[0] = 'i'; // id de l'article node | ||
| 64 | } | ||
| 65 | |||
| 66 | if($director->makeArticleNode($id)) // une entrée est trouvée | ||
| 67 | { | ||
| 68 | $node = $director->getArticleNode(); // article | ||
| 69 | switch($json['id'][0]){ | ||
| 70 | case 'i': | ||
| 71 | $node->getArticle()->setContent($content); | ||
| 72 | break; | ||
| 73 | case 'p': | ||
| 74 | $node->getArticle()->setPreview($content); // html de l'éditeur | ||
| 75 | break; | ||
| 76 | case 't': | ||
| 77 | $node->getArticle()->setTitle($content); // html de l'éditeur | ||
| 78 | break; | ||
| 79 | case 'd': | ||
| 80 | echo json_encode(['success' => false, 'message' => 'l\'action editor_submit ne supporte pas les dates, utiliser date_submit.']); | ||
| 81 | die; | ||
| 82 | default: | ||
| 83 | echo json_encode(['success' => false, 'message' => 'identifiant non utilisable']); | ||
| 84 | die; | ||
| 85 | } | ||
| 86 | $entityManager->flush(); | ||
| 87 | echo json_encode(['success' => true]); | ||
| 88 | } | ||
| 89 | else | ||
| 90 | { | ||
| 91 | echo json_encode(['success' => false, 'message' => 'article non identifié']); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | else{ | ||
| 95 | echo json_encode(['success' => false, 'message' => 'Erreur de décodage JSON']); | ||
| 96 | } | ||
| 97 | die; | ||
| 98 | } | ||
| 99 | |||
| 100 | static public function deleteArticle(EntityManager $entityManager, array $json): void | ||
| 101 | { | ||
| 102 | $director = new Director($entityManager); | ||
| 103 | $director->makeArticleNode($json['id'], true); | ||
| 104 | $article = $director->getArticleNode(); | ||
| 105 | $section = $director->getNode(); | ||
| 106 | |||
| 107 | $entityManager->remove($article); | ||
| 108 | $section->removeChild($article); | ||
| 109 | $section->sortChildren(true); // régénère les positions | ||
| 110 | $entityManager->flush(); | ||
| 111 | |||
| 112 | // test avec une nouvelle requête qui ne devrait rien trouver | ||
| 113 | if(!$director->makeArticleNode($json['id'])) | ||
| 114 | { | ||
| 115 | echo json_encode(['success' => true]); | ||
| 116 | |||
| 117 | // on pourrait afficher une notification "toast" | ||
| 118 | } | ||
| 119 | else{ | ||
| 120 | http_response_code(500); | ||
| 121 | echo json_encode(['success' => false, 'message' => 'Erreur lors de la suppression de l\'article.']); | ||
| 122 | } | ||
| 123 | die; | ||
| 124 | } | ||
| 125 | |||
| 126 | static public function switchPositions(EntityManager $entityManager, array $json): void | ||
| 127 | { | ||
| 128 | $director = new Director($entityManager); | ||
| 129 | $director->makeArticleNode($json['id1'], true); | ||
| 130 | $article1 = $director->getArticleNode(); | ||
| 131 | $section = $director->getNode(); | ||
| 132 | |||
| 133 | $section->sortChildren(true); // régénère les positions avant inversion | ||
| 134 | |||
| 135 | $article2 = null; | ||
| 136 | foreach($section->getChildren() as $child){ | ||
| 137 | if($child->getArticleTimestamp() === $json['id2']) // type string | ||
| 138 | { | ||
| 139 | $article2 = $child; | ||
| 140 | break; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 144 | // inversion | ||
| 145 | $tmp = $article1->getPosition(); | ||
| 146 | $article1->setPosition($article2->getPosition()); | ||
| 147 | $article2->setPosition($tmp); | ||
| 148 | $entityManager->flush(); | ||
| 149 | |||
| 150 | echo json_encode(['success' => true]); | ||
| 151 | die; | ||
| 152 | } | ||
| 153 | |||
| 154 | static public function dateSubmit(EntityManager $entityManager, array $json): void | ||
| 155 | { | ||
| 156 | $id = $json['id']; | ||
| 157 | $id[0] = 'i'; | ||
| 158 | $date = new DateTime($json['date']); | ||
| 159 | |||
| 160 | $director = new Director($entityManager); | ||
| 161 | $director->makeArticleNode($id); | ||
| 162 | $node = $director->getArticleNode(); | ||
| 163 | $node->getArticle()->setDateTime($date); | ||
| 164 | $entityManager->flush(); | ||
| 165 | |||
| 166 | echo json_encode(['success' => true]); | ||
| 167 | die; | ||
| 168 | } | ||
| 169 | } \ No newline at end of file | ||
diff --git a/src/controller/CalendarController.php b/src/controller/CalendarController.php new file mode 100644 index 0000000..cc37d0f --- /dev/null +++ b/src/controller/CalendarController.php | |||
| @@ -0,0 +1,79 @@ | |||
| 1 | <?php | ||
| 2 | // /src/controller/CalendarController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use Doctrine\ORM\EntityManager; | ||
| 7 | use App\Entity\Event; | ||
| 8 | |||
| 9 | class CalendarController | ||
| 10 | { | ||
| 11 | static public function getData(EntityManager $entityManager): void | ||
| 12 | { | ||
| 13 | // bornes début et fin du calendrier affiché à l'heure locale | ||
| 14 | // noter que la vue "planning" est similaire à la vue "semaine" | ||
| 15 | $start = new DateTime($_GET['start']); | ||
| 16 | $end = new DateTime($_GET['end']); | ||
| 17 | $start->setTimezone(new DateTimeZone('UTC')); | ||
| 18 | $end->setTimezone(new DateTimeZone('UTC')); | ||
| 19 | |||
| 20 | // affichage format ISO à l'heure UTC | ||
| 21 | //$date->format('Y-m-d\TH:i:s\Z'); | ||
| 22 | |||
| 23 | // on prend les évènements se finissant après le début ou commençant avant la fin de la fourchette | ||
| 24 | $dql = 'SELECT e FROM App\Entity\Event e WHERE e.end >= :start AND e.start <= :end'; | ||
| 25 | $bulk_data = $entityManager->createQuery($dql) | ||
| 26 | ->setParameter('start', $start) | ||
| 27 | ->setParameter('end', $end) | ||
| 28 | ->getResult(); | ||
| 29 | |||
| 30 | $events = []; | ||
| 31 | foreach($bulk_data as $one_entry){ | ||
| 32 | $event = new EventDTO($one_entry); | ||
| 33 | $events[] = $event->toArray(); | ||
| 34 | } | ||
| 35 | |||
| 36 | header('Content-Type: application/json'); | ||
| 37 | echo json_encode($events); | ||
| 38 | die; | ||
| 39 | } | ||
| 40 | |||
| 41 | static public function newEvent(array $json, EntityManager $entityManager):void | ||
| 42 | { | ||
| 43 | try{ | ||
| 44 | $event = new Event($json); | ||
| 45 | } | ||
| 46 | catch(InvalidArgumentException $e){ | ||
| 47 | echo json_encode(['success' => false, 'error' => $e->getMessage()]); | ||
| 48 | http_response_code(400); | ||
| 49 | die; | ||
| 50 | } | ||
| 51 | $entityManager->persist($event); | ||
| 52 | $entityManager->flush(); | ||
| 53 | |||
| 54 | echo json_encode(['success' => true, 'id' => $event->getId()]); | ||
| 55 | } | ||
| 56 | static public function updateEvent(array $json, EntityManager $entityManager):void | ||
| 57 | { | ||
| 58 | $event = $entityManager->find('App\Entity\Event', (int)$json['id']); | ||
| 59 | try{ | ||
| 60 | $event->securedUpdateFromJSON($json); | ||
| 61 | } | ||
| 62 | catch(InvalidArgumentException $e){ | ||
| 63 | echo json_encode(['success' => false, 'error' => $e->getMessage()]); | ||
| 64 | http_response_code(400); | ||
| 65 | die; | ||
| 66 | } | ||
| 67 | $entityManager->flush(); | ||
| 68 | |||
| 69 | echo json_encode(['success' => true]); | ||
| 70 | } | ||
| 71 | static public function removeEvent(array $json, EntityManager $entityManager):void | ||
| 72 | { | ||
| 73 | $event = $entityManager->find('App\Entity\Event', (int)$json['id']); | ||
| 74 | $entityManager->remove($event); | ||
| 75 | $entityManager->flush(); | ||
| 76 | |||
| 77 | echo json_encode(['success' => true]); | ||
| 78 | } | ||
| 79 | } \ No newline at end of file | ||
diff --git a/src/controller/ContactFormController.php b/src/controller/ContactFormController.php new file mode 100644 index 0000000..9d62a77 --- /dev/null +++ b/src/controller/ContactFormController.php | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ContactFormController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use Doctrine\ORM\EntityManager; | ||
| 7 | |||
| 8 | class ContactFormController | ||
| 9 | { | ||
| 10 | static public function updateRecipient(EntityManager $entityManager, array $json): void | ||
| 11 | { | ||
| 12 | $email = htmlspecialchars(trim($json['email'])); | ||
| 13 | |||
| 14 | if((filter_var($email, FILTER_VALIDATE_EMAIL) // nouvel e-mail | ||
| 15 | || ($json['email'] === '' && !empty(Config::$email_dest))) // e-mail par défaut | ||
| 16 | && isset($json['hidden']) && empty($json['hidden'])) | ||
| 17 | { | ||
| 18 | $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); | ||
| 19 | $form_data->updateData('email', $email); | ||
| 20 | $entityManager->persist($form_data); | ||
| 21 | $entityManager->flush(); | ||
| 22 | |||
| 23 | echo json_encode(['success' => true]); | ||
| 24 | } | ||
| 25 | else{ | ||
| 26 | echo json_encode(['success' => false]); | ||
| 27 | } | ||
| 28 | die; | ||
| 29 | } | ||
| 30 | static public function sendTestEmail(EntityManager $entityManager, array $json): void | ||
| 31 | { | ||
| 32 | // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur | ||
| 33 | $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); | ||
| 34 | $recipient = $form_data->getData()['email'] ?? Config::$email_dest; | ||
| 35 | |||
| 36 | if(EmailController::send($recipient, false, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){ | ||
| 37 | echo json_encode(['success' => true]); | ||
| 38 | } | ||
| 39 | else{ | ||
| 40 | echo json_encode(['success' => false]); | ||
| 41 | } | ||
| 42 | die; | ||
| 43 | } | ||
| 44 | } \ No newline at end of file | ||
diff --git a/src/controller/EmailController.php b/src/controller/EmailController.php new file mode 100644 index 0000000..1eea257 --- /dev/null +++ b/src/controller/EmailController.php | |||
| @@ -0,0 +1,91 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/EmailController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use PHPMailer\PHPMailer\PHPMailer; | ||
| 7 | use PHPMailer\PHPMailer\Exception; | ||
| 8 | use App\Entity\Email; | ||
| 9 | use Doctrine\ORM\EntityManager; | ||
| 10 | |||
| 11 | class EmailController | ||
| 12 | { | ||
| 13 | static public function send(string $recipient, bool $true_email, string $name = '', string $email = '', string $message = ''): bool | ||
| 14 | { | ||
| 15 | $mail = new PHPMailer(true); // true => exceptions | ||
| 16 | $mail->CharSet = 'UTF-8'; | ||
| 17 | |||
| 18 | try{ | ||
| 19 | // Paramètres du serveur | ||
| 20 | $mail->isSMTP(); | ||
| 21 | $mail->Host = Config::$smtp_host; | ||
| 22 | $mail->SMTPAuth = true; | ||
| 23 | $mail->Port = 25; | ||
| 24 | |||
| 25 | if($mail->SMTPAuth){ | ||
| 26 | $mail->Username = Config::$smtp_username; // e-mail | ||
| 27 | $mail->Password = Config::$smtp_password; | ||
| 28 | $mail->SMTPSecure = Config::$smtp_secure; // tls (starttls) ou ssl (smtps) | ||
| 29 | if($mail->SMTPSecure === 'tls'){ | ||
| 30 | $mail->Port = 587; | ||
| 31 | } | ||
| 32 | elseif($mail->SMTPSecure === 'ssl'){ | ||
| 33 | $mail->Port = 465; | ||
| 34 | } | ||
| 35 | } | ||
| 36 | //var_dump($mail->smtpConnect());die; // test de connexion | ||
| 37 | |||
| 38 | // Expéditeur et destinataire | ||
| 39 | $mail->setFrom(strtolower(Config::$email_from), Config::$email_from_name); // expéditeur | ||
| 40 | $mail->addAddress(strtolower($recipient), Config::$email_dest_name); // destinataire | ||
| 41 | |||
| 42 | // Contenu | ||
| 43 | $mail->isHTML(true); | ||
| 44 | if($true_email){ | ||
| 45 | $mail->Subject = 'Message envoyé par: ' . $name . ' (' . $email . ') depuis le site web'; | ||
| 46 | |||
| 47 | } | ||
| 48 | else{ | ||
| 49 | $mail->Subject = "TEST d'un envoi d'e-mail depuis le site web"; | ||
| 50 | } | ||
| 51 | $mail->Body = $message; | ||
| 52 | $mail->AltBody = $message; | ||
| 53 | |||
| 54 | $mail->send(); | ||
| 55 | return true; | ||
| 56 | } | ||
| 57 | catch(Exception $e){ | ||
| 58 | return false; | ||
| 59 | //echo "Le message n'a pas pu être envoyé. Erreur : {$mail->ErrorInfo}"; | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | static public function submit(array $json, EntityManager $entityManager): void | ||
| 64 | { | ||
| 65 | $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; | ||
| 66 | $captcha_try = isset($json['captcha']) ? Captcha::controlInput($json['captcha']) : 0; | ||
| 67 | |||
| 68 | // contrôles des entrées | ||
| 69 | $name = htmlspecialchars(trim($json['name'])); | ||
| 70 | $email = strtolower(htmlspecialchars(trim($json['email']))); | ||
| 71 | $message = htmlspecialchars(trim($json['message'])); | ||
| 72 | |||
| 73 | // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur | ||
| 74 | $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); | ||
| 75 | $recipient = $form_data->getData()['email'] ?? Config::$email_dest; | ||
| 76 | |||
| 77 | if($captcha_try != 0 && $captcha_solution != 0 && ($captcha_try === $captcha_solution) | ||
| 78 | && filter_var($email, FILTER_VALIDATE_EMAIL) && isset($json['hidden']) && empty($json['hidden']) | ||
| 79 | && self::send($recipient, true, $name, $email, $message)) | ||
| 80 | { | ||
| 81 | $db_email = new Email($email, Config::$email_dest, $message); | ||
| 82 | $entityManager->persist($db_email); | ||
| 83 | $entityManager->flush(); | ||
| 84 | echo json_encode(['success' => true]); | ||
| 85 | } | ||
| 86 | else{ | ||
| 87 | echo json_encode(['success' => false]); | ||
| 88 | } | ||
| 89 | die; | ||
| 90 | } | ||
| 91 | } \ No newline at end of file | ||
diff --git a/src/controller/ImageUploadController.php b/src/controller/ImageUploadController.php new file mode 100644 index 0000000..29b8059 --- /dev/null +++ b/src/controller/ImageUploadController.php | |||
| @@ -0,0 +1,184 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ImageUploadController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | class ImageUploadController | ||
| 7 | { | ||
| 8 | static public function imagickCleanImage(string $image_data, string $local_path, string $format = 'jpeg'): bool // "string" parce que file_get_contents... | ||
| 9 | { | ||
| 10 | try{ | ||
| 11 | $imagick = new Imagick(); | ||
| 12 | $imagick->readImageBlob($image_data); | ||
| 13 | $imagick->stripImage(); // nettoyage métadonnées | ||
| 14 | $imagick->setImageFormat($format); | ||
| 15 | if($format === 'jpeg'){ | ||
| 16 | $imagick->setImageCompression(Imagick::COMPRESSION_JPEG); | ||
| 17 | $imagick->setImageCompressionQuality(85); // optionnel | ||
| 18 | } | ||
| 19 | $imagick->writeImage($local_path); // enregistrement | ||
| 20 | $imagick->clear(); | ||
| 21 | $imagick->destroy(); | ||
| 22 | return true; | ||
| 23 | } | ||
| 24 | catch(Exception $e){ | ||
| 25 | return false; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | static public function curlDownloadImage(string $url, $maxRetries = 3, $timeout = 10): string|false | ||
| 29 | { | ||
| 30 | $attempt = 0; | ||
| 31 | $imageData = false; | ||
| 32 | |||
| 33 | while($attempt < $maxRetries){ | ||
| 34 | $ch = curl_init($url); // instance de CurlHandle | ||
| 35 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
| 36 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); | ||
| 37 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); | ||
| 38 | curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); | ||
| 39 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); | ||
| 40 | curl_setopt($ch, CURLOPT_USERAGENT, 'TinyMCE-Image-Downloader'); | ||
| 41 | |||
| 42 | $imageData = curl_exec($ch); | ||
| 43 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | ||
| 44 | //$curlError = curl_error($ch); | ||
| 45 | |||
| 46 | curl_close($ch); | ||
| 47 | |||
| 48 | if($imageData !== false && $httpCode >= 200 && $httpCode < 300){ | ||
| 49 | return $imageData; | ||
| 50 | } | ||
| 51 | |||
| 52 | $attempt++; | ||
| 53 | sleep(1); | ||
| 54 | } | ||
| 55 | |||
| 56 | return false; // échec après trois tentatives | ||
| 57 | } | ||
| 58 | |||
| 59 | // téléchargement par le plugin (bouton "insérer une image") | ||
| 60 | static public function imageUploadTinyMce(): void | ||
| 61 | { | ||
| 62 | if(isset($_FILES['file'])){ | ||
| 63 | $file = $_FILES['file']; | ||
| 64 | $dest = 'images/'; | ||
| 65 | $dest_mini = 'images-mini/'; | ||
| 66 | |||
| 67 | // Vérifier si les répertoires existent, sinon les créer | ||
| 68 | if(!is_dir($dest)) { | ||
| 69 | mkdir($dest, 0700, true); | ||
| 70 | } | ||
| 71 | if(!is_dir($dest_mini)) { | ||
| 72 | mkdir($dest_mini, 0700, true); | ||
| 73 | } | ||
| 74 | |||
| 75 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
| 76 | $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME)); | ||
| 77 | $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); | ||
| 78 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
| 79 | $extension = 'jpeg'; | ||
| 80 | } | ||
| 81 | $file_path = $dest . $name . '_' . uniqid() . '.' . $extension; | ||
| 82 | |||
| 83 | // créer une miniature de l'image | ||
| 84 | // | ||
| 85 | |||
| 86 | if(self::imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer | ||
| 87 | echo json_encode(['location' => $file_path]); // renvoyer l'URL de l'image téléchargée | ||
| 88 | } | ||
| 89 | else{ | ||
| 90 | http_response_code(500); | ||
| 91 | echo json_encode(['message' => 'Erreur image non valide']); | ||
| 92 | } | ||
| 93 | } | ||
| 94 | else{ | ||
| 95 | http_response_code(400); | ||
| 96 | echo json_encode(['message' => 'Erreur 400: Bad Request']); | ||
| 97 | } | ||
| 98 | die; | ||
| 99 | } | ||
| 100 | |||
| 101 | // collage de HTML => recherche de balises <img>, téléchargement côté serveur et renvoi de l'adresse sur le serveur | ||
| 102 | static public function uploadImageHtml(): void | ||
| 103 | { | ||
| 104 | $json = json_decode(file_get_contents('php://input'), true); | ||
| 105 | |||
| 106 | if(isset($json['image_url'])){ | ||
| 107 | $image_data = self::curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents | ||
| 108 | $dest = 'images/'; | ||
| 109 | |||
| 110 | if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer | ||
| 111 | mkdir($dest, 0777, true); | ||
| 112 | } | ||
| 113 | |||
| 114 | if($image_data === false){ | ||
| 115 | http_response_code(400); | ||
| 116 | echo json_encode(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."]); | ||
| 117 | die; | ||
| 118 | } | ||
| 119 | |||
| 120 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
| 121 | $url_path = parse_url($json['image_url'], PHP_URL_PATH); | ||
| 122 | $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME)); | ||
| 123 | $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION)); | ||
| 124 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
| 125 | $extension = 'jpeg'; | ||
| 126 | } | ||
| 127 | $local_path = $dest . $name . '_' . uniqid() . '.' . $extension; | ||
| 128 | |||
| 129 | if(self::imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer | ||
| 130 | echo json_encode(['location' => $local_path]); // nouvelle adresse | ||
| 131 | } | ||
| 132 | else{ | ||
| 133 | http_response_code(500); | ||
| 134 | echo json_encode(['message' => 'Erreur image non valide']); | ||
| 135 | } | ||
| 136 | } | ||
| 137 | else{ | ||
| 138 | echo json_encode(['message' => 'Erreur 400: Bad Request']); | ||
| 139 | } | ||
| 140 | die; | ||
| 141 | } | ||
| 142 | |||
| 143 | // collage simple d'une image (base64 dans le presse-papier) non encapsulée dans du HTML | ||
| 144 | static public function uploadImageBase64(): void | ||
| 145 | { | ||
| 146 | $json = json_decode(file_get_contents('php://input'), true); | ||
| 147 | $dest = 'images/'; | ||
| 148 | |||
| 149 | if(!is_dir('images')){ | ||
| 150 | mkdir('images', 0777, true); | ||
| 151 | } | ||
| 152 | |||
| 153 | // détection de data:image/ et de ;base64, et capture du format dans $type | ||
| 154 | if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){ | ||
| 155 | http_response_code(400); | ||
| 156 | echo json_encode(['message' => 'Données image base64 manquantes ou invalides']); | ||
| 157 | die; | ||
| 158 | } | ||
| 159 | |||
| 160 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
| 161 | $extension = strtolower($type[1]); | ||
| 162 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
| 163 | $extension = 'jpeg'; | ||
| 164 | } | ||
| 165 | |||
| 166 | $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire | ||
| 167 | if($image_data === false){ | ||
| 168 | http_response_code(400); | ||
| 169 | echo json_encode(['message' => 'Décodage base64 invalide']); | ||
| 170 | die; | ||
| 171 | } | ||
| 172 | |||
| 173 | $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension; | ||
| 174 | |||
| 175 | if(self::imagickCleanImage($image_data, $local_path)){ | ||
| 176 | echo json_encode(['location' => $local_path]); | ||
| 177 | } | ||
| 178 | else{ | ||
| 179 | http_response_code(500); | ||
| 180 | echo json_encode(['message' => 'Erreur image non valide']); | ||
| 181 | } | ||
| 182 | die; | ||
| 183 | } | ||
| 184 | } \ No newline at end of file | ||
diff --git a/src/controller/MenuAndPathsController.php b/src/controller/MenuAndPathsController.php new file mode 100644 index 0000000..d429287 --- /dev/null +++ b/src/controller/MenuAndPathsController.php | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/MenuAndPathsController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use App\Entity\Page; | ||
| 7 | use Doctrine\ORM\EntityManager; | ||
| 8 | |||
| 9 | class MenuAndPathsController | ||
| 10 | { | ||
| 11 | static public function newUrlMenuEntry(EntityManager $entityManager): void | ||
| 12 | { | ||
| 13 | Director::$menu_data = new Menu($entityManager); | ||
| 14 | $previous_page = Director::$menu_data->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1); | ||
| 15 | $parent = $previous_page->getParent(); | ||
| 16 | |||
| 17 | $page = new Page( | ||
| 18 | trim(htmlspecialchars($_POST["label_input"])), | ||
| 19 | filter_var($_POST["url_input"], FILTER_VALIDATE_URL), | ||
| 20 | true, true, false, | ||
| 21 | $previous_page->getPosition(), | ||
| 22 | $parent); // peut et DOIT être null si on est au 1er niveau | ||
| 23 | |||
| 24 | // on a donné à la nouvelle entrée la même position qu'à la précédente, | ||
| 25 | // addChild l'ajoute à la fin du tableau "children" puis on trie | ||
| 26 | // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position | ||
| 27 | if($parent == null){ | ||
| 28 | $parent = Director::$menu_data; | ||
| 29 | } | ||
| 30 | $parent->addChild($page); // true pour réindexer les positions en BDD | ||
| 31 | $parent->reindexPositions(); | ||
| 32 | |||
| 33 | $entityManager->persist($page); | ||
| 34 | $entityManager->flush(); | ||
| 35 | header("Location: " . new URL(['page' => $_GET['from']])); | ||
| 36 | die; | ||
| 37 | } | ||
| 38 | |||
| 39 | static public function deleteUrlMenuEntry(EntityManager $entityManager): void | ||
| 40 | { | ||
| 41 | Director::$menu_data = new Menu($entityManager); | ||
| 42 | $page = Director::$menu_data->findPageById((int)$_POST["delete"]); | ||
| 43 | $parent = $page->getParent(); | ||
| 44 | if($parent == null){ | ||
| 45 | $parent = Director::$menu_data; | ||
| 46 | } | ||
| 47 | |||
| 48 | $parent->removeChild($page); // suppression de $children avant de trier | ||
| 49 | $parent->reindexPositions(); | ||
| 50 | |||
| 51 | $entityManager->remove($page); // suppression en BDD | ||
| 52 | $entityManager->flush(); | ||
| 53 | header("Location: " . new URL(['page' => $_GET['from']])); | ||
| 54 | die; | ||
| 55 | } | ||
| 56 | |||
| 57 | static public function MoveOneLevelUp(EntityManager $entityManager, array $json): void | ||
| 58 | { | ||
| 59 | $id = $json['id']; | ||
| 60 | $page = Director::$menu_data->findPageById((int)$id); | ||
| 61 | |||
| 62 | $parent = $page->getParent(); // peut être null | ||
| 63 | if($parent === null){ | ||
| 64 | // 1er niveau: ne rien faire | ||
| 65 | echo json_encode(['success' => false]); | ||
| 66 | die; | ||
| 67 | } | ||
| 68 | // BDD | ||
| 69 | else{ | ||
| 70 | $page->setPosition($parent->getPosition() + 1); // nouvelle position | ||
| 71 | |||
| 72 | // 2ème niveau: le parent devient $menu_data, puis null après tri | ||
| 73 | if($parent->getParent() === null){ | ||
| 74 | // connexion dans les deux sens | ||
| 75 | $page->setParent(Director::$menu_data); // => pour la persistance | ||
| 76 | |||
| 77 | //Director::$menu_data->addChild($page); // => pour sortChildren | ||
| 78 | $page->getParent()->addChild($page); // => pour sortChildren | ||
| 79 | //Director::$menu_data->sortChildren(true); // positions décaléees des nouveaux petits frères | ||
| 80 | $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères | ||
| 81 | $page->setParent(null); | ||
| 82 | |||
| 83 | // affichage | ||
| 84 | $page->setPagePath($page->getEndOfPath()); | ||
| 85 | $page->fillChildrenPagePath(); | ||
| 86 | } | ||
| 87 | // 3ème niveau et plus | ||
| 88 | else{ | ||
| 89 | $page->setParent($parent->getParent()); // nouveau parent | ||
| 90 | $page->getParent()->addChild($page); // => pour sortChildren | ||
| 91 | $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères | ||
| 92 | $page->fillChildrenPagePath($page->getParent()->getPagePath()); | ||
| 93 | } | ||
| 94 | //$parent->sortChildren(true); // positions des enfants restants, inutile si la fonction est récursive? | ||
| 95 | $entityManager->flush(); | ||
| 96 | |||
| 97 | // affichage | ||
| 98 | $parent->removeChild($page); | ||
| 99 | $nav_builder = new NavBuilder(); | ||
| 100 | $menu_builder = new MenuBuilder(null, false); | ||
| 101 | echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]); | ||
| 102 | die; | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 106 | static public function MoveOneLevelDown(EntityManager $entityManager, array $json): void | ||
| 107 | { | ||
| 108 | $id = $json['id']; | ||
| 109 | $page = Director::$menu_data->findPageById((int)$id); | ||
| 110 | |||
| 111 | $parent = $page->getParent(); // peut être null | ||
| 112 | if($parent == null){ | ||
| 113 | $parent = Director::$menu_data; | ||
| 114 | } | ||
| 115 | |||
| 116 | // BDD | ||
| 117 | $parent->sortChildren(true); // trie et réindexe par sécurité: 1, 2, 3... | ||
| 118 | if($page->getPosition() > 1){ | ||
| 119 | foreach($parent->getChildren() as $child){ | ||
| 120 | if($child->getPosition() === $page->getPosition() - 1){ | ||
| 121 | $page->setParent($child); | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | $page->setPosition(count($page->getParent()->getChildren()) + 1); | ||
| 126 | } | ||
| 127 | $entityManager->flush(); | ||
| 128 | |||
| 129 | // affichage | ||
| 130 | $parent->removeChild($page); | ||
| 131 | $page->getParent()->addChild($page); | ||
| 132 | $page->fillChildrenPagePath($page->getParent()->getPagePath()); // variable non mappée $page_path | ||
| 133 | $nav_builder = new NavBuilder(); | ||
| 134 | $menu_builder = new MenuBuilder(null, false); | ||
| 135 | |||
| 136 | echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]); | ||
| 137 | die; | ||
| 138 | } | ||
| 139 | |||
| 140 | static public function SwitchPositions(EntityManager $entityManager, array $json): void | ||
| 141 | { | ||
| 142 | $id1 = $json['id1']; | ||
| 143 | $id2 = $json['id2']; | ||
| 144 | |||
| 145 | // vérifier qu'ils ont le même parent | ||
| 146 | $page1 = Director::$menu_data->findPageById((int)$id1); | ||
| 147 | $page2 = Director::$menu_data->findPageById((int)$id2); | ||
| 148 | |||
| 149 | // double le contrôle fait en JS | ||
| 150 | if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?) | ||
| 151 | { | ||
| 152 | // inversion | ||
| 153 | $tmp = $page1->getPosition(); | ||
| 154 | $page1->setPosition($page2->getPosition()); | ||
| 155 | $page2->setPosition($tmp); | ||
| 156 | Director::$menu_data->sortChildren(true); // modifie tableau children | ||
| 157 | $entityManager->flush(); | ||
| 158 | |||
| 159 | // nouveau menu | ||
| 160 | $nav_builder = new NavBuilder(); | ||
| 161 | echo json_encode(['success' => true, 'nav' => $nav_builder->render()]); | ||
| 162 | } | ||
| 163 | else{ | ||
| 164 | echo json_encode(['success' => false]); | ||
| 165 | } | ||
| 166 | |||
| 167 | die; | ||
| 168 | } | ||
| 169 | |||
| 170 | static public function displayInMenu(EntityManager $entityManager, array $json): void | ||
| 171 | { | ||
| 172 | $id = $json['id']; | ||
| 173 | $checked = $json['checked']; | ||
| 174 | |||
| 175 | $page = Director::$menu_data->findPageById((int)$id); | ||
| 176 | if($page->isHidden() === $checked){ | ||
| 177 | $page->setHidden(!$checked); | ||
| 178 | $entityManager->flush(); | ||
| 179 | |||
| 180 | // nouveau menu | ||
| 181 | $nav_builder = new NavBuilder(); | ||
| 182 | echo json_encode(['success' => true, 'nav' => $nav_builder->render()]); | ||
| 183 | } | ||
| 184 | else{ | ||
| 185 | echo json_encode(['success' => false]); | ||
| 186 | } | ||
| 187 | die; | ||
| 188 | } | ||
| 189 | } \ No newline at end of file | ||
diff --git a/src/controller/PageManagementController.php b/src/controller/PageManagementController.php new file mode 100644 index 0000000..f84c528 --- /dev/null +++ b/src/controller/PageManagementController.php | |||
| @@ -0,0 +1,264 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/PageManagementController.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use App\Entity\Page; | ||
| 7 | use App\Entity\Node; | ||
| 8 | use App\Entity\NodeData; | ||
| 9 | //use App\Entity\Image; | ||
| 10 | use Doctrine\Common\Collections\ArrayCollection; | ||
| 11 | use Doctrine\ORM\EntityManager; | ||
| 12 | |||
| 13 | class PageManagementController | ||
| 14 | { | ||
| 15 | /* -- partie page -- */ | ||
| 16 | static public function setPageTitle(EntityManager $entityManager, array $json): void | ||
| 17 | { | ||
| 18 | $page = $entityManager->find('App\Entity\Page', $json['page_id']); | ||
| 19 | $page->setPageName(htmlspecialchars($json['title'])); | ||
| 20 | $entityManager->flush(); | ||
| 21 | echo json_encode(['success' => true, 'title' => $page->getPageName()]); | ||
| 22 | die; | ||
| 23 | } | ||
| 24 | |||
| 25 | static public function updatePageMenuPath(EntityManager $entityManager): void | ||
| 26 | { | ||
| 27 | Director::$menu_data = new Menu($entityManager); | ||
| 28 | Director::$page_path = new Path(); | ||
| 29 | $page = Director::$page_path->getLast(); | ||
| 30 | $path = htmlspecialchars($_POST['page_menu_path']); | ||
| 31 | |||
| 32 | // mise en snake_case: filtre caractères non-alphanumériques, minuscule, doublons d'underscore, trim des underscores | ||
| 33 | $path = trim(preg_replace('/_+/', '_', strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $path))), '_'); | ||
| 34 | $page->setEndOfPath($path); | ||
| 35 | foreach(Director::$menu_data->getChildren() as $child){ | ||
| 36 | if($child->getEndOfPath() === Director::$page_path->getArray()[0]->getEndOfPath()){ | ||
| 37 | $child->fillChildrenPagePath(); // MAJ de $page_path | ||
| 38 | } | ||
| 39 | } | ||
| 40 | $entityManager->flush(); | ||
| 41 | header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page'])); | ||
| 42 | die; | ||
| 43 | } | ||
| 44 | |||
| 45 | static public function setPageDescription(EntityManager $entityManager, array $json): void | ||
| 46 | { | ||
| 47 | $node_data = $entityManager->find('App\Entity\NodeData', $json['node_data_id']); | ||
| 48 | $node_data->updateData('description', htmlspecialchars($json['description'])); | ||
| 49 | $entityManager->flush(); | ||
| 50 | echo json_encode(['success' => true, 'description' => $node_data->getData()['description']]); | ||
| 51 | die; | ||
| 52 | } | ||
| 53 | |||
| 54 | static public function newPage(EntityManager $entityManager): void | ||
| 55 | { | ||
| 56 | // titre et chemin | ||
| 57 | $director = new Director($entityManager, true); | ||
| 58 | //Director::$menu_data = new Menu($entityManager); | ||
| 59 | $previous_page = Director::$menu_data->findPageById((int)$_POST["page_location"]); // (int) à cause de declare(strict_types=1); | ||
| 60 | $parent = $previous_page->getParent(); | ||
| 61 | |||
| 62 | $page = new Page( | ||
| 63 | trim(htmlspecialchars($_POST["page_name"])), | ||
| 64 | trim(htmlspecialchars($_POST["page_name_path"])), | ||
| 65 | true, true, false, | ||
| 66 | $previous_page->getPosition(), | ||
| 67 | $parent); // peut et DOIT être null si on est au 1er niveau | ||
| 68 | |||
| 69 | // on a donné à la nouvelle entrée la même position qu'à la précédente, | ||
| 70 | // addChild l'ajoute à la fin du tableau "children" puis on trie | ||
| 71 | // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position | ||
| 72 | if($parent == null){ | ||
| 73 | $parent = Director::$menu_data; | ||
| 74 | } | ||
| 75 | $parent->addChild($page); | ||
| 76 | $parent->reindexPositions(); | ||
| 77 | |||
| 78 | $page->setPagePath(ltrim($parent->getPagePath() . '/' . $page->getEndOfPath(), '/')); | ||
| 79 | |||
| 80 | // noeud "head" | ||
| 81 | $node = new Node( | ||
| 82 | 'head', | ||
| 83 | null, [], | ||
| 84 | 1, // position d'un head = 1 | ||
| 85 | null, // pas de parent | ||
| 86 | $page); | ||
| 87 | $node->useDefaultAttributes(); // fichiers CSS et JS | ||
| 88 | |||
| 89 | $data = new NodeData([ | ||
| 90 | // pas de titre, il est dans $page | ||
| 91 | 'description' => trim(htmlspecialchars($_POST["page_description"]))], | ||
| 92 | $node); | ||
| 93 | |||
| 94 | $bulk_data = $entityManager | ||
| 95 | ->createQuery('SELECT n FROM App\Entity\Image n WHERE n.file_name LIKE :name') | ||
| 96 | ->setParameter('name', '%favicon%') | ||
| 97 | ->getResult(); | ||
| 98 | $data->setImages(new ArrayCollection($bulk_data)); | ||
| 99 | |||
| 100 | $entityManager->persist($page); | ||
| 101 | $entityManager->persist($node); | ||
| 102 | $entityManager->persist($data); | ||
| 103 | $entityManager->flush(); | ||
| 104 | |||
| 105 | // page créée, direction la page en mode modification pour ajouter des blocs | ||
| 106 | header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page'])); | ||
| 107 | die; | ||
| 108 | } | ||
| 109 | |||
| 110 | static public function deletePage(EntityManager $entityManager): void | ||
| 111 | { | ||
| 112 | $page = $entityManager->find('App\Entity\Page', (int)$_POST['page_id']); | ||
| 113 | $nodes = $entityManager->getRepository('App\Entity\Node')->findBy(['page' => $page]); | ||
| 114 | $data = []; | ||
| 115 | foreach($nodes as $node){ | ||
| 116 | $data[] = $entityManager->getRepository('App\Entity\NodeData')->findOneBy(['node' => $node]); | ||
| 117 | $entityManager->remove($node); | ||
| 118 | } | ||
| 119 | foreach($data as $one_data){ | ||
| 120 | $entityManager->remove($one_data); | ||
| 121 | } | ||
| 122 | $entityManager->remove($page); // suppression en BDD | ||
| 123 | |||
| 124 | $entityManager->flush(); | ||
| 125 | header("Location: " . new URL); | ||
| 126 | die; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* partie "blocs" */ | ||
| 130 | static public function addBloc(EntityManager $entityManager): void | ||
| 131 | { | ||
| 132 | $director = new Director($entityManager, true); // on a besoin de page_path qui dépend de menu_data | ||
| 133 | $page = Director::$page_path->getLast(); | ||
| 134 | $director->findUniqueNodeByName('main'); | ||
| 135 | $director->findItsChildren(); | ||
| 136 | $main = $director->getNode(); | ||
| 137 | $position = count($main->getChildren()) + 1; // position dans la fraterie | ||
| 138 | |||
| 139 | $blocks = ['blog', 'grid', 'calendar', 'galery', 'form']; // même liste dans FormBuilder.php | ||
| 140 | if(!in_array($_POST["bloc_select"], $blocks, true)) // 3è param: contrôle du type | ||
| 141 | { | ||
| 142 | header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'bad_bloc_type'])); | ||
| 143 | die; | ||
| 144 | } | ||
| 145 | |||
| 146 | if($_POST["bloc_select"] === 'calendar' || $_POST["bloc_select"] === 'form'){ | ||
| 147 | $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page AND n.name_node = :name'; // noeud 'head' de la page | ||
| 148 | $bulk_data = $entityManager | ||
| 149 | ->createQuery($dql) | ||
| 150 | ->setParameter('page', $page) | ||
| 151 | ->setParameter('name', 'head') | ||
| 152 | ->getResult(); | ||
| 153 | |||
| 154 | if(count($bulk_data) != 1){ // 1 head par page | ||
| 155 | header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'head_node_not_found'])); | ||
| 156 | die; | ||
| 157 | } | ||
| 158 | |||
| 159 | $bulk_data[0]->addAttribute('css_array', $_POST["bloc_select"]); | ||
| 160 | if($_POST["bloc_select"] === 'form'){ | ||
| 161 | $bulk_data[0]->addAttribute('js_array', $_POST["bloc_select"]); | ||
| 162 | } | ||
| 163 | $entityManager->persist($bulk_data[0]); | ||
| 164 | } | ||
| 165 | |||
| 166 | $bloc = new Node( | ||
| 167 | $_POST["bloc_select"], | ||
| 168 | null, [], | ||
| 169 | $position, | ||
| 170 | $main, | ||
| 171 | $page); | ||
| 172 | $data = new NodeData( | ||
| 173 | ['title' => trim(htmlspecialchars($_POST["bloc_title"]))], | ||
| 174 | $bloc); | ||
| 175 | |||
| 176 | $entityManager->persist($bloc); | ||
| 177 | $entityManager->persist($data); | ||
| 178 | $entityManager->flush(); | ||
| 179 | header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page'])); | ||
| 180 | die; | ||
| 181 | } | ||
| 182 | |||
| 183 | static public function deleteBloc(EntityManager $entityManager): void | ||
| 184 | { | ||
| 185 | $director = new Director($entityManager, true); | ||
| 186 | $director->findUniqueNodeByName('main'); | ||
| 187 | $director->findItsChildren(); | ||
| 188 | //$director->findNodeById((int)$_POST['delete_bloc_id']); | ||
| 189 | $main = $director->getNode(); | ||
| 190 | $bloc = null; | ||
| 191 | foreach($main->getChildren() as $child){ | ||
| 192 | if($child->getId() === (int)$_POST['delete_bloc_id']){ | ||
| 193 | $bloc = $child; | ||
| 194 | break; | ||
| 195 | } | ||
| 196 | } | ||
| 197 | if(!empty($bloc)){ // si $bloc est null c'est que le HTML a été modifié volontairement | ||
| 198 | $main->removeChild($bloc); // réindex le tableau $children au passage | ||
| 199 | $main->reindexPositions(); | ||
| 200 | $entityManager->remove($bloc); // suppression en BDD | ||
| 201 | $entityManager->flush(); | ||
| 202 | } | ||
| 203 | header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page'])); | ||
| 204 | die; | ||
| 205 | } | ||
| 206 | |||
| 207 | static public function renameBloc(EntityManager $entityManager, array $json): void | ||
| 208 | { | ||
| 209 | if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){ | ||
| 210 | $director = new Director($entityManager); | ||
| 211 | $director->findNodeById($json['bloc_id']); | ||
| 212 | |||
| 213 | // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé | ||
| 214 | $data = $director->getNode()->getNodeData()->getData(); | ||
| 215 | $data['title'] = htmlspecialchars($json['bloc_title']); | ||
| 216 | $director->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title'])); | ||
| 217 | |||
| 218 | $entityManager->flush(); | ||
| 219 | echo json_encode(['success' => true, 'title' => $data['title']]); | ||
| 220 | } | ||
| 221 | else{ | ||
| 222 | echo json_encode(['success' => false]); | ||
| 223 | } | ||
| 224 | die; | ||
| 225 | } | ||
| 226 | |||
| 227 | static public function SwitchBlocsPositions(EntityManager $entityManager, array $json): void | ||
| 228 | { | ||
| 229 | if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($_GET['page'])){ | ||
| 230 | $director = new Director($entityManager, true); | ||
| 231 | $director->findUniqueNodeByName('main'); | ||
| 232 | $director->findItsChildren(); | ||
| 233 | $main = $director->getNode(); | ||
| 234 | $main->sortChildren(true); // régénère les positions avant inversion | ||
| 235 | |||
| 236 | $bloc1 = null; | ||
| 237 | $bloc2 = null; | ||
| 238 | foreach($main->getChildren() as $child){ | ||
| 239 | if($child->getId() === $json['id1']){ | ||
| 240 | $bloc1 = $child; | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | foreach($main->getChildren() as $child){ | ||
| 245 | if($child->getId() === $json['id2']){ | ||
| 246 | $bloc2 = $child; | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | |||
| 251 | // inversion | ||
| 252 | $tmp = $bloc1->getPosition(); | ||
| 253 | $bloc1->setPosition($bloc2->getPosition()); | ||
| 254 | $bloc2->setPosition($tmp); | ||
| 255 | |||
| 256 | $entityManager->flush(); | ||
| 257 | echo json_encode(['success' => true]); | ||
| 258 | } | ||
| 259 | else{ | ||
| 260 | echo json_encode(['success' => false]); | ||
| 261 | } | ||
| 262 | die; | ||
| 263 | } | ||
| 264 | } \ No newline at end of file | ||
diff --git a/src/controller/ajax_admin.php b/src/controller/ajax_admin.php deleted file mode 100644 index b69be77..0000000 --- a/src/controller/ajax_admin.php +++ /dev/null | |||
| @@ -1,636 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ajax_admin.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use App\Entity\Page; | ||
| 7 | use App\Entity\Node; | ||
| 8 | use App\Entity\Article; | ||
| 9 | |||
| 10 | // mettre ça ailleurs | ||
| 11 | function imagickCleanImage(string $image_data, string $local_path, string $format = 'jpeg'): bool // "string" parce que file_get_contents... | ||
| 12 | { | ||
| 13 | try{ | ||
| 14 | $imagick = new Imagick(); | ||
| 15 | $imagick->readImageBlob($image_data); | ||
| 16 | $imagick->stripImage(); // nettoyage métadonnées | ||
| 17 | $imagick->setImageFormat($format); | ||
| 18 | if($format === 'jpeg'){ | ||
| 19 | $imagick->setImageCompression(Imagick::COMPRESSION_JPEG); | ||
| 20 | $imagick->setImageCompressionQuality(85); // optionnel | ||
| 21 | } | ||
| 22 | $imagick->writeImage($local_path); // enregistrement | ||
| 23 | $imagick->clear(); | ||
| 24 | $imagick->destroy(); | ||
| 25 | return true; | ||
| 26 | } | ||
| 27 | catch(Exception $e){ | ||
| 28 | return false; | ||
| 29 | } | ||
| 30 | } | ||
| 31 | function curlDownloadImage(string $url, $maxRetries = 3, $timeout = 10): string|false | ||
| 32 | { | ||
| 33 | $attempt = 0; | ||
| 34 | $imageData = false; | ||
| 35 | |||
| 36 | while($attempt < $maxRetries){ | ||
| 37 | $ch = curl_init($url); // instance de CurlHandle | ||
| 38 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | ||
| 39 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); | ||
| 40 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); | ||
| 41 | curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); | ||
| 42 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); | ||
| 43 | curl_setopt($ch, CURLOPT_USERAGENT, 'TinyMCE-Image-Downloader'); | ||
| 44 | |||
| 45 | $imageData = curl_exec($ch); | ||
| 46 | $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); | ||
| 47 | //$curlError = curl_error($ch); | ||
| 48 | |||
| 49 | curl_close($ch); | ||
| 50 | |||
| 51 | if($imageData !== false && $httpCode >= 200 && $httpCode < 300){ | ||
| 52 | return $imageData; | ||
| 53 | } | ||
| 54 | |||
| 55 | $attempt++; | ||
| 56 | sleep(1); | ||
| 57 | } | ||
| 58 | |||
| 59 | return false; // échec après trois tentatives | ||
| 60 | } | ||
| 61 | |||
| 62 | function imageUploadTinyMce(): void | ||
| 63 | { | ||
| 64 | if(isset($_FILES['file'])){ | ||
| 65 | $file = $_FILES['file']; | ||
| 66 | $dest = 'images/'; | ||
| 67 | $dest_mini = 'images-mini/'; | ||
| 68 | |||
| 69 | // Vérifier si les répertoires existent, sinon les créer | ||
| 70 | if(!is_dir($dest)) { | ||
| 71 | mkdir($dest, 0700, true); | ||
| 72 | } | ||
| 73 | if(!is_dir($dest_mini)) { | ||
| 74 | mkdir($dest_mini, 0700, true); | ||
| 75 | } | ||
| 76 | |||
| 77 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
| 78 | $name = Security::secureFileName(pathinfo($file['name'], PATHINFO_FILENAME)); | ||
| 79 | $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); | ||
| 80 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
| 81 | $extension = 'jpeg'; | ||
| 82 | } | ||
| 83 | $file_path = $dest . $name . '_' . uniqid() . '.' . $extension; | ||
| 84 | |||
| 85 | // créer une miniature de l'image | ||
| 86 | // | ||
| 87 | |||
| 88 | if(imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer | ||
| 89 | echo json_encode(['location' => $file_path]); // renvoyer l'URL de l'image téléchargée | ||
| 90 | } | ||
| 91 | else{ | ||
| 92 | http_response_code(500); | ||
| 93 | echo json_encode(['message' => 'Erreur image non valide']); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | else{ | ||
| 97 | http_response_code(400); | ||
| 98 | echo json_encode(['message' => 'Erreur 400: Bad Request']); | ||
| 99 | } | ||
| 100 | die; | ||
| 101 | } | ||
| 102 | |||
| 103 | // détection des requêtes d'upload d'image de tinymce | ||
| 104 | if(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false && isset($_GET['action']) && $_GET['action'] === 'upload_image') | ||
| 105 | { | ||
| 106 | imageUploadTinyMce(); | ||
| 107 | } | ||
| 108 | // cas du collage d'un contenu HTML, réception d'une URL, téléchargement par le serveur et renvoie de l'adresse sur le serveur | ||
| 109 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url') | ||
| 110 | { | ||
| 111 | $json = json_decode(file_get_contents('php://input'), true); | ||
| 112 | |||
| 113 | if(isset($json['image_url'])){ | ||
| 114 | $image_data = curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents | ||
| 115 | $dest = 'images/'; | ||
| 116 | |||
| 117 | if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer | ||
| 118 | mkdir($dest, 0777, true); | ||
| 119 | } | ||
| 120 | |||
| 121 | if($image_data === false){ | ||
| 122 | http_response_code(400); | ||
| 123 | echo json_encode(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."]); | ||
| 124 | die; | ||
| 125 | } | ||
| 126 | |||
| 127 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
| 128 | $url_path = parse_url($json['image_url'], PHP_URL_PATH); | ||
| 129 | $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME)); | ||
| 130 | $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION)); | ||
| 131 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
| 132 | $extension = 'jpeg'; | ||
| 133 | } | ||
| 134 | $local_path = $dest . $name . '_' . uniqid() . '.' . $extension; | ||
| 135 | |||
| 136 | if(imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer | ||
| 137 | echo json_encode(['location' => $local_path]); // nouvelle adresse | ||
| 138 | } | ||
| 139 | else{ | ||
| 140 | http_response_code(500); | ||
| 141 | echo json_encode(['message' => 'Erreur image non valide']); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | else{ | ||
| 145 | echo json_encode(['message' => 'Erreur 400: Bad Request']); | ||
| 146 | } | ||
| 147 | die; | ||
| 148 | } | ||
| 149 | // cas du collage d'une image (code base64) non encapsulée dans du HTML | ||
| 150 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64') | ||
| 151 | { | ||
| 152 | $json = json_decode(file_get_contents('php://input'), true); | ||
| 153 | $dest = 'images/'; | ||
| 154 | |||
| 155 | if(!is_dir('images')){ | ||
| 156 | mkdir('images', 0777, true); | ||
| 157 | } | ||
| 158 | |||
| 159 | // détection de data:image/ et de ;base64, et capture du format dans $type | ||
| 160 | if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){ | ||
| 161 | http_response_code(400); | ||
| 162 | echo json_encode(['message' => 'Données image base64 manquantes ou invalides']); | ||
| 163 | die; | ||
| 164 | } | ||
| 165 | |||
| 166 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | ||
| 167 | $extension = strtolower($type[1]); | ||
| 168 | if(!in_array($extension, $allowed_extensions) || $extension === 'jpg'){ | ||
| 169 | $extension = 'jpeg'; | ||
| 170 | } | ||
| 171 | |||
| 172 | $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire | ||
| 173 | if($image_data === false){ | ||
| 174 | http_response_code(400); | ||
| 175 | echo json_encode(['message' => 'Décodage base64 invalide']); | ||
| 176 | die; | ||
| 177 | } | ||
| 178 | |||
| 179 | $local_path = $dest . 'pasted_image_' . uniqid() . '.' . $extension; | ||
| 180 | |||
| 181 | if(imagickCleanImage($image_data, $local_path)){ | ||
| 182 | echo json_encode(['location' => $local_path]); | ||
| 183 | } | ||
| 184 | else{ | ||
| 185 | http_response_code(500); | ||
| 186 | echo json_encode(['message' => 'Erreur image non valide']); | ||
| 187 | } | ||
| 188 | die; | ||
| 189 | } | ||
| 190 | |||
| 191 | // détection des requêtes de type XHR, y en a pas à priori | ||
| 192 | /*elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'){ | ||
| 193 | echo "requête XHR reçue par le serveur"; | ||
| 194 | die; | ||
| 195 | }*/ | ||
| 196 | |||
| 197 | |||
| 198 | // détection des requêtes envoyées avec fetch (application/json) et récupération du JSON | ||
| 199 | if($_SERVER['CONTENT_TYPE'] === 'application/json') | ||
| 200 | { | ||
| 201 | $data = file_get_contents('php://input'); | ||
| 202 | $json = json_decode($data, true); | ||
| 203 | |||
| 204 | if(isset($_GET['action'])) | ||
| 205 | { | ||
| 206 | if($_GET['action'] === 'editor_submit' && isset($json['id']) && isset($json['content'])) | ||
| 207 | { | ||
| 208 | if(json_last_error() === JSON_ERROR_NONE) | ||
| 209 | { | ||
| 210 | $id = $json['id']; | ||
| 211 | $director = new Director($entityManager); | ||
| 212 | |||
| 213 | // cas d'une nouvelle "news" | ||
| 214 | if(is_array($json['content'])){ | ||
| 215 | foreach($json['content'] as $one_input){ | ||
| 216 | $one_input = Security::secureString($one_input); | ||
| 217 | } | ||
| 218 | $content = $json['content']; | ||
| 219 | } | ||
| 220 | else{ | ||
| 221 | $content = Security::secureString($json['content']); | ||
| 222 | } | ||
| 223 | |||
| 224 | // nouvel article | ||
| 225 | if($id[0] === 'n') | ||
| 226 | { | ||
| 227 | $section_id = (int)substr($id, 1); // id du bloc <section> | ||
| 228 | $director->findNodeById($section_id); | ||
| 229 | $director->makeSectionNode(); | ||
| 230 | $node = $director->getNode(); // = <section> | ||
| 231 | |||
| 232 | if(is_array($content)){ | ||
| 233 | $date = new \DateTime($content['d']); | ||
| 234 | $article = new Article($content['i'], $date, $content['t'], $content['p']); | ||
| 235 | $article_node = new Node('new', 'i' . (string)$date->getTimestamp(), [], count($node->getChildren()) + 1, $node, $node->getPage(), $article); | ||
| 236 | |||
| 237 | // id_node tout juste généré | ||
| 238 | //$article_node->getId(); | ||
| 239 | } | ||
| 240 | else{ | ||
| 241 | $timestamp = time(); | ||
| 242 | $date = new \DateTime; | ||
| 243 | $date->setTimestamp($timestamp); | ||
| 244 | |||
| 245 | $article = new Article($content, $date); // le "current" timestamp est obtenu par la BDD | ||
| 246 | $article_node = new Node('article', 'i' . (string)$timestamp, [], count($node->getChildren()) + 1, $node, $node->getPage(), $article); | ||
| 247 | } | ||
| 248 | |||
| 249 | $entityManager->persist($article_node); | ||
| 250 | $entityManager->flush(); | ||
| 251 | |||
| 252 | echo json_encode(['success' => true, 'article_id' => $article_node->getArticleTimestamp()]); | ||
| 253 | die; | ||
| 254 | } | ||
| 255 | // modification article | ||
| 256 | else{ | ||
| 257 | $id[0] = 'i'; // id de l'article node | ||
| 258 | } | ||
| 259 | |||
| 260 | if($director->makeArticleNode($id)) // une entrée est trouvée | ||
| 261 | { | ||
| 262 | $node = $director->getArticleNode(); // article | ||
| 263 | switch($json['id'][0]){ | ||
| 264 | case 'i': | ||
| 265 | $node->getArticle()->setContent($content); | ||
| 266 | break; | ||
| 267 | case 'p': | ||
| 268 | $node->getArticle()->setPreview($content); // html de l'éditeur | ||
| 269 | break; | ||
| 270 | case 't': | ||
| 271 | $node->getArticle()->setTitle($content); // html de l'éditeur | ||
| 272 | break; | ||
| 273 | case 'd': | ||
| 274 | echo json_encode(['success' => false, 'message' => 'l\'action editor_submit ne supporte pas les dates, utiliser date_submit.']); | ||
| 275 | die; | ||
| 276 | default: | ||
| 277 | echo json_encode(['success' => false, 'message' => 'identifiant non utilisable']); | ||
| 278 | die; | ||
| 279 | } | ||
| 280 | $entityManager->flush(); | ||
| 281 | echo json_encode(['success' => true]); | ||
| 282 | } | ||
| 283 | else | ||
| 284 | { | ||
| 285 | echo json_encode(['success' => false, 'message' => 'article non identifié']); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | else{ | ||
| 289 | echo json_encode(['success' => false, 'message' => 'Erreur de décodage JSON']); | ||
| 290 | } | ||
| 291 | die; | ||
| 292 | } | ||
| 293 | elseif($_GET['action'] === 'delete_article' && isset($json['id'])) | ||
| 294 | { | ||
| 295 | $director = new Director($entityManager); | ||
| 296 | $director->makeArticleNode($json['id'], true); | ||
| 297 | $article = $director->getArticleNode(); | ||
| 298 | $section = $director->getNode(); | ||
| 299 | |||
| 300 | $entityManager->remove($article); | ||
| 301 | $section->removeChild($article); | ||
| 302 | $section->sortChildren(true); // régénère les positions | ||
| 303 | $entityManager->flush(); | ||
| 304 | |||
| 305 | // test avec une nouvelle requête qui ne devrait rien trouver | ||
| 306 | if(!$director->makeArticleNode($json['id'])) | ||
| 307 | { | ||
| 308 | echo json_encode(['success' => true]); | ||
| 309 | |||
| 310 | // on pourrait afficher une notification "toast" | ||
| 311 | } | ||
| 312 | else{ | ||
| 313 | http_response_code(500); | ||
| 314 | echo json_encode(['success' => false, 'message' => 'Erreur lors de la suppression de l\'article.']); | ||
| 315 | } | ||
| 316 | die; | ||
| 317 | } | ||
| 318 | // inversion de la position de deux noeuds | ||
| 319 | elseif($_GET['action'] === 'switch_positions' && isset($json['id1']) && isset($json['id2'])) | ||
| 320 | { | ||
| 321 | $director = new Director($entityManager); | ||
| 322 | $director->makeArticleNode($json['id1'], true); | ||
| 323 | $article1 = $director->getArticleNode(); | ||
| 324 | $section = $director->getNode(); | ||
| 325 | |||
| 326 | $section->sortChildren(true); // régénère les positions avant inversion | ||
| 327 | |||
| 328 | $article2; | ||
| 329 | foreach($section->getChildren() as $child){ | ||
| 330 | if($child->getArticleTimestamp() === $json['id2']) // type string | ||
| 331 | { | ||
| 332 | $article2 = $child; | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | // inversion | ||
| 338 | $tmp = $article1->getPosition(); | ||
| 339 | $article1->setPosition($article2->getPosition()); | ||
| 340 | $article2->setPosition($tmp); | ||
| 341 | $entityManager->flush(); | ||
| 342 | |||
| 343 | echo json_encode(['success' => true]); | ||
| 344 | die; | ||
| 345 | } | ||
| 346 | elseif($_GET['action'] === 'date_submit' && isset($json['id']) && isset($json['date'])) | ||
| 347 | { | ||
| 348 | $id = $json['id']; | ||
| 349 | $id[0] = 'i'; | ||
| 350 | $date = new DateTime($json['date']); | ||
| 351 | |||
| 352 | $director = new Director($entityManager); | ||
| 353 | $director->makeArticleNode($id); | ||
| 354 | $node = $director->getArticleNode(); | ||
| 355 | $node->getArticle()->setDateTime($date); | ||
| 356 | $entityManager->flush(); | ||
| 357 | |||
| 358 | echo json_encode(['success' => true]); | ||
| 359 | die; | ||
| 360 | } | ||
| 361 | |||
| 362 | |||
| 363 | /* -- bloc Formulaire -- */ | ||
| 364 | elseif($_GET['action'] === 'recipient_email'){ | ||
| 365 | $email = htmlspecialchars(trim($json['email'])); | ||
| 366 | |||
| 367 | if((filter_var($email, FILTER_VALIDATE_EMAIL) // nouvel e-mail | ||
| 368 | || ($json['email'] === '' && !empty(Config::$email_dest))) // e-mail par défaut | ||
| 369 | && isset($json['hidden']) && empty($json['hidden'])) | ||
| 370 | { | ||
| 371 | $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); | ||
| 372 | $form_data->updateData('email', $email); | ||
| 373 | $entityManager->persist($form_data); | ||
| 374 | $entityManager->flush(); | ||
| 375 | |||
| 376 | echo json_encode(['success' => true]); | ||
| 377 | } | ||
| 378 | else{ | ||
| 379 | echo json_encode(['success' => false]); | ||
| 380 | } | ||
| 381 | die; | ||
| 382 | } | ||
| 383 | elseif($_GET['action'] === 'test_email'){ | ||
| 384 | // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur | ||
| 385 | $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); | ||
| 386 | $recipient = $form_data->getData()['email'] ?? Config::$email_dest; | ||
| 387 | |||
| 388 | if(sendEmail($recipient, false, 'nom du visiteur', 'adresse@du_visiteur.fr', "TEST d'un envoi d'e-mail depuis le site web")){ | ||
| 389 | echo json_encode(['success' => true]); | ||
| 390 | } | ||
| 391 | else{ | ||
| 392 | echo json_encode(['success' => false]); | ||
| 393 | } | ||
| 394 | die; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | |||
| 399 | /* -- page Menu et chemins -- */ | ||
| 400 | elseif(isset($_GET['menu_edit'])) | ||
| 401 | { | ||
| 402 | // récupération des données | ||
| 403 | $data = file_get_contents('php://input'); | ||
| 404 | $json = json_decode($data, true); | ||
| 405 | Director::$menu_data = new Menu($entityManager); | ||
| 406 | |||
| 407 | // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions | ||
| 408 | if($_GET['menu_edit'] === 'move_one_level_up' && isset($json['id'])){ | ||
| 409 | $id = $json['id']; | ||
| 410 | $page = Director::$menu_data->findPageById((int)$id); | ||
| 411 | |||
| 412 | $parent = $page->getParent(); // peut être null | ||
| 413 | if($parent === null){ | ||
| 414 | // 1er niveau: ne rien faire | ||
| 415 | echo json_encode(['success' => false]); | ||
| 416 | die; | ||
| 417 | } | ||
| 418 | // BDD | ||
| 419 | else{ | ||
| 420 | $page->setPosition($parent->getPosition() + 1); // nouvelle position | ||
| 421 | |||
| 422 | // 2ème niveau: le parent devient $menu_data, puis null après tri | ||
| 423 | if($parent->getParent() === null){ | ||
| 424 | // connexion dans les deux sens | ||
| 425 | $page->setParent(Director::$menu_data); // => pour la persistance | ||
| 426 | |||
| 427 | //Director::$menu_data->addChild($page); // => pour sortChildren | ||
| 428 | $page->getParent()->addChild($page); // => pour sortChildren | ||
| 429 | //Director::$menu_data->sortChildren(true); // positions décaléees des nouveaux petits frères | ||
| 430 | $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères | ||
| 431 | $page->setParent(null); | ||
| 432 | |||
| 433 | // affichage | ||
| 434 | $page->setPagePath($page->getEndOfPath()); | ||
| 435 | $page->fillChildrenPagePath(); | ||
| 436 | } | ||
| 437 | // 3ème niveau et plus | ||
| 438 | else{ | ||
| 439 | $page->setParent($parent->getParent()); // nouveau parent | ||
| 440 | $page->getParent()->addChild($page); // => pour sortChildren | ||
| 441 | $page->getParent()->sortChildren(true); // positions décaléees des nouveaux petits frères | ||
| 442 | $page->fillChildrenPagePath($page->getParent()->getPagePath()); | ||
| 443 | } | ||
| 444 | //$parent->sortChildren(true); // positions des enfants restants, inutile si la fonction est récursive? | ||
| 445 | $entityManager->flush(); | ||
| 446 | |||
| 447 | // affichage | ||
| 448 | $parent->removeChild($page); | ||
| 449 | $nav_builder = new NavBuilder(); | ||
| 450 | $menu_builder = new MenuBuilder(null, false); | ||
| 451 | echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]); | ||
| 452 | die; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | // flèche droite =>: position = nombre d'éléments de la fraterie + 1, l'élément précédent devient le parent | ||
| 457 | if($_GET['menu_edit'] === 'move_one_level_down' && isset($json['id'])){ | ||
| 458 | $id = $json['id']; | ||
| 459 | $page = Director::$menu_data->findPageById((int)$id); | ||
| 460 | |||
| 461 | $parent = $page->getParent(); // peut être null | ||
| 462 | if($parent == null){ | ||
| 463 | $parent = Director::$menu_data; | ||
| 464 | } | ||
| 465 | |||
| 466 | // BDD | ||
| 467 | $parent->sortChildren(true); // trie et réindexe par sécurité: 1, 2, 3... | ||
| 468 | if($page->getPosition() > 1){ | ||
| 469 | foreach($parent->getChildren() as $child){ | ||
| 470 | if($child->getPosition() === $page->getPosition() - 1){ | ||
| 471 | $page->setParent($child); | ||
| 472 | break; | ||
| 473 | } | ||
| 474 | } | ||
| 475 | $page->setPosition(count($page->getParent()->getChildren()) + 1); | ||
| 476 | } | ||
| 477 | $entityManager->flush(); | ||
| 478 | |||
| 479 | // affichage | ||
| 480 | $parent->removeChild($page); | ||
| 481 | $page->getParent()->addChild($page); | ||
| 482 | $page->fillChildrenPagePath($page->getParent()->getPagePath()); // variable non mappée $page_path | ||
| 483 | $nav_builder = new NavBuilder(); | ||
| 484 | $menu_builder = new MenuBuilder(null, false); | ||
| 485 | |||
| 486 | echo json_encode(['success' => true, 'nav' => $nav_builder->render(), 'menu_buttons' => $menu_builder->render()]); | ||
| 487 | die; | ||
| 488 | } | ||
| 489 | |||
| 490 | if($_GET['menu_edit'] === 'switch_positions' && isset($json['id1']) && isset($json['id2'])) | ||
| 491 | { | ||
| 492 | $id1 = $json['id1']; | ||
| 493 | $id2 = $json['id2']; | ||
| 494 | |||
| 495 | // vérifier qu'ils ont le même parent | ||
| 496 | $page1 = Director::$menu_data->findPageById((int)$id1); | ||
| 497 | $page2 = Director::$menu_data->findPageById((int)$id2); | ||
| 498 | |||
| 499 | // double le contrôle fait en JS | ||
| 500 | if($page1->getParent() === $page2->getParent()) // comparaison stricte d'objet (même instance du parent?) | ||
| 501 | { | ||
| 502 | // inversion | ||
| 503 | $tmp = $page1->getPosition(); | ||
| 504 | $page1->setPosition($page2->getPosition()); | ||
| 505 | $page2->setPosition($tmp); | ||
| 506 | Director::$menu_data->sortChildren(true); // modifie tableau children | ||
| 507 | $entityManager->flush(); | ||
| 508 | |||
| 509 | // nouveau menu | ||
| 510 | $nav_builder = new NavBuilder(); | ||
| 511 | echo json_encode(['success' => true, 'nav' => $nav_builder->render()]); | ||
| 512 | } | ||
| 513 | else{ | ||
| 514 | echo json_encode(['success' => false]); | ||
| 515 | } | ||
| 516 | |||
| 517 | die; | ||
| 518 | } | ||
| 519 | |||
| 520 | if($_GET['menu_edit'] === 'displayInMenu' && isset($json['id']) && isset($json['checked'])) | ||
| 521 | { | ||
| 522 | $id = $json['id']; | ||
| 523 | $checked = $json['checked']; | ||
| 524 | |||
| 525 | $page = Director::$menu_data->findPageById((int)$id); | ||
| 526 | if($page->isHidden() === $checked){ | ||
| 527 | $page->setHidden(!$checked); | ||
| 528 | $entityManager->flush(); | ||
| 529 | |||
| 530 | // nouveau menu | ||
| 531 | $nav_builder = new NavBuilder(); | ||
| 532 | echo json_encode(['success' => true, 'nav' => $nav_builder->render()]); | ||
| 533 | } | ||
| 534 | else{ | ||
| 535 | echo json_encode(['success' => false]); | ||
| 536 | } | ||
| 537 | die; | ||
| 538 | } | ||
| 539 | } | ||
| 540 | |||
| 541 | |||
| 542 | /* -- mode Modification d'une page -- */ | ||
| 543 | |||
| 544 | // partie "page" | ||
| 545 | elseif(isset($_GET['page_edit'])) | ||
| 546 | { | ||
| 547 | // récupération des données | ||
| 548 | $data = file_get_contents('php://input'); | ||
| 549 | $json = json_decode($data, true); | ||
| 550 | |||
| 551 | // titre de la page | ||
| 552 | if($_GET['page_edit'] === 'page_title'){ | ||
| 553 | $page = $entityManager->find('App\Entity\Page', $json['page_id']); | ||
| 554 | $page->setPageName(htmlspecialchars($json['title'])); | ||
| 555 | $entityManager->flush(); | ||
| 556 | echo json_encode(['success' => true, 'title' => $page->getPageName()]); | ||
| 557 | } | ||
| 558 | // titre en snake_case pour le menu | ||
| 559 | /*elseif($_GET['page_edit'] === 'page_menu_path'){ | ||
| 560 | $page = $entityManager->find('App\Entity\Page', $json['page_id']); | ||
| 561 | $page->setEndOfPath(htmlspecialchars($json['page_menu_path'])); | ||
| 562 | $entityManager->flush(); | ||
| 563 | echo json_encode(['success' => true, 'page_name_path' => $page->getEndOfPath()]); | ||
| 564 | }*/ | ||
| 565 | // description dans les métadonnées | ||
| 566 | elseif($_GET['page_edit'] === 'page_description'){ | ||
| 567 | $node_data = $entityManager->find('App\Entity\NodeData', $json['node_data_id']); | ||
| 568 | $node_data->updateData('description', htmlspecialchars($json['description'])); | ||
| 569 | $entityManager->flush(); | ||
| 570 | echo json_encode(['success' => true, 'description' => $node_data->getData()['description']]); | ||
| 571 | } | ||
| 572 | die; | ||
| 573 | } | ||
| 574 | |||
| 575 | // partie "blocs" | ||
| 576 | elseif(isset($_GET['bloc_edit'])) | ||
| 577 | { | ||
| 578 | // renommage d'un bloc | ||
| 579 | if($_GET['bloc_edit'] === 'rename_page_bloc') | ||
| 580 | { | ||
| 581 | if(isset($json['bloc_title']) && $json['bloc_title'] !== null && isset($json['bloc_id']) && is_int($json['bloc_id'])){ | ||
| 582 | $director = new Director($entityManager); | ||
| 583 | $director->findNodeById($json['bloc_id']); | ||
| 584 | |||
| 585 | // le titre (du JSON en BDD) est récupéré sous forme de tableau, modifié et renvoyé | ||
| 586 | $data = $director->getNode()->getNodeData()->getData(); | ||
| 587 | $data['title'] = htmlspecialchars($json['bloc_title']); | ||
| 588 | $director->getNode()->getNodeData()->updateData('title', htmlspecialchars($json['bloc_title'])); | ||
| 589 | |||
| 590 | $entityManager->flush(); | ||
| 591 | echo json_encode(['success' => true, 'title' => $data['title']]); | ||
| 592 | } | ||
| 593 | else{ | ||
| 594 | echo json_encode(['success' => false]); | ||
| 595 | } | ||
| 596 | die; | ||
| 597 | } | ||
| 598 | // inversion des positions de deux blocs | ||
| 599 | elseif($_GET['bloc_edit'] === 'switch_blocs_positions') | ||
| 600 | { | ||
| 601 | if(isset($json['id1']) && is_int($json['id1']) && isset($json['id2']) && is_int($json['id2']) && isset($_GET['page'])){ | ||
| 602 | $director = new Director($entityManager, true); | ||
| 603 | $director->findUniqueNodeByName('main'); | ||
| 604 | $director->findItsChildren(); | ||
| 605 | $main = $director->getNode(); | ||
| 606 | $main->sortChildren(true); // régénère les positions avant inversion | ||
| 607 | |||
| 608 | $bloc1; $bloc2; | ||
| 609 | foreach($main->getChildren() as $child){ | ||
| 610 | if($child->getId() === $json['id1']){ | ||
| 611 | $bloc1 = $child; | ||
| 612 | break; | ||
| 613 | } | ||
| 614 | } | ||
| 615 | foreach($main->getChildren() as $child){ | ||
| 616 | if($child->getId() === $json['id2']){ | ||
| 617 | $bloc2 = $child; | ||
| 618 | break; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | |||
| 622 | // inversion | ||
| 623 | $tmp = $bloc1->getPosition(); | ||
| 624 | $bloc1->setPosition($bloc2->getPosition()); | ||
| 625 | $bloc2->setPosition($tmp); | ||
| 626 | |||
| 627 | $entityManager->flush(); | ||
| 628 | echo json_encode(['success' => true]); | ||
| 629 | } | ||
| 630 | else{ | ||
| 631 | echo json_encode(['success' => false]); | ||
| 632 | } | ||
| 633 | die; | ||
| 634 | } | ||
| 635 | } | ||
| 636 | } \ No newline at end of file | ||
diff --git a/src/controller/ajax_calendar_admin.php b/src/controller/ajax_calendar_admin.php deleted file mode 100644 index 0baf73e..0000000 --- a/src/controller/ajax_calendar_admin.php +++ /dev/null | |||
| @@ -1,54 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ajax_calendar_admin.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use App\Entity\Event; | ||
| 7 | |||
| 8 | // actions sur le calendrier | ||
| 9 | if(isset($_SESSION['admin']) && $_SESSION['admin'] === true | ||
| 10 | && $_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['CONTENT_TYPE'] === 'application/json') | ||
| 11 | { | ||
| 12 | $data = file_get_contents('php://input'); | ||
| 13 | $json = json_decode($data, true); | ||
| 14 | |||
| 15 | if($_GET['action'] === 'new_event'){ | ||
| 16 | try{ | ||
| 17 | $event = new Event($json); | ||
| 18 | } | ||
| 19 | catch(InvalidArgumentException $e){ | ||
| 20 | echo json_encode(['success' => false, 'error' => $e->getMessage()]); | ||
| 21 | http_response_code(400); | ||
| 22 | die; | ||
| 23 | } | ||
| 24 | $entityManager->persist($event); | ||
| 25 | $entityManager->flush(); | ||
| 26 | |||
| 27 | echo json_encode(['success' => true, 'id' => $event->getId()]); | ||
| 28 | } | ||
| 29 | elseif($_GET['action'] === 'update_event'){ | ||
| 30 | $event = $entityManager->find('App\Entity\Event', (int)$json['id']); | ||
| 31 | try{ | ||
| 32 | $event->securedUpdateFromJSON($json); | ||
| 33 | } | ||
| 34 | catch(InvalidArgumentException $e){ | ||
| 35 | echo json_encode(['success' => false, 'error' => $e->getMessage()]); | ||
| 36 | http_response_code(400); | ||
| 37 | die; | ||
| 38 | } | ||
| 39 | $entityManager->flush(); | ||
| 40 | |||
| 41 | echo json_encode(['success' => true]); | ||
| 42 | } | ||
| 43 | elseif($_GET['action'] === 'remove_event'){ | ||
| 44 | $event = $entityManager->find('App\Entity\Event', (int)$json['id']); | ||
| 45 | $entityManager->remove($event); | ||
| 46 | $entityManager->flush(); | ||
| 47 | |||
| 48 | echo json_encode(['success' => true]); | ||
| 49 | } | ||
| 50 | else{ | ||
| 51 | echo json_encode(['success' => false]); | ||
| 52 | } | ||
| 53 | die; | ||
| 54 | } \ No newline at end of file | ||
diff --git a/src/controller/ajax_calendar_visitor.php b/src/controller/ajax_calendar_visitor.php deleted file mode 100644 index dcdbebd..0000000 --- a/src/controller/ajax_calendar_visitor.php +++ /dev/null | |||
| @@ -1,39 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ajax_calendar_visitor.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use App\Entity\Event; | ||
| 7 | |||
| 8 | // chargement des évènements à la création du calendrier | ||
| 9 | // et au changement de dates affichées (boutons flèches mais pas changement de vue) | ||
| 10 | if($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'get_events' | ||
| 11 | && isset($_GET['start']) && isset($_GET['end']) && empty($_POST)) | ||
| 12 | { | ||
| 13 | // bornes début et fin du calendrier affiché à l'heure locale | ||
| 14 | // noter que la vue "planning" est similaire à la vue "semaine" | ||
| 15 | $start = new DateTime($_GET['start']); | ||
| 16 | $end = new DateTime($_GET['end']); | ||
| 17 | $start->setTimezone(new DateTimeZone('UTC')); | ||
| 18 | $end->setTimezone(new DateTimeZone('UTC')); | ||
| 19 | |||
| 20 | // affichage format ISO à l'heure UTC | ||
| 21 | //$date->format('Y-m-d\TH:i:s\Z'); | ||
| 22 | |||
| 23 | // on prend les évènements se finissant après le début ou commençant avant la fin de la fourchette | ||
| 24 | $dql = 'SELECT e FROM App\Entity\Event e WHERE e.end >= :start AND e.start <= :end'; | ||
| 25 | $bulk_data = $entityManager->createQuery($dql) | ||
| 26 | ->setParameter('start', $start) | ||
| 27 | ->setParameter('end', $end) | ||
| 28 | ->getResult(); | ||
| 29 | |||
| 30 | $events = []; | ||
| 31 | foreach($bulk_data as $one_entry){ | ||
| 32 | $event = new EventDTO($one_entry); | ||
| 33 | $events[] = $event->toArray(); | ||
| 34 | } | ||
| 35 | |||
| 36 | header('Content-Type: application/json'); | ||
| 37 | echo json_encode($events); | ||
| 38 | die; | ||
| 39 | } \ No newline at end of file | ||
diff --git a/src/controller/ajax_email.php b/src/controller/ajax_email.php deleted file mode 100644 index 1138e04..0000000 --- a/src/controller/ajax_email.php +++ /dev/null | |||
| @@ -1,105 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/ajax.php | ||
| 3 | |||
| 4 | declare(strict_types=1); | ||
| 5 | |||
| 6 | use PHPMailer\PHPMailer\PHPMailer; | ||
| 7 | use PHPMailer\PHPMailer\Exception; | ||
| 8 | use App\Entity\Email; | ||
| 9 | use Doctrine\ORM\EntityManager; | ||
| 10 | |||
| 11 | // mettre ça ailleurs? | ||
| 12 | function sendEmail(string $recipient, bool $true_email, string $name = '', string $email = '', string $message = ''): bool | ||
| 13 | { | ||
| 14 | $mail = new PHPMailer(true); // true => exceptions | ||
| 15 | $mail->CharSet = 'UTF-8'; | ||
| 16 | |||
| 17 | try{ | ||
| 18 | // Paramètres du serveur | ||
| 19 | $mail->isSMTP(); | ||
| 20 | $mail->Host = Config::$smtp_host; | ||
| 21 | $mail->SMTPAuth = true; | ||
| 22 | $mail->Port = 25; | ||
| 23 | |||
| 24 | if($mail->SMTPAuth){ | ||
| 25 | $mail->Username = Config::$smtp_username; // e-mail | ||
| 26 | $mail->Password = Config::$smtp_password; | ||
| 27 | $mail->SMTPSecure = Config::$smtp_secure; // tls (starttls) ou ssl (smtps) | ||
| 28 | if($mail->SMTPSecure === 'tls'){ | ||
| 29 | $mail->Port = 587; | ||
| 30 | } | ||
| 31 | elseif($mail->SMTPSecure === 'ssl'){ | ||
| 32 | $mail->Port = 465; | ||
| 33 | } | ||
| 34 | } | ||
| 35 | //var_dump($mail->smtpConnect());die; // test de connexion | ||
| 36 | |||
| 37 | // Expéditeur et destinataire | ||
| 38 | $mail->setFrom(strtolower(Config::$email_from), Config::$email_from_name); // expéditeur | ||
| 39 | $mail->addAddress(strtolower($recipient), Config::$email_dest_name); // destinataire | ||
| 40 | |||
| 41 | // Contenu | ||
| 42 | $mail->isHTML(true); | ||
| 43 | if($true_email){ | ||
| 44 | $mail->Subject = 'Message envoyé par: ' . $name . ' (' . $email . ') depuis le site web'; | ||
| 45 | |||
| 46 | } | ||
| 47 | else{ | ||
| 48 | $mail->Subject = "TEST d'un envoi d'e-mail depuis le site web"; | ||
| 49 | } | ||
| 50 | $mail->Body = $message; | ||
| 51 | $mail->AltBody = $message; | ||
| 52 | |||
| 53 | $mail->send(); | ||
| 54 | return true; | ||
| 55 | } | ||
| 56 | catch(Exception $e){ | ||
| 57 | return false; | ||
| 58 | //echo "Le message n'a pas pu être envoyé. Erreur : {$mail->ErrorInfo}"; | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | function submitEmail(array $json, EntityManager $entityManager): void | ||
| 63 | { | ||
| 64 | $captcha_solution = (isset($_SESSION['captcha']) && is_int($_SESSION['captcha'])) ? $_SESSION['captcha'] : 0; | ||
| 65 | $captcha_try = isset($json['captcha']) ? Captcha::controlInput($json['captcha']) : 0; | ||
| 66 | |||
| 67 | // contrôles des entrées | ||
| 68 | $name = htmlspecialchars(trim($json['name'])); | ||
| 69 | $email = strtolower(htmlspecialchars(trim($json['email']))); | ||
| 70 | $message = htmlspecialchars(trim($json['message'])); | ||
| 71 | |||
| 72 | // destinataire = e-mail par défaut dans config.ini OU choisi par l'utilisateur | ||
| 73 | $form_data = $entityManager->find('App\Entity\NodeData', $json['id']); | ||
| 74 | $recipient = $form_data->getData()['email'] ?? Config::$email_dest; | ||
| 75 | |||
| 76 | if($captcha_try != 0 && $captcha_solution != 0 && ($captcha_try === $captcha_solution) | ||
| 77 | && filter_var($email, FILTER_VALIDATE_EMAIL) && isset($json['hidden']) && empty($json['hidden']) | ||
| 78 | && sendEmail($recipient, true, $name, $email, $message)) | ||
| 79 | { | ||
| 80 | $db_email = new Email($email, Config::$email_dest, $message); | ||
| 81 | $entityManager->persist($db_email); | ||
| 82 | $entityManager->flush(); | ||
| 83 | echo json_encode(['success' => true]); | ||
| 84 | } | ||
| 85 | else{ | ||
| 86 | echo json_encode(['success' => false]); | ||
| 87 | } | ||
| 88 | die; | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | // détection des requêtes envoyées avec fetch (application/json) et récupération du JSON | ||
| 93 | if($_SERVER['CONTENT_TYPE'] === 'application/json') | ||
| 94 | { | ||
| 95 | $data = file_get_contents('php://input'); | ||
| 96 | $json = json_decode($data, true); | ||
| 97 | |||
| 98 | if(isset($_GET['action'])) | ||
| 99 | { | ||
| 100 | // formulaire de contact | ||
| 101 | if($_GET['action'] === 'send_email'){ | ||
| 102 | submitEmail($json, $entityManager); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | } \ No newline at end of file | ||
diff --git a/src/controller/password.php b/src/controller/password.php index e91cc16..3d003da 100644 --- a/src/controller/password.php +++ b/src/controller/password.php | |||
| @@ -226,7 +226,8 @@ function changePassword(EntityManager $entityManager): void | |||
| 226 | } | 226 | } |
| 227 | elseif(!isset($_POST['login']) || empty($_POST['login']) | 227 | elseif(!isset($_POST['login']) || empty($_POST['login']) |
| 228 | || !isset($_POST['old_password']) || empty($_POST['old_password']) | 228 | || !isset($_POST['old_password']) || empty($_POST['old_password']) |
| 229 | || !isset($_POST['new_password']) || empty($_POST['new_password'])) | 229 | || !isset($_POST['new_password']) || empty($_POST['new_password']) |
| 230 | || !isset($_POST['modify_password_hidden']) || !empty($_POST['modify_password_hidden'])) | ||
| 230 | { | 231 | { |
| 231 | $error = 'bad_login_or_password'; | 232 | $error = 'bad_login_or_password'; |
| 232 | } | 233 | } |
diff --git a/src/controller/post_functions_admin.php b/src/controller/post_functions_admin.php deleted file mode 100644 index b47850a..0000000 --- a/src/controller/post_functions_admin.php +++ /dev/null | |||
| @@ -1,231 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/post_functions_admin.php | ||
| 3 | // | ||
| 4 | // sera remplacé pas une ou plusieurs classes pour le routeur de symfony | ||
| 5 | |||
| 6 | declare(strict_types=1); | ||
| 7 | |||
| 8 | use App\Entity\Node; | ||
| 9 | use App\Entity\NodeData; | ||
| 10 | use App\Entity\Page; | ||
| 11 | //use App\Entity\Image; | ||
| 12 | use Doctrine\Common\Collections\ArrayCollection; | ||
| 13 | use Doctrine\ORM\EntityManager; | ||
| 14 | |||
| 15 | |||
| 16 | function newPage(EntityManager $entityManager): void | ||
| 17 | { | ||
| 18 | // titre et chemin | ||
| 19 | $director = new Director($entityManager, true); | ||
| 20 | //Director::$menu_data = new Menu($entityManager); | ||
| 21 | $previous_page = Director::$menu_data->findPageById((int)$_POST["page_location"]); // (int) à cause de declare(strict_types=1); | ||
| 22 | $parent = $previous_page->getParent(); | ||
| 23 | |||
| 24 | $page = new Page( | ||
| 25 | trim(htmlspecialchars($_POST["page_name"])), | ||
| 26 | trim(htmlspecialchars($_POST["page_name_path"])), | ||
| 27 | true, true, false, | ||
| 28 | $previous_page->getPosition(), | ||
| 29 | $parent); // peut et DOIT être null si on est au 1er niveau | ||
| 30 | |||
| 31 | // on a donné à la nouvelle entrée la même position qu'à la précédente, | ||
| 32 | // addChild l'ajoute à la fin du tableau "children" puis on trie | ||
| 33 | // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position | ||
| 34 | if($parent == null){ | ||
| 35 | $parent = Director::$menu_data; | ||
| 36 | } | ||
| 37 | $parent->addChild($page); | ||
| 38 | $parent->reindexPositions(); | ||
| 39 | |||
| 40 | $page->setPagePath(ltrim($parent->getPagePath() . '/' . $page->getEndOfPath(), '/')); | ||
| 41 | |||
| 42 | // noeud "head" | ||
| 43 | $node = new Node( | ||
| 44 | 'head', | ||
| 45 | null, [], | ||
| 46 | 1, // position d'un head = 1 | ||
| 47 | null, // pas de parent | ||
| 48 | $page); | ||
| 49 | $node->useDefaultAttributes(); // fichiers CSS et JS | ||
| 50 | |||
| 51 | $data = new NodeData([ | ||
| 52 | // pas de titre, il est dans $page | ||
| 53 | 'description' => trim(htmlspecialchars($_POST["page_description"]))], | ||
| 54 | $node); | ||
| 55 | |||
| 56 | $bulk_data = $entityManager | ||
| 57 | ->createQuery('SELECT n FROM App\Entity\Image n WHERE n.file_name LIKE :name') | ||
| 58 | ->setParameter('name', '%favicon%') | ||
| 59 | ->getResult(); | ||
| 60 | $data->setImages(new ArrayCollection($bulk_data)); | ||
| 61 | |||
| 62 | $entityManager->persist($page); | ||
| 63 | $entityManager->persist($node); | ||
| 64 | $entityManager->persist($data); | ||
| 65 | $entityManager->flush(); | ||
| 66 | |||
| 67 | // page créée, direction la page en mode modification pour ajouter des blocs | ||
| 68 | header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page'])); | ||
| 69 | die; | ||
| 70 | } | ||
| 71 | |||
| 72 | function deletePage(EntityManager $entityManager): void | ||
| 73 | { | ||
| 74 | $page = $entityManager->find('App\Entity\Page', (int)$_POST['page_id']); | ||
| 75 | $nodes = $entityManager->getRepository('App\Entity\Node')->findBy(['page' => $page]); | ||
| 76 | $data = []; | ||
| 77 | foreach($nodes as $node){ | ||
| 78 | $data[] = $entityManager->getRepository('App\Entity\NodeData')->findOneBy(['node' => $node]); | ||
| 79 | $entityManager->remove($node); | ||
| 80 | } | ||
| 81 | foreach($data as $one_data){ | ||
| 82 | $entityManager->remove($one_data); | ||
| 83 | } | ||
| 84 | $entityManager->remove($page); // suppression en BDD | ||
| 85 | |||
| 86 | $entityManager->flush(); | ||
| 87 | header("Location: " . new URL); | ||
| 88 | die; | ||
| 89 | } | ||
| 90 | |||
| 91 | function pageMenuPathUpdate(EntityManager $entityManager): void | ||
| 92 | { | ||
| 93 | $director = new Director($entityManager, true); | ||
| 94 | $page = Director::$page_path->getLast(); | ||
| 95 | $path = htmlspecialchars($_POST['page_menu_path']); | ||
| 96 | |||
| 97 | // mise en snake_case: filtre caractères non-alphanumériques, minuscule, doublons d'underscore, trim des underscores | ||
| 98 | $path = trim(preg_replace('/_+/', '_', strtolower(preg_replace('/[^a-zA-Z0-9]/', '_', $path))), '_'); | ||
| 99 | $page->setEndOfPath($path); | ||
| 100 | foreach(Director::$menu_data->getChildren() as $child){ | ||
| 101 | if($child->getEndOfPath() === Director::$page_path->getArray()[0]->getEndOfPath()){ | ||
| 102 | $child->fillChildrenPagePath(); // MAJ de $page_path | ||
| 103 | } | ||
| 104 | } | ||
| 105 | $entityManager->flush(); | ||
| 106 | header("Location: " . new URL(['page' => $page->getPagePath(), 'action' => 'modif_page'])); | ||
| 107 | die; | ||
| 108 | } | ||
| 109 | |||
| 110 | function addBloc(EntityManager $entityManager): void | ||
| 111 | { | ||
| 112 | $director = new Director($entityManager, true); // on a besoin de page_path qui dépend de menu_data | ||
| 113 | $page = Director::$page_path->getLast(); | ||
| 114 | $director->findUniqueNodeByName('main'); | ||
| 115 | $director->findItsChildren(); | ||
| 116 | $main = $director->getNode(); | ||
| 117 | $position = count($main->getChildren()) + 1; // position dans la fraterie | ||
| 118 | |||
| 119 | $blocks = ['blog', 'grid', 'calendar', 'galery', 'form']; // même liste dans FormBuilder.php | ||
| 120 | if(!in_array($_POST["bloc_select"], $blocks, true)) // 3è param: contrôle du type | ||
| 121 | { | ||
| 122 | header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'bad_bloc_type'])); | ||
| 123 | die; | ||
| 124 | } | ||
| 125 | |||
| 126 | if($_POST["bloc_select"] === 'calendar' || $_POST["bloc_select"] === 'form'){ | ||
| 127 | $dql = 'SELECT n FROM App\Entity\Node n WHERE n.page = :page AND n.name_node = :name'; // noeud 'head' de la page | ||
| 128 | $bulk_data = $entityManager | ||
| 129 | ->createQuery($dql) | ||
| 130 | ->setParameter('page', $page) | ||
| 131 | ->setParameter('name', 'head') | ||
| 132 | ->getResult(); | ||
| 133 | |||
| 134 | if(count($bulk_data) != 1){ // 1 head par page | ||
| 135 | header("Location: " . new URL(['page' => $_GET['page'], 'error' => 'head_node_not_found'])); | ||
| 136 | die; | ||
| 137 | } | ||
| 138 | |||
| 139 | $bulk_data[0]->addAttribute('css_array', $_POST["bloc_select"]); | ||
| 140 | if($_POST["bloc_select"] === 'form'){ | ||
| 141 | $bulk_data[0]->addAttribute('js_array', $_POST["bloc_select"]); | ||
| 142 | } | ||
| 143 | $entityManager->persist($bulk_data[0]); | ||
| 144 | } | ||
| 145 | |||
| 146 | $bloc = new Node( | ||
| 147 | $_POST["bloc_select"], | ||
| 148 | null, [], | ||
| 149 | $position, | ||
| 150 | $main, | ||
| 151 | $page); | ||
| 152 | $data = new NodeData( | ||
| 153 | ['title' => trim(htmlspecialchars($_POST["bloc_title"]))], | ||
| 154 | $bloc); | ||
| 155 | |||
| 156 | $entityManager->persist($bloc); | ||
| 157 | $entityManager->persist($data); | ||
| 158 | $entityManager->flush(); | ||
| 159 | header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page'])); | ||
| 160 | die; | ||
| 161 | } | ||
| 162 | |||
| 163 | function deleteBloc(EntityManager $entityManager): void | ||
| 164 | { | ||
| 165 | $director = new Director($entityManager, true); | ||
| 166 | $director->findUniqueNodeByName('main'); | ||
| 167 | $director->findItsChildren(); | ||
| 168 | //$director->findNodeById((int)$_POST['delete_bloc_id']); | ||
| 169 | $main = $director->getNode(); | ||
| 170 | $bloc = null; | ||
| 171 | foreach($main->getChildren() as $child){ | ||
| 172 | if($child->getId() === (int)$_POST['delete_bloc_id']){ | ||
| 173 | $bloc = $child; | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | if(!empty($bloc)){ // si $bloc est null c'est que le HTML a été modifié volontairement | ||
| 178 | $main->removeChild($bloc); // réindex le tableau $children au passage | ||
| 179 | $main->reindexPositions(); | ||
| 180 | $entityManager->remove($bloc); // suppression en BDD | ||
| 181 | $entityManager->flush(); | ||
| 182 | } | ||
| 183 | header("Location: " . new URL(['page' => $_GET['page'], 'action' => 'modif_page'])); | ||
| 184 | die; | ||
| 185 | } | ||
| 186 | |||
| 187 | function newUrlMenuEntry(EntityManager $entityManager): void | ||
| 188 | { | ||
| 189 | Director::$menu_data = new Menu($entityManager); | ||
| 190 | $previous_page = Director::$menu_data->findPageById((int)$_POST["location"]); // (int) à cause de declare(strict_types=1); | ||
| 191 | $parent = $previous_page->getParent(); | ||
| 192 | |||
| 193 | $page = new Page( | ||
| 194 | trim(htmlspecialchars($_POST["label_input"])), | ||
| 195 | filter_var($_POST["url_input"], FILTER_VALIDATE_URL), | ||
| 196 | true, true, false, | ||
| 197 | $previous_page->getPosition(), | ||
| 198 | $parent); // peut et DOIT être null si on est au 1er niveau | ||
| 199 | |||
| 200 | // on a donné à la nouvelle entrée la même position qu'à la précédente, | ||
| 201 | // addChild l'ajoute à la fin du tableau "children" puis on trie | ||
| 202 | // exemple avec 2 comme position demandée: 1 2 3 4 2 devient 1 2 3 4 5 et la nouvelle entrée sera en 3è position | ||
| 203 | if($parent == null){ | ||
| 204 | $parent = Director::$menu_data; | ||
| 205 | } | ||
| 206 | $parent->addChild($page); // true pour réindexer les positions en BDD | ||
| 207 | $parent->reindexPositions(); | ||
| 208 | |||
| 209 | $entityManager->persist($page); | ||
| 210 | $entityManager->flush(); | ||
| 211 | header("Location: " . new URL(['page' => $_GET['from']])); | ||
| 212 | die; | ||
| 213 | } | ||
| 214 | |||
| 215 | function deleteUrlMenuEntry(EntityManager $entityManager): void | ||
| 216 | { | ||
| 217 | Director::$menu_data = new Menu($entityManager); | ||
| 218 | $page = Director::$menu_data->findPageById((int)$_POST["delete"]); | ||
| 219 | $parent = $page->getParent(); | ||
| 220 | if($parent == null){ | ||
| 221 | $parent = Director::$menu_data; | ||
| 222 | } | ||
| 223 | |||
| 224 | $parent->removeChild($page); // suppression de $children avant de trier | ||
| 225 | $parent->reindexPositions(); | ||
| 226 | |||
| 227 | $entityManager->remove($page); // suppression en BDD | ||
| 228 | $entityManager->flush(); | ||
| 229 | header("Location: " . new URL(['page' => $_GET['from']])); | ||
| 230 | die; | ||
| 231 | } \ No newline at end of file | ||
diff --git a/src/controller/post_router.php b/src/controller/post_router.php deleted file mode 100644 index e71852a..0000000 --- a/src/controller/post_router.php +++ /dev/null | |||
| @@ -1,120 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/post_router.php | ||
| 3 | // | ||
| 4 | // routage des requêtes des formulaires et AJAX | ||
| 5 | // n'utilisent que des POST à l'exception d'un GET par fullcalendar | ||
| 6 | // les contrôleurs des formulaires sont appelés ici, | ||
| 7 | // ceux des requêtes AJAX sont derrière d'autres routeurs | ||
| 8 | |||
| 9 | declare(strict_types=1); | ||
| 10 | |||
| 11 | |||
| 12 | /* appel des contrôleurs dans password.php */ | ||
| 13 | if(isset($_GET['action']) && $_GET['action'] === 'deconnexion') | ||
| 14 | { | ||
| 15 | disconnect($entityManager); | ||
| 16 | } | ||
| 17 | elseif(isset($_GET['action']) && $_GET['action'] === 'modif_mdp') | ||
| 18 | { | ||
| 19 | changePassword($entityManager); | ||
| 20 | } | ||
| 21 | |||
| 22 | |||
| 23 | if($_SERVER['REQUEST_METHOD'] === 'POST'){ | ||
| 24 | /* -- contrôleurs appellables par tout le monde -- */ | ||
| 25 | // POST "ajax" | ||
| 26 | require '../src/controller/ajax_email.php'; | ||
| 27 | |||
| 28 | // POST "form" | ||
| 29 | // ... | ||
| 30 | |||
| 31 | |||
| 32 | if($_SESSION['admin'] === true) | ||
| 33 | { | ||
| 34 | /* -- requêtes "form" -- */ | ||
| 35 | if($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded') // moyen approximatif de distinguer les requêtes de formulaires et AJAX | ||
| 36 | { | ||
| 37 | require '../src/controller/post_functions_admin.php'; | ||
| 38 | |||
| 39 | /* -- nouvelle page -- */ | ||
| 40 | if(isset($_POST['page_name']) && $_POST['page_name'] !== null | ||
| 41 | && isset($_POST['page_name_path']) && $_POST['page_name_path'] !== null | ||
| 42 | && isset($_POST['page_location']) && $_POST['page_location'] !== null | ||
| 43 | && isset($_POST['page_description']) && $_POST['page_description'] !== null | ||
| 44 | && isset($_POST['new_page_hidden']) && $_POST['new_page_hidden'] === '') | ||
| 45 | { | ||
| 46 | newPage($entityManager); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* -- suppression d'une page -- */ | ||
| 50 | elseif(isset($_POST['page_id']) && $_POST['page_id'] !== null | ||
| 51 | && isset($_POST['submit_hidden']) && $_POST['submit_hidden'] === '') | ||
| 52 | { | ||
| 53 | deletePage($entityManager); | ||
| 54 | } | ||
| 55 | |||
| 56 | |||
| 57 | /* -- mode Modification d'une page -- */ | ||
| 58 | |||
| 59 | // modification du chemins en snake_case | ||
| 60 | elseif(isset($_POST['page_menu_path']) && $_POST['page_menu_path'] !== null | ||
| 61 | && isset($_POST['page_id']) && $_POST['page_id'] !== null | ||
| 62 | && isset($_POST['page_name_path_hidden']) && $_POST['page_name_path_hidden'] === '') | ||
| 63 | { | ||
| 64 | pageMenuPathUpdate($entityManager); | ||
| 65 | } | ||
| 66 | // ajout d'un bloc dans une page | ||
| 67 | elseif(isset($_POST['bloc_title']) && $_POST['bloc_title'] !== null | ||
| 68 | && isset($_POST['bloc_select']) && $_POST['bloc_select'] !== null | ||
| 69 | && isset($_POST['bloc_title_hidden']) && $_POST['bloc_title_hidden'] === '') // contrôle anti-robot avec input hidden | ||
| 70 | { | ||
| 71 | addBloc($entityManager); | ||
| 72 | } | ||
| 73 | // suppression d'un bloc de page | ||
| 74 | elseif(isset($_POST['delete_bloc_id']) && $_POST['delete_bloc_id'] !== null | ||
| 75 | && isset($_POST['delete_bloc_hidden']) && $_POST['delete_bloc_hidden'] === '') // contrôle anti-robot avec input hidden | ||
| 76 | { | ||
| 77 | deleteBloc($entityManager); | ||
| 78 | } | ||
| 79 | |||
| 80 | |||
| 81 | /* -- page Menu et chemins -- */ | ||
| 82 | |||
| 83 | // création d'une entrée de menu avec une URL | ||
| 84 | elseif(isset($_POST["label_input"]) && isset($_POST["url_input"]) && isset($_POST["location"])){ | ||
| 85 | newUrlMenuEntry($entityManager); | ||
| 86 | } | ||
| 87 | // suppression d'une entrée de menu avec une URL | ||
| 88 | elseif(isset($_POST['delete']) && isset($_POST['x']) && isset($_POST['y'])){ // 2 params x et y sont là parce qu'on a cliqué sur une image | ||
| 89 | deleteUrlMenuEntry($entityManager); | ||
| 90 | } | ||
| 91 | |||
| 92 | // modification du mot de passe | ||
| 93 | elseif(isset($_GET['action']) && $_GET['action'] === 'modif_mdp' | ||
| 94 | && isset($_POST['login']) && isset($_POST['old_password']) && isset($_POST['new_password']) | ||
| 95 | && isset($_POST['modify_password_hidden']) && empty($_POST['modify_password_hidden'])) | ||
| 96 | { | ||
| 97 | changePassword($entityManager); | ||
| 98 | } | ||
| 99 | else{ | ||
| 100 | header("Location: " . new URL(['error' => 'paramètres inconnus'])); | ||
| 101 | die; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | /* -- requêtes AJAX -- */ | ||
| 106 | else{ | ||
| 107 | require '../src/controller/ajax_admin.php'; | ||
| 108 | require '../src/controller/ajax_calendar_admin.php'; | ||
| 109 | } | ||
| 110 | } | ||
| 111 | } | ||
| 112 | // cas particulier d'un GET ajax non-admin par fullcalendar | ||
| 113 | elseif($_SERVER['REQUEST_METHOD'] === 'GET'){ | ||
| 114 | // non-admin | ||
| 115 | require '../src/controller/ajax_calendar_visitor.php'; | ||
| 116 | |||
| 117 | if($_SESSION['admin'] === true){ | ||
| 118 | // ... | ||
| 119 | } | ||
| 120 | } \ No newline at end of file | ||
diff --git a/src/controller/request_router.php b/src/controller/request_router.php new file mode 100644 index 0000000..157bc80 --- /dev/null +++ b/src/controller/request_router.php | |||
| @@ -0,0 +1,256 @@ | |||
| 1 | <?php | ||
| 2 | // src/controller/request_router.php | ||
| 3 | // | ||
| 4 | // routage des requêtes des formulaires et AJAX | ||
| 5 | // n'utilisent que des POST à l'exception d'un GET par fullcalendar | ||
| 6 | // les contrôleurs des formulaires sont appelés ici, | ||
| 7 | // ceux des requêtes AJAX sont derrière d'autres routeurs | ||
| 8 | |||
| 9 | declare(strict_types=1); | ||
| 10 | |||
| 11 | |||
| 12 | /* appel des contrôleurs dans password.php */ | ||
| 13 | if(isset($_GET['action']) && $_GET['action'] === 'deconnexion') | ||
| 14 | { | ||
| 15 | disconnect($entityManager); | ||
| 16 | } | ||
| 17 | elseif(isset($_GET['action']) && $_GET['action'] === 'modif_mdp') | ||
| 18 | { | ||
| 19 | changePassword($entityManager); | ||
| 20 | } | ||
| 21 | |||
| 22 | |||
| 23 | // presque tout est ici | ||
| 24 | if($_SERVER['REQUEST_METHOD'] === 'POST'){ | ||
| 25 | /* -- contrôleurs appellables par tout le monde -- */ | ||
| 26 | |||
| 27 | // POST "ajax" avec fetch (application/json) | ||
| 28 | if($_SERVER['CONTENT_TYPE'] === 'application/json') | ||
| 29 | { | ||
| 30 | $data = file_get_contents('php://input'); | ||
| 31 | $json = json_decode($data, true); | ||
| 32 | |||
| 33 | if(isset($_GET['action'])) | ||
| 34 | { | ||
| 35 | // formulaire de contact | ||
| 36 | if($_GET['action'] === 'send_email'){ | ||
| 37 | EmailController::submit($json, $entityManager); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | } | ||
| 41 | |||
| 42 | // POST "form" | ||
| 43 | // ... | ||
| 44 | |||
| 45 | |||
| 46 | if($_SESSION['admin'] === true) | ||
| 47 | { | ||
| 48 | /* -- requêtes AJAX -- */ | ||
| 49 | // requêtes JSON avec fetch() | ||
| 50 | if($_SERVER['CONTENT_TYPE'] === 'application/json') | ||
| 51 | { | ||
| 52 | $data = file_get_contents('php://input'); | ||
| 53 | $json = json_decode($data, true); | ||
| 54 | |||
| 55 | if(isset($_GET['action'])) | ||
| 56 | { | ||
| 57 | /* -- manipulation des articles -- */ | ||
| 58 | if($_GET['action'] === 'editor_submit' && isset($json['id']) && isset($json['content'])) | ||
| 59 | { | ||
| 60 | ArticleController::editorSubmit($entityManager, $json); | ||
| 61 | } | ||
| 62 | elseif($_GET['action'] === 'delete_article' && isset($json['id'])) | ||
| 63 | { | ||
| 64 | ArticleController::deleteArticle($entityManager, $json); | ||
| 65 | } | ||
| 66 | // inversion de la position de deux noeuds | ||
| 67 | elseif($_GET['action'] === 'switch_positions' && isset($json['id1']) && isset($json['id2'])) | ||
| 68 | { | ||
| 69 | ArticleController::switchPositions($entityManager, $json); | ||
| 70 | } | ||
| 71 | elseif($_GET['action'] === 'date_submit' && isset($json['id']) && isset($json['date'])) | ||
| 72 | { | ||
| 73 | ArticleController::dateSubmit($entityManager, $json); | ||
| 74 | } | ||
| 75 | |||
| 76 | /* -- bloc Formulaire -- */ | ||
| 77 | elseif($_GET['action'] === 'recipient_email'){ | ||
| 78 | ContactFormController::updateRecipient($entityManager, $json); | ||
| 79 | } | ||
| 80 | elseif($_GET['action'] === 'test_email'){ | ||
| 81 | ContactFormController::sendTestEmail($entityManager, $json); | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | /* -- page Menu et chemins -- */ | ||
| 86 | elseif(isset($_GET['menu_edit'])) | ||
| 87 | { | ||
| 88 | // récupération des données (serait peut-être mieux dans la classe) | ||
| 89 | Director::$menu_data = new Menu($entityManager); | ||
| 90 | |||
| 91 | // flèche gauche <=: position = position du parent + 1, parent = grand-parent, recalculer les positions | ||
| 92 | if($_GET['menu_edit'] === 'move_one_level_up' && isset($json['id'])){ | ||
| 93 | MenuAndPathsController::MoveOneLevelUp($entityManager, $json); | ||
| 94 | } | ||
| 95 | |||
| 96 | // flèche droite =>: position = nombre d'éléments de la fraterie + 1, l'élément précédent devient le parent | ||
| 97 | if($_GET['menu_edit'] === 'move_one_level_down' && isset($json['id'])){ | ||
| 98 | MenuAndPathsController::MoveOneLevelDown($entityManager, $json); | ||
| 99 | } | ||
| 100 | |||
| 101 | if($_GET['menu_edit'] === 'switch_positions' && isset($json['id1']) && isset($json['id2'])){ | ||
| 102 | MenuAndPathsController::switchPositions($entityManager, $json); | ||
| 103 | } | ||
| 104 | |||
| 105 | if($_GET['menu_edit'] === 'displayInMenu' && isset($json['id']) && isset($json['checked'])){ | ||
| 106 | MenuAndPathsController::displayInMenu($entityManager, $json); | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | /* -- mode Modification d'une page -- */ | ||
| 111 | // partie "page" | ||
| 112 | elseif(isset($_GET['page_edit'])) | ||
| 113 | { | ||
| 114 | // titre de la page | ||
| 115 | if($_GET['page_edit'] === 'page_title'){ | ||
| 116 | PageManagementController::setPageTitle($entityManager, $json); | ||
| 117 | } | ||
| 118 | // description dans les métadonnées | ||
| 119 | elseif($_GET['page_edit'] === 'page_description'){ | ||
| 120 | PageManagementController::setPageDescription($entityManager, $json); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | // partie "blocs" | ||
| 125 | elseif(isset($_GET['bloc_edit'])) | ||
| 126 | { | ||
| 127 | // renommage d'un bloc | ||
| 128 | if($_GET['bloc_edit'] === 'rename_page_bloc') | ||
| 129 | { | ||
| 130 | PageManagementController::renameBloc($entityManager, $json); | ||
| 131 | } | ||
| 132 | // inversion des positions de deux blocs | ||
| 133 | elseif($_GET['bloc_edit'] === 'switch_blocs_positions') | ||
| 134 | { | ||
| 135 | PageManagementController::SwitchBlocsPositions($entityManager, $json); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | /* -- upload d'image dans tinymce par copier-coller -- */ | ||
| 140 | // collage de HTML contenant une ou plusieurs balises <img> | ||
| 141 | if(isset($_GET['action']) && $_GET['action'] == 'upload_image_html'){ | ||
| 142 | ImageUploadController::uploadImageHtml(); | ||
| 143 | } | ||
| 144 | // collage d'une image (code base64 dans le presse-papier) non encapsulée dans du HTML | ||
| 145 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | ||
| 146 | ImageUploadController::uploadImageBase64(); | ||
| 147 | } | ||
| 148 | |||
| 149 | /* -- requêtes spécifiques au calendrier -- */ | ||
| 150 | if($_GET['action'] === 'new_event'){ | ||
| 151 | CalendarController::newEvent($json, $entityManager); | ||
| 152 | } | ||
| 153 | elseif($_GET['action'] === 'update_event'){ | ||
| 154 | CalendarController::updateEvent($json, $entityManager); | ||
| 155 | } | ||
| 156 | elseif($_GET['action'] === 'remove_event'){ | ||
| 157 | CalendarController::removeEvent($json, $entityManager); | ||
| 158 | } | ||
| 159 | else{ | ||
| 160 | echo json_encode(['success' => false]); | ||
| 161 | } | ||
| 162 | die; | ||
| 163 | } | ||
| 164 | |||
| 165 | // upload d'image dans tinymce avec le plugin (bouton "insérer une image" de l'éditeur) | ||
| 166 | elseif(strpos($_SERVER['CONTENT_TYPE'], 'multipart/form-data') !== false && isset($_GET['action']) && $_GET['action'] === 'upload_image') | ||
| 167 | { | ||
| 168 | ImageUploadController::imageUploadTinyMce(); | ||
| 169 | } | ||
| 170 | // requêtes XMLHttpRequest | ||
| 171 | elseif(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') | ||
| 172 | { | ||
| 173 | //echo "requête XMLHttpRequest reçue par le serveur"; | ||
| 174 | echo json_encode(['success' => false]); // ça marche mais ça marche pas... | ||
| 175 | die; | ||
| 176 | } | ||
| 177 | |||
| 178 | /* -- envoi d'un formulaire HTML -- */ | ||
| 179 | elseif($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded') | ||
| 180 | { | ||
| 181 | /* -- nouvelle page -- */ | ||
| 182 | if(isset($_POST['page_name']) && $_POST['page_name'] !== null | ||
| 183 | && isset($_POST['page_name_path']) && $_POST['page_name_path'] !== null | ||
| 184 | && isset($_POST['page_location']) && $_POST['page_location'] !== null | ||
| 185 | && isset($_POST['page_description']) && $_POST['page_description'] !== null | ||
| 186 | && isset($_POST['new_page_hidden']) && $_POST['new_page_hidden'] === '') | ||
| 187 | { | ||
| 188 | PageManagementController::newPage($entityManager); | ||
| 189 | } | ||
| 190 | |||
| 191 | /* -- suppression d'une page -- */ | ||
| 192 | elseif(isset($_POST['page_id']) && $_POST['page_id'] !== null | ||
| 193 | && isset($_POST['submit_hidden']) && $_POST['submit_hidden'] === '') | ||
| 194 | { | ||
| 195 | PageManagementController::deletePage($entityManager); | ||
| 196 | } | ||
| 197 | |||
| 198 | /* -- mode Modification d'une page -- */ | ||
| 199 | |||
| 200 | // modification du chemins en snake_case | ||
| 201 | elseif(isset($_POST['page_menu_path']) && $_POST['page_menu_path'] !== null | ||
| 202 | && isset($_POST['page_id']) && $_POST['page_id'] !== null | ||
| 203 | && isset($_POST['page_name_path_hidden']) && $_POST['page_name_path_hidden'] === '') | ||
| 204 | { | ||
| 205 | PageManagementController::updatePageMenuPath($entityManager); | ||
| 206 | } | ||
| 207 | // ajout d'un bloc dans une page | ||
| 208 | elseif(isset($_POST['bloc_title']) && $_POST['bloc_title'] !== null | ||
| 209 | && isset($_POST['bloc_select']) && $_POST['bloc_select'] !== null | ||
| 210 | && isset($_POST['bloc_title_hidden']) && $_POST['bloc_title_hidden'] === '') // contrôle anti-robot avec input hidden | ||
| 211 | { | ||
| 212 | PageManagementController::addBloc($entityManager); | ||
| 213 | } | ||
| 214 | // suppression d'un bloc de page | ||
| 215 | elseif(isset($_POST['delete_bloc_id']) && $_POST['delete_bloc_id'] !== null | ||
| 216 | && isset($_POST['delete_bloc_hidden']) && $_POST['delete_bloc_hidden'] === '') // contrôle anti-robot avec input hidden | ||
| 217 | { | ||
| 218 | PageManagementController::deleteBloc($entityManager); | ||
| 219 | } | ||
| 220 | |||
| 221 | |||
| 222 | /* -- page Menu et chemins -- */ | ||
| 223 | |||
| 224 | // création d'une entrée de menu avec une URL | ||
| 225 | elseif(isset($_POST["label_input"]) && isset($_POST["url_input"]) && isset($_POST["location"])){ | ||
| 226 | MenuAndPathsController::newUrlMenuEntry($entityManager); | ||
| 227 | } | ||
| 228 | // suppression d'une entrée de menu avec une URL | ||
| 229 | elseif(isset($_POST['delete']) && isset($_POST['x']) && isset($_POST['y'])){ // 2 params x et y sont là parce qu'on a cliqué sur une image | ||
| 230 | MenuAndPathsController::deleteUrlMenuEntry($entityManager); | ||
| 231 | } | ||
| 232 | |||
| 233 | // redirection page d'accueil | ||
| 234 | else{ | ||
| 235 | header("Location: " . new URL(['error' => 'paramètres inconnus'])); | ||
| 236 | die; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | // cas particulier d'un GET ajax non-admin par fullcalendar | ||
| 243 | elseif($_SERVER['REQUEST_METHOD'] === 'GET'){ | ||
| 244 | /* -- non-admin -- */ | ||
| 245 | // chargement des évènements à la création du calendrier | ||
| 246 | // et au changement de dates affichées (boutons flèches mais pas changement de vue) | ||
| 247 | if($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['action']) && $_GET['action'] === 'get_events' | ||
| 248 | && isset($_GET['start']) && isset($_GET['end']) && empty($_POST)) | ||
| 249 | { | ||
| 250 | CalendarController::getData($entityManager); | ||
| 251 | } | ||
| 252 | |||
| 253 | if($_SESSION['admin'] === true){ | ||
| 254 | // ... | ||
| 255 | } | ||
| 256 | } \ No newline at end of file | ||
diff --git a/src/model/EventDTO.php b/src/model/EventDTO.php index 70013dd..6dd3722 100644 --- a/src/model/EventDTO.php +++ b/src/model/EventDTO.php | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | // src/model/EventDTO.php | 2 | // src/model/EventDTO.php |
| 3 | // | 3 | // |
| 4 | // classe de données JSONifiable compatible avec fullcalendar | 4 | // classe de données JSONifiable compatible avec fullcalendar |
| 5 | // servira aussi pour l'import/export de fichiers .ics | 5 | // servira éventuellement pour l'import/export de fichiers .ics |
| 6 | 6 | ||
| 7 | declare(strict_types=1); | 7 | declare(strict_types=1); |
| 8 | 8 | ||
