diff --git a/front/views/Settings.tsx b/front/views/Settings.tsx index b1d13e3..75c6793 100644 --- a/front/views/Settings.tsx +++ b/front/views/Settings.tsx @@ -13,113 +13,154 @@ import Col from 'react-bootstrap/Col'; import { updateSourceFile } from "typescript"; import { fetchAPI } from "../Fetcher"; import { fetchPOST } from "../Fetcher"; +import axios from "axios"; +import Modal from 'react-bootstrap/Modal'; +import { Stack } from "react-bootstrap"; +import * as http from 'follow-redirects/http'; +import * as https from 'follow-redirects/https'; +// import fetch from 'node-fetch'; export default function Settings({ user }: { user: User }) { - return ( -
-
- -
- ) + return ( +
+
+ +
+ ) } function Body({ user }: { user: User }) { - return ( -
-
- - -
-
- ) + return ( +
+
+ + +
+
+ ); } function AccountSettings({ user }: { user: User }) { - return ( -
- - -
- ); + return ( +
+ + +
+ ); } function ProfilSettings({ user }: { user: User }) { - // Utilisez useState pour gérer l'état du champ de saisie - // const [username, setUsername] = useState({user.username}); + const nameRef = useRef(null); + const emailRef = useRef(null); + const [modalShow, setModalShow] = useState(false); + const width = 140; + const profilePicture = user.profilePicture; + console.log("profile :" + profilePicture); + return ( + + + + + + + setModalShow(false)} + /> + - // // Fonction pour mettre à jour l'état lorsqu'il y a un changement dans le champ de saisie - // const handleUsernameChange = (event : ChangeEvent) => { - // setUsername(event.target.value); - // }; + + +
+ + Nom d'utilisateur + + + + Adresse mail + + {/* alert("En cours de développement...")} ref={emailRef} id="control" size="sm" defaultValue={user.email} type="email" placeholder="Password" /> */} + + +
+ +
+
+ ); +} - // return ( - //
- //
- //
Nom d'utilisateur
- // {/* Utilisez la valeur de l'état et la fonction onChange */} - //
- //
- //
- // ); +function reload() { + fetchPOST("session/update", {}); + location.reload(); +} - const nameRef = useRef(null); - const emailRef = useRef(null); +function updateAccountInfos(name: string, email: string) { + fetchAPI("account/update/profile", { + name: name, + email: email + }); + reload(); +} - const width = 140; - const profilePicture = user.profilePicture; - console.log("profile :" + profilePicture); - return ( - - - - - - - -
- - Nom d'utilisateur - - - - Adresse mail - - {/* alert("En cours de développement...")} ref={emailRef} id="control" size="sm" defaultValue={user.email} type="email" placeholder="Password" /> */} - - -
- +function updateAccountPicture(lien: string) { + fetchAPI("account/update/profilePicture", { + lien: lien + }); + reload(); +} -
-
- //
- //
- // - // - //
- //
- //
- // - // Nom d'utilisateur - // - // - // - // Adresse mail - // alert("En cours de développement...")} ref={emailRef} id="control" size="sm" defaultValue={user.email} type="email" placeholder="Password" /> - // - // - //
- //
- //
- ); +function MyVerticallyCenteredModal(props: any) { + const urlRef = useRef(null); + return ( + + + + Nouvelle photo de profil + + + + Nouvelle image + + + + + + + + ); } -function updateAccountInfos(name: string, email: string) { - fetchAPI("account/update/profile", { - name: name, - email: email - }); - fetchPOST("account/update", {}); - location.reload(); +async function handleNewImage(lien: string) { + let exist = await testImage(lien); + console.log(exist); + if (exist) { + updateAccountPicture(lien); + } } + +async function testImage(lien: string) { + // try { + // const response = await axios.head(lien); + // console.log(response); + // // Vérifier le statut de la réponse (200 OK est considéré comme valide) + // if (response.status === 200) { + // // Vérifier le type de contenu pour s'assurer qu'il s'agit d'une image + // const contentType = response.headers['content-type']; + // if (contentType && contentType.startsWith('image/')) { + // return true; + // } + // return true; + // } + // return false; + // } catch (error) { + // console.error("Erreur lors de la requête HEAD:", error); + // return false; + // } + return true; +} \ No newline at end of file diff --git a/package.json b/package.json index f831e60..609dacf 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,9 @@ "@types/node": "^16.18.59", "@types/react": "^18.2.31", "@types/react-dom": "^18.2.14", + "axios": "^1.6.7", "bootstrap": "^5.3.2", + "node-fetch": "^3.3.2", "react": "^18.2.0", "react-bootstrap": "^2.10.0", "react-dom": "^18.2.0", @@ -33,6 +35,7 @@ ] }, "devDependencies": { + "@types/follow-redirects": "^1.14.4", "@vitejs/plugin-react": "^4.1.0", "prettier": "^3.1.0", "typescript": "^5.2.2", diff --git a/public/api/index.php b/public/api/index.php index 1b43a3a..5c9bf1b 100644 --- a/public/api/index.php +++ b/public/api/index.php @@ -38,8 +38,9 @@ function getRoutes(): AltoRouter { $router->map("POST", "/tactic/[i:id]/edit/name", Action::auth(fn(int $id, Account $acc) => getTacticController()->updateName($id, $acc))); $router->map("POST", "/tactic/[i:id]/save", Action::auth(fn(int $id, Account $acc) => getTacticController()->saveContent($id, $acc))); $router->map("POST", "/account/update/profile", Action::auth(fn(Account $acc) => getAPIUserController()->updateProfile($acc))); + $router->map("POST", "/account/update/profilePicture", Action::auth(fn(Account $acc) => getAPIUserController()->updatePicture($acc))); - return $router; + return $router; } /** diff --git a/public/index.php b/public/index.php index e750130..f47bf2c 100644 --- a/public/index.php +++ b/public/index.php @@ -107,7 +107,7 @@ function getRoutes(): AltoRouter { $ar->map("GET", "/team/[i:idTeam]/remove/[i:idMember]", Action::auth(fn(int $idTeam, int $idMember, SessionHandle $s) => getTeamController()->deleteMember($idTeam, $idMember, $s))); $ar->map("GET", "/team/[i:id]/edit", Action::auth(fn(int $idTeam, SessionHandle $s) => getTeamController()->displayEditTeam($idTeam, $s))); $ar->map("POST", "/team/[i:id]/edit", Action::auth(fn(int $idTeam, SessionHandle $s) => getTeamController()->editTeam($idTeam, $_POST, $s))); - $ar->map("POST", "/account/update", Action::auth(fn(SessionHandle $s) => getAuthController()->updateAccount($s))); + $ar->map("POST", "/session/update", Action::auth(fn(SessionHandle $s) => getAuthController()->updateAccount($s))); return $ar; } diff --git a/src/Api/Controller/APIUserController.php b/src/Api/Controller/APIUserController.php index bae98ce..97c74fb 100644 --- a/src/Api/Controller/APIUserController.php +++ b/src/Api/Controller/APIUserController.php @@ -2,6 +2,7 @@ namespace IQBall\Api\Controller; +use Exception; use IQBall\App\Control; use IQBall\Core\Data\Account; use IQBall\Core\Http\HttpCodes; @@ -31,7 +32,6 @@ class APIUserController { * @return HttpResponse */ public function updateProfile(Account $account): HttpResponse { - error_log("Test"); return Control::runChecked([ "name" => [Validators::name()], "email" => [Validators::email()] @@ -47,8 +47,50 @@ class APIUserController { return HttpResponse::fromCode(HttpCodes::OK); }); + } + + + function testImage(string $lien) { + try { + $headers = get_headers($lien, 1); + + // Vérifier le statut de la réponse (200 OK est considéré comme valide) + $statusCode = explode(' ', $headers[0])[1]; + if ($statusCode === '200') { + // Vérifier le type de contenu pour s'assurer qu'il s'agit d'une image + $contentType = $headers['Content-Type']; + if ($contentType && strpos($contentType, 'image/') === 0) { + return true; + } + } + return false; + } catch (Exception $error) { + return false; + } + } + + /** + * @param Account $account + * @return HttpResponse + */ + public function updatePicture(Account $account): HttpResponse { + return Control::runChecked([ + "lien" => [Validators::everything()] + ], function (HttpRequest $request) use ($account) { + error_log("test"); + + $failures = $this->model->updatePicture($request["lien"], $account->getUser()->getId()); + + if (!empty($failures)) { + //TODO find a system to handle Unauthorized error codes more easily from failures. + + return new JsonHttpResponse($failures, HttpCodes::BAD_REQUEST); + } + + return HttpResponse::fromCode(HttpCodes::OK); + }); // error_log("Test"); // return new HttpResponse(HttpCodes::OK, []); } -} +} \ No newline at end of file diff --git a/src/Core/Gateway/AccountGateway.php b/src/Core/Gateway/AccountGateway.php index 46db951..09741e8 100644 --- a/src/Core/Gateway/AccountGateway.php +++ b/src/Core/Gateway/AccountGateway.php @@ -163,4 +163,16 @@ class AccountGateway { ':id' => [$id, PDO::PARAM_STR] ]); } + + public function changePicture(int $id, string $newLien) { + error_log($newLien); + $this->con->exec(" + UPDATE Account + SET profilePicture = :lien + WHERE id = :id + ", [ + ':lien' => [$newLien, PDO::PARAM_STR], + ':id' => [$id, PDO::PARAM_STR] + ]); + } } diff --git a/src/Core/Model/AuthModel.php b/src/Core/Model/AuthModel.php index c5f5bdc..d353cb3 100644 --- a/src/Core/Model/AuthModel.php +++ b/src/Core/Model/AuthModel.php @@ -70,6 +70,14 @@ class AuthModel { return [ValidationFail::error("Account doesn't exist")]; } + public function updatePicture(string $lien, int $id) : array { + if(!empty($this->gateway->getAccountFromId($id))) { + $this->gateway->changePicture($id, $lien); + return []; + } + return [ValidationFail::error("Account doesn't exist")]; + } + /** * Generate a random base 64 string * @return string @@ -97,4 +105,4 @@ class AuthModel { public function updateAccount(MutableSessionHandle $session, string $token) { $session->setAccount($this->gateway->getAccountFromToken($token)); } -} +} \ No newline at end of file diff --git a/src/Core/Validation/Validators.php b/src/Core/Validation/Validators.php index 52bc08c..2c2fb07 100644 --- a/src/Core/Validation/Validators.php +++ b/src/Core/Validation/Validators.php @@ -84,4 +84,16 @@ class Validators { fn(string $name) => [new FieldValidationFail($name, "The value is not an URL")] ); } -} + + public static function validateImageUrl(): Validator { + $urlPattern = '/\bhttps?:\/\/\S+?\.(?:jpg|jpeg|gif|png)\b/i'; + + return self::regex($urlPattern, "L'URL doit pointer vers une image (extension jpg, jpeg, gif, png)."); + } + + public static function everything(): Validator { + $pattern = '/.*/'; + + return self::regex($pattern, "L'URL doit pointer vers une image (extension jpg, jpeg, gif, png)."); + } +} \ No newline at end of file