Compare commits

...

No commits in common. "8b094379ca40501906a7986f0224ca2640db63c1" and "a18d1bf92a0f39ef19c98ffe41778b9842085736" have entirely different histories.

76 changed files with 1133 additions and 1835 deletions

10
.env
View file

@ -1,10 +0,0 @@
# config BDD
DB_CONNECTION=mysql
DB_HOSTNAME=boulayoune.com
DB_DATABASE=projet_folliow
DB_USERNAME=
DB_PASSWORD=
IMG_PROJECT_PATH = uploads/projects/
IMG_USER_PATH = uploads/profiles/

View file

@ -1,37 +0,0 @@
name: Deploy production (servyass)
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy via SSH
uses: appleboy/ssh-action@master
with:
host: boulayoune.com
username: yass
key: |
${{ secrets.SSH_KEY }}
port: 22
debug: true
script: |
echo "➡️ Connexion réussie !"
cd /var/www/projet_php
echo "➡️ Mise à jour du code..."
git fetch origin main
git reset --hard origin/main
echo "➡️ Correction des permissions et nettoyage..."
sudo chown -R yass:www-data /var/www/projet_php
sudo chmod -R 775 /var/www/projet_php/templates_c
sudo rm -rf /var/www/projet_php/templates_c/*
sudo chmod -R 775 /var/www/projet_php/uploads/projects
sudo chmod -R 775 /var/www/projet_php/uploads/profiles
echo "✅ Déploiement terminé ! (Shin-en no Egotisu)"

View file

@ -1,98 +0,0 @@
# Folliow Projet PHP
A platform for sharing portfolios and projects, designed as a mix between Behance and LinkedIn. Folliow focuses on highlighting real projects while making it easy to connect with other users.
This project was developed as part of the **DWWM (Développeur Web et Web Mobile)** training.
---
## Features
- User authentication and profile management
- Portfolio and project creation
- Project showcase with descriptions and technologies
- User connections / follow system
- Project feed and discovery
- Profile and project search
---
## Tech Stack
**Client:** HTML, CSS, JavaScript
**Server:** PHP (MVC architecture)
**Database:** MySQL
**Web Server:** Apache
---
## Project Structure
```text
folliow/
├── app/
│ ├── controllers/
│ ├── models/
│ └── views/
├── public/
│ ├── assets/
│ └── index.php
├── config/
│ └── database.php
├── sql/
│ └── folliow.sql
└── README.md
```
---
## Installation
Clone the project
```bash
git clone https://github.com/Yasder5/projet_php.git
```
Go to the project directory
```bash
cd projet_php
```
Import the database
- Use the SQL file located in the `sql/` directory
Configure database access
- Update credentials in `config/database.php`
Run the project
- Use a local server (XAMPP, WAMP, or Apache on Linux)
---
## Learning Objectives
- Build a complete PHP web application
- Apply MVC architecture
- Manage a relational database
- Design a user-oriented portfolio platform
---
## Future Improvements
- Private messaging
- Likes and comments on projects
- Tags and categories
- Improved responsive design
- Advanced authentication and roles
---
## License
This project is for educational purposes.

View file

@ -102,7 +102,7 @@ body {
.footer{ .footer{
color: white; color: white;
background-color: #6A6ED4; background-color: #0000ff;
} }
.footer ul{ .footer ul{
@ -113,7 +113,3 @@ body {
text-decoration: none; text-decoration: none;
color: white; color: white;
} }
.txt_title {
color: rgb(51, 152, 217);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

View file

@ -1,5 +1,5 @@
{ {
"name": "groupe3/projetphp", "name": "yasse/projetphp",
"description": "le projet php de ces mort", "description": "le projet php de ces mort",
"require": { "require": {
"smarty/smarty": "^5.7", "smarty/smarty": "^5.7",
@ -8,15 +8,13 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Controllers\\": "controllers/", "Guill\\Guillaume\\": "src/"
"Entities\\": "entities/",
"Models\\": "models/"
} }
}, },
"authors": [ "authors": [
{ {
"name": "Le Meilleur groupe", "name": "GuillaumeH-Cci",
"email": "pasdemail@meilleurgroupe.ccicampus" "email": "guillaume.hess@ccicampus.fr"
} }
] ]
} }

View file

@ -1,39 +0,0 @@
<?php
namespace Controllers;
/**
* Le controller des pages annexes
* @author Laura & Besnik
*/
class PageCtrl extends MotherCtrl{
/**
* Page aide utilisateur
*/
public function help(){
$this->_display("help");
}
/**
* Page mentions légales
*/
public function mentions(){
// Afficher
$this->_display("mentions");
}
/**
* Page à propos
*/
public function about(){
// Afficher
$this->_display("about");
}
}

View file

@ -1,13 +1,16 @@
<?php <?php
namespace Controllers;
use Models\CategoryModel; require("./models/project_model.php");
use Models\UserModel; require("./entities/project_entity.php");
use Models\AuthorisationModel; require("./models/category_model.php");
require("./entities/category_entity.php");
use Entities\Category; require("./models/image_model.php");
use Entities\Authorisation; require("./entities/image_entity.php");
use Entities\User; require("./models/user_model.php");
require("./entities/user_entity.php");
require("./models/authorisation_model.php");
require("./entities/authorisation_entity.php");
require("mother_controller.php");
/** /**
* Le controller de la partie accessible uniquement par l'admin * Le controller de la partie accessible uniquement par l'admin
@ -15,9 +18,7 @@
*/ */
class AdminCtrl extends MotherCtrl{ class AdminCtrl extends MotherCtrl{
/**
* Page Admin
*/
public function admin(){ public function admin(){
if (!isset($_SESSION['user']) && ($_SESSION['user']['user_status'] != 1 )){ if (!isset($_SESSION['user']) && ($_SESSION['user']['user_status'] != 1 )){
@ -25,6 +26,7 @@
exit; exit;
} }
//gestion de l'user
$objCategoryModel = new CategoryModel; $objCategoryModel = new CategoryModel;
if (!empty($_POST['new_category'])) { if (!empty($_POST['new_category'])) {
@ -46,6 +48,7 @@
exit; exit;
} }
//affichage select des catégories
$arrCategory = $objCategoryModel->findAllCategory(); $arrCategory = $objCategoryModel->findAllCategory();
$arrCategoryToDisplay = array(); $arrCategoryToDisplay = array();
@ -55,6 +58,7 @@
$arrCategoryToDisplay[] = $objCategory; $arrCategoryToDisplay[] = $objCategory;
} }
//gestion de l'user
$objUserModel = new UserModel; $objUserModel = new UserModel;
if (!empty($_POST['action'])) { if (!empty($_POST['action'])) {
@ -78,6 +82,7 @@
} }
} }
//affichage select des users
$arrUser = $objUserModel->findAllUsers(); $arrUser = $objUserModel->findAllUsers();
$arrUserToDisplay = array(); $arrUserToDisplay = array();
@ -87,6 +92,7 @@
$arrUserToDisplay[] = $objUser; $arrUserToDisplay[] = $objUser;
} }
//affichage select des authorisations
$objAuthorisationModel = new AuthorisationModel; $objAuthorisationModel = new AuthorisationModel;
$arrAuthorisation = $objAuthorisationModel->findAllAuthorisation(); $arrAuthorisation = $objAuthorisationModel->findAllAuthorisation();
$arrAuthorisationToDisplay = array(); $arrAuthorisationToDisplay = array();
@ -97,6 +103,7 @@
$arrAuthorisationToDisplay[] = $objAuthorisation; $arrAuthorisationToDisplay[] = $objAuthorisation;
} }
//gérer l'affichage
$this->_arrData['arrCategoryToDisplay'] = $arrCategoryToDisplay; $this->_arrData['arrCategoryToDisplay'] = $arrCategoryToDisplay;
$this->_arrData['arrUserToDisplay'] = $arrUserToDisplay; $this->_arrData['arrUserToDisplay'] = $arrUserToDisplay;
$this->_arrData['arrAuthorisationToDisplay'] = $arrAuthorisationToDisplay; $this->_arrData['arrAuthorisationToDisplay'] = $arrAuthorisationToDisplay;

View file

@ -1,9 +1,9 @@
<?php <?php
namespace Controllers; require("mother_controller.php");
/** /**
* Le contrôleur des erreurs * Le contrôleur des erreurs
* @author Laura * @author Laura (largement inspiré de Christel)
*/ */
class ErrorCtrl extends MotherCtrl{ class ErrorCtrl extends MotherCtrl{

View file

@ -1,12 +1,7 @@
<?php <?php
namespace Controllers;
use Smarty\Smarty; use Smarty\Smarty;
/**
* Controller Mère qui permet de gèrer l'affichage des pages
* @author Yasser
*/
class MotherCtrl { class MotherCtrl {
@ -14,25 +9,27 @@
/** /**
* Méthode d'affichage des pages * Méthode d'affichage des pages
* @param string $strView Le fichier a afficher
* @param bool $boolDisplay Booléen pour afficher web ou mail
* @return page|object affiche la page ou retourne l'objet pour le mail
*/ */
protected function _display($strView, bool $boolDisplay = true){ protected function _display($strView, bool $boolDisplay = true){
// Création de l'objet Smarty
$objSmarty = new Smarty(); $objSmarty = new Smarty();
// Ajouter le var_dump au modificateur de smarty : vardump est le nom appelé après le |
$objSmarty->registerPlugin('modifier', 'vardump', 'var_dump'); $objSmarty->registerPlugin('modifier', 'vardump', 'var_dump');
$objSmarty->registerPlugin('modifier', 'file_exists', 'file_exists'); // Désactiver la mise en cache
$objSmarty->caching = false; $objSmarty->caching = false;
// Forcer la recompilation des templates
$objSmarty->force_compile = true; $objSmarty->force_compile = true;
// Vérifier si les templates ont été modifiés
$objSmarty->compile_check = true; $objSmarty->compile_check = true;
// Récupérer les variables
foreach($this->_arrData as $key=>$value){ foreach($this->_arrData as $key=>$value){
//$$key = $value;
$objSmarty->assign($key, $value); $objSmarty->assign($key, $value);
} }
// Message de succès
$objSmarty->assign("success_message", $_SESSION['success']??''); $objSmarty->assign("success_message", $_SESSION['success']??'');
unset($_SESSION['success']); unset($_SESSION['success']);
@ -46,6 +43,14 @@
}else{ }else{
return $objSmarty->fetch("views/".$strView.".tpl"); return $objSmarty->fetch("views/".$strView.".tpl");
} }
// inclusion du header
/*include("views/_partial/header.php");
include("views/".$strView.".php");
include("views/_partial/footer.php");*/
} }
} }

View file

@ -0,0 +1,17 @@
<?php
require("mother_controller.php");
/**
* Le controller de la page d'aide utilisateur
* @author Laura
*/
class PageCtrl extends MotherCtrl{
public function help(){
$this->_display("help");
}
}

View file

@ -1,34 +1,27 @@
<?php <?php
require("./models/project_model.php");
namespace Controllers; require("./entities/project_entity.php");
require("./models/category_model.php");
require("./entities/category_entity.php");
require("./models/image_model.php");
use Models\ProjectModel; require("./entities/image_entity.php");
use Models\CategoryModel; require("./models/user_model.php");
use Models\ImageModel; require("./entities/user_entity.php");
use Models\UserModel; require("mother_controller.php");
use Entities\Project;
use Entities\Category;
use Entities\Authorisation;
use Entities\User;
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\SMTP; use PHPMailer\PHPMailer\SMTP;
/** /**
* Le controler des Project * Le controler des Project
* @author Yasser, Laura, Besnik & Guillaume * @author Yasser & Laura
*/ */
class ProjectCtrl extends MotherCtrl{ class ProjectCtrl extends MotherCtrl{
/** /**
* Fonction d'affichage de la page d'acceuil * Fonction d'affichage de la page d'acceuil
*/ */
public function home(){ public function home(){
@ -38,12 +31,15 @@
$hash_a_verifier = hash('sha256', $token_du_cookie); $hash_a_verifier = hash('sha256', $token_du_cookie);
$objUserModel = new UserModel; $objUserModel = new UserModel;
// 2. On cherche le jeton dans TA table "tokens" (avec token_user_id)
$row = $objUserModel->getTokenUser($hash_a_verifier); $row = $objUserModel->getTokenUser($hash_a_verifier);
if ($row) { if ($row) {
// 3. Jeton trouvé ! On récupère les infos de l'utilisateur
$user = $objUserModel->findUserById($row['token_user_id']); $user = $objUserModel->findUserById($row['token_user_id']);
if ($user) { if ($user) {
// 4. On recrée la session comme lors d'un login normal
$_SESSION['user'] = $user; $_SESSION['user'] = $user;
} }
} }
@ -79,6 +75,7 @@
*/ */
public function search(){ public function search(){
//Récupérer les informations du formulaire
$strKeywords = $_POST['keywords']??''; $strKeywords = $_POST['keywords']??'';
$intAuthor = $_POST['author']??0; $intAuthor = $_POST['author']??0;
$intPeriod = $_POST['period']??0; $intPeriod = $_POST['period']??0;
@ -87,6 +84,7 @@
$strEndDate = $_POST['enddate']??''; $strEndDate = $_POST['enddate']??'';
$intCategory = $_POST['category']??0; $intCategory = $_POST['category']??0;
// Récupération des projets
$objProjectModel = new ProjectModel; $objProjectModel = new ProjectModel;
$arrProject = $objProjectModel->findAll(intAuthor:$intAuthor, intPeriod:$intPeriod, strDate:$strDate, $arrProject = $objProjectModel->findAll(intAuthor:$intAuthor, intPeriod:$intPeriod, strDate:$strDate,
strKeywords:$strKeywords, strStartDate:$strStartDate, strEndDate:$strEndDate, intCategory:$intCategory); strKeywords:$strKeywords, strStartDate:$strStartDate, strEndDate:$strEndDate, intCategory:$intCategory);
@ -98,32 +96,28 @@
$arrProjectToDisplay[] = $objProject; $arrProjectToDisplay[] = $objProject;
} }
// Récupération des utilisateurs
$objUserModel = new UserModel; $objUserModel = new UserModel;
$arrUser = $objUserModel->findAllUsers(); $arrUser = $objUserModel->findAllUsers();
// Récupération des catégories
$objCategoryModel = new CategoryModel; $objCategoryModel = new CategoryModel;
$arrCategory = $objCategoryModel->findAllCategory(); $arrCategory = $objCategoryModel->findAllCategory();
$this->_arrData['arrProjectToDisplay'] = $arrProjectToDisplay; $this->_arrData['arrProjectToDisplay'] = $arrProjectToDisplay;
$this->_arrData['arrCategory'] = $arrCategory; $this->_arrData['arrCategory'] = $arrCategory;
$this->_arrData['arrProject'] = $arrProject; $this->_arrData['arrProject'] = $arrProject;
$this->_arrData['arrUser'] = $arrUser; $this->_arrData['arrUser'] = $arrUser;
$this->_arrData['strKeywords'] = $strKeywords;
$this->_arrData['intAuthor'] = $intAuthor;
$this->_arrData['intPeriod'] = $intPeriod;
$this->_arrData['strDate'] = $strDate;
$this->_arrData['strStartDate'] = $strStartDate;
$this->_arrData['strEndDate'] = $strEndDate;
$this->_arrData['intCategory'] = $intCategory;
$this->_display("search"); $this->_display("search");
} }
/** /**
* Fonction d'affichage de la page projet * Fonction d'affichage de la page projet
* @author Christel adapter par Guillaume
*/ */
public function addedit_project() { public function addedit_project(){
if (!isset($_SESSION['user'])){ if (!isset($_SESSION['user'])){ // Pas d'utilisateur connecté
header("Location:index.php?ctrl=error&action=error_403"); header("Location:index.php?ctrl=error&action=error_403");
exit; exit;
} }
@ -132,20 +126,18 @@
$objProjectModel = new ProjectModel; $objProjectModel = new ProjectModel;
$objCategoryModel = new CategoryModel; $objCategoryModel = new CategoryModel;
// Dans la cas de modif
if (isset($_GET['id'])){ if (isset($_GET['id'])){
$arrProject = $objProjectModel->findOne($_GET['id']); $arrProject = $objProjectModel->findOne($_GET['id']);
if($_SESSION['user']['user_id'] != $arrProject['project_user_id']){ $objProject->hydrate($arrProject); // BDD
header("Location:index.php?ctrl=error&action=error_403");
exit;
}
$objProject->hydrate($arrProject);
$this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId()); $this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId());
} }
// Tester le formulaire
$arrError = []; $arrError = [];
if (count($_POST) > 0) { if (count($_POST) > 0) {
$objProject->hydrate($_POST); $objProject->hydrate($_POST); // Formulaire
if ($objProject->getTitle() == ""){ if ($objProject->getTitle() == ""){
$arrError['title'] = "Le titre est obligatoire"; $arrError['title'] = "Le titre est obligatoire";
} }
@ -158,6 +150,7 @@
$arrError['content'] = "Le contenu est obligatoire"; $arrError['content'] = "Le contenu est obligatoire";
} }
// Vérification de l'image (Thumbnail)
$arrTypeAllowed = array('image/jpeg', 'image/png', 'image/webp'); $arrTypeAllowed = array('image/jpeg', 'image/png', 'image/webp');
if ($_FILES['thumbnail']['error'] != 4){ if ($_FILES['thumbnail']['error'] != 4){
if (!in_array($_FILES['thumbnail']['type'], $arrTypeAllowed)){ if (!in_array($_FILES['thumbnail']['type'], $arrTypeAllowed)){
@ -192,14 +185,18 @@
} }
} }
// SI pas d'erreur : on traite l'image principale
if (count($arrError) == 0){ if (count($arrError) == 0){
$boolImageOk = true; $boolImageOk = true;
// On peux changer ces dimensions si on veux que la miniature soit plus grande/petite
if (isset($strImageName)){ if (isset($strImageName)){
$strDest = $_ENV['IMG_PROJECT_PATH'].$strImageName; $strDest = $_ENV['IMG_PROJECT_PATH'].$strImageName;
$strSource = $_FILES['thumbnail']['tmp_name']; $strSource = $_FILES['thumbnail']['tmp_name'];
list($intWidth, $intHeight) = getimagesize($strSource); list($intWidth, $intHeight) = getimagesize($strSource);
// Redimensionnement de la Thumbnail
$intDestWidth = 200; $intDestHeight = 250; $intDestWidth = 200; $intDestHeight = 250;
$fltDestRatio = $intDestWidth / $intDestHeight; $fltDestRatio = $intDestWidth / $intDestHeight;
$fltSourceRatio = $intWidth / $intHeight; $fltSourceRatio = $intWidth / $intHeight;
@ -232,10 +229,12 @@
imagecopyresampled($objDest, $objSource, 0, 0, $intCropX, $intCropY, $intDestWidth, $intDestHeight, $intCropWidth, $intCropHeight); imagecopyresampled($objDest, $objSource, 0, 0, $intCropX, $intCropY, $intDestWidth, $intDestHeight, $intCropWidth, $intCropHeight);
$boolImageOk = imagewebp($objDest, $strDest); $boolImageOk = imagewebp($objDest, $strDest);
//Suppression des doublons pour la mémoire vive
imagedestroy($objDest); imagedestroy($objDest);
imagedestroy($objSource); imagedestroy($objSource);
} }
// SI image ok, on balance tout dans la bdd
if ($boolImageOk){ if ($boolImageOk){
if (!isset($_GET['id'])){ if (!isset($_GET['id'])){
$objProject->setUser_id($_SESSION['user']['user_id']); $objProject->setUser_id($_SESSION['user']['user_id']);
@ -244,21 +243,28 @@
$boolOk = $objProjectModel->updateProject($objProject); $boolOk = $objProjectModel->updateProject($objProject);
} }
// Gestion des 20 Images après l'envoie de la Thumbnail en BDD
if ($boolOk){ if ($boolOk){
//Si pas d'erreur
if (isset($_FILES['imageProject']) && $_FILES['imageProject']['error'][0] != 4) { if (isset($_FILES['imageProject']) && $_FILES['imageProject']['error'][0] != 4) {
$files = $_FILES['imageProject']; $files = $_FILES['imageProject'];
$maxPhotos = 20; $maxPhotos = 20;
// 1. On compte combien d'images le projet possède déjà en BDD
$currentImages = $objProjectModel->getImagesByProjectId($objProject->getId()); $currentImages = $objProjectModel->getImagesByProjectId($objProject->getId());
$totalExisting = count($currentImages); $totalExisting = count($currentImages);
// 2. On calcule combien de photos on peut encore ajouter
$remainingSlots = $maxPhotos - $totalExisting; $remainingSlots = $maxPhotos - $totalExisting;
// Si on a déjà atteint ou dépassé la limite, on ne traite même pas les fichiers
if ($remainingSlots <= 0) { if ($remainingSlots <= 0) {
$_SESSION['error'] = "Limite de $maxPhotos photos atteinte. Supprimez-en pour en ajouter de nouvelles."; $_SESSION['error'] = "Limite de $maxPhotos photos atteinte. Supprimez-en pour en ajouter de nouvelles.";
} else { } else {
$uploadedCount = 0; $uploadedCount = 0;
foreach ($files['name'] as $key => $name) { foreach ($files['name'] as $key => $name) {
// 3. On utilise le quota restant comme condition d'arrêt
if ($uploadedCount >= $remainingSlots) break; if ($uploadedCount >= $remainingSlots) break;
if ($files['error'][$key] === 0 && in_array($files['type'][$key], $arrTypeAllowed)) { if ($files['error'][$key] === 0 && in_array($files['type'][$key], $arrTypeAllowed)) {
@ -267,8 +273,10 @@
$strDestGallery = $_ENV['IMG_PROJECT_PATH'].$galleryName; $strDestGallery = $_ENV['IMG_PROJECT_PATH'].$galleryName;
$strSourceGallery = $files['tmp_name'][$key]; $strSourceGallery = $files['tmp_name'][$key];
// Reprise de la logique de redimensionnement
list($intW, $intH) = getimagesize($strSourceGallery); list($intW, $intH) = getimagesize($strSourceGallery);
// On peux changer ces dimensions si on veux que la galerie soit plus grande/petite
$intDestW = 150; $intDestH = 150; $intDestW = 150; $intDestH = 150;
$fltDestR = $intDestW / $intDestH; $fltDestR = $intDestW / $intDestH;
$fltSourceR = $intW / $intH; $fltSourceR = $intW / $intH;
@ -286,7 +294,8 @@
} }
$objDestGallery = imagecreatetruecolor($intDestW, $intDestH); $objDestGallery = imagecreatetruecolor($intDestW, $intDestH);
// Création de la source selon le type de chaque image de la boucle
switch ($files['type'][$key]) { switch ($files['type'][$key]) {
case 'image/jpeg' : case 'image/jpeg' :
$objSourceGallery = imagecreatefromjpeg($strSourceGallery); $objSourceGallery = imagecreatefromjpeg($strSourceGallery);
@ -303,6 +312,7 @@
imagecopyresampled($objDestGallery, $objSourceGallery, 0, 0, $intCropX, $intCropY, $intDestW, $intDestH, $intCropW, $intCropH); imagecopyresampled($objDestGallery, $objSourceGallery, 0, 0, $intCropX, $intCropY, $intDestW, $intDestH, $intCropW, $intCropH);
if (imagewebp($objDestGallery, $strDestGallery)) { if (imagewebp($objDestGallery, $strDestGallery)) {
// Insertion en BDD
$objProjectModel->addImageInProject($galleryName, $objProject->getId()); $objProjectModel->addImageInProject($galleryName, $objProject->getId());
$uploadedCount++; $uploadedCount++;
} }
@ -319,6 +329,7 @@
} }
} }
// Suppression de l'ancienne miniature
if(isset($strOldImg) && !empty($strOldImg) && isset($strImageName)){ if(isset($strOldImg) && !empty($strOldImg) && isset($strImageName)){
$strOldFile = $_ENV['IMG_PROJECT_PATH'].$strOldImg; $strOldFile = $_ENV['IMG_PROJECT_PATH'].$strOldImg;
if (file_exists($strOldFile)) unlink($strOldFile); if (file_exists($strOldFile)) unlink($strOldFile);
@ -336,23 +347,26 @@
} }
} }
// Données pour la vue
$this->_arrData['arrCategory'] = $objCategoryModel->findAllCategory(); $this->_arrData['arrCategory'] = $objCategoryModel->findAllCategory();
$this->_arrData['objProject'] = $objProject; $this->_arrData['objProject'] = $objProject;
$this->_arrData['arrError'] = $arrError; $this->_arrData['arrError'] = $arrError;
// Si on est en modifications de projet, on récupère les images pour les afficher dans le formulaire
if ($objProject->getId()) { if ($objProject->getId()) {
// On récupère les images via le modèle et on les stocke dans le tableau de données
$this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId()); $this->_arrData['arrImages'] = $objProjectModel->getImagesByProjectId($objProject->getId());
} else { } else {
// Sinon on initialise un tableau vide pour éviter que Smarty ne râle
$this->_arrData['arrImages'] = []; $this->_arrData['arrImages'] = [];
} }
$this->_display('addedit_project'); $this->_display('addedit_project');
} }
/** /**
* Fonction d'affichage d'un projet * Fonction d'affichage de projet
*/ */
public function display() { public function display() {
$intId = $_GET['id'] ?? null; $intId = $_GET['id'] ?? null;
@ -360,13 +374,13 @@
$objProjectModel = new ProjectModel(); $objProjectModel = new ProjectModel();
$arrProject = $objProjectModel->findOne((int)$intId); $arrProject = $objProjectModel->findOne((int)$intId);
// CORRECTION ICI : on utilise $intId (pas $id)
$arrImages = $objProjectModel->getImagesByProjectId((int)$intId); $arrImages = $objProjectModel->getImagesByProjectId((int)$intId);
if ($arrProject) { if ($arrProject) {
$objProject = new Project(); $objProject = new Project();
$objProject->hydrate($arrProject); $objProject->hydrate($arrProject);
$this->_arrData["arrProject"] = $arrProject;
$this->_arrData["objProject"] = $objProject; $this->_arrData["objProject"] = $objProject;
$this->_arrData["arrImages"] = $arrImages; $this->_arrData["arrImages"] = $arrImages;
@ -382,12 +396,12 @@
} }
} }
/** /**
* Fonction d'envoi d'email * Fonction de partage de projet
*/ */
public function sendEmail(){ public function shareProject(){
if (count($_POST) > 0) { if (count($_POST) > 0)
{
$projectId = (int)($_POST['project_id'] ?? 0); $projectId = (int)($_POST['project_id'] ?? 0);
$toEmail = trim($_POST['to_email'] ?? ''); $toEmail = trim($_POST['to_email'] ?? '');
@ -415,6 +429,8 @@
$objMail->Username = 'a2a67e001@smtp-brevo.com'; $objMail->Username = 'a2a67e001@smtp-brevo.com';
$objMail->Password = 'xsmtpsib-f2af87e12d3db6f1b99802a92c1acda32d45fc32a8446eeed7e49ec91c4ec7ef-AX8Y7YkRWYSmKHwS'; $objMail->Password = 'xsmtpsib-f2af87e12d3db6f1b99802a92c1acda32d45fc32a8446eeed7e49ec91c4ec7ef-AX8Y7YkRWYSmKHwS';
// Désactive la vérification du certificat SSL
// Cela permet d'éviter les erreurs liées au certificat, mais réduit la sécurité de la connexion.
$objMail->SMTPOptions = [ $objMail->SMTPOptions = [
'ssl' => [ 'ssl' => [
'verify_peer' => false, 'verify_peer' => false,
@ -451,72 +467,76 @@
/** /**
* Fonction de modération de projet = accepté * Fonction de modération de projet = accepté
* @author Guillaume
*/ */
public function accept(){ public function accept(){
//Récupéré l'id dans l'url
$intId = $_GET['id']; $intId = $_GET['id'];
//Je créer un nouveau model pour exec la commande SQL
$objProjectModel = new ProjectModel; $objProjectModel = new ProjectModel;
$objProjectModel->accept($intId); $objProjectModel->accept($intId);
//Redirection vers la page
header("Location: index.php"); header("Location: index.php");
exit; exit;
} }
/** /**
* Fonction de modération de projet = refusé * Fonction de modération de projet = refusé
* @author Guillaume
*/ */
public function refuse(){ public function refuse(){
//Récupéré l'id dans l'url
$intId = $_GET['id']; $intId = $_GET['id'];
//Je créer un nouveau model pour exec la commande SQL
$objProjectModel = new ProjectModel; $objProjectModel = new ProjectModel;
$objProjectModel->refuse($intId); $objProjectModel->refuse($intId);
//Redirection vers la page
header("Location: index.php"); header("Location: index.php");
exit; exit;
} }
/** /**
* Fonction de suppression de projet * Fonction de suppression de projet
* @author Guillaume
*/ */
public function delete(){ public function delete(){
if (!isset($_SESSION['user']) || $_SESSION['user']['user_status'] != 2) { //Récupéré l'id dans l'url
header("Location: index.php"); $intId = $_GET['id'];
exit;
}
$intId = $_GET['id'] ?? null;
if ($intId) { //Je créer un nouveau model pour exec la commande SQL
$objProjectModel = new ProjectModel(); $objProjectModel = new ProjectModel;
if ($objProjectModel->delete_soft_project((int) $intId)) { $objProjectModel->delete($intId);
$_SESSION['success'] = "Le projet a été archivé avec succès.";
} else {
$_SESSION['error'] = "Une erreur est survenue lors de l'archivage.";
}
}
//Redirection vers la page
header("Location: index.php"); header("Location: index.php");
exit; exit;
} }
/** /**
* Fonction de changement de statut (Approuvé, Refusé, En attente) * Fonction de changement de statut (Approuvé, Refusé, En attente)
* @author Guillaume
*/ */
public function change_image_status() { public function change_image_status() {
if (isset($_GET['id_img']) && isset($_GET['status'])) { if (isset($_GET['id_img']) && isset($_GET['status'])) {
$idImg = (int)$_GET['id_img']; $idImg = (int)$_GET['id_img'];
$status = $_GET['status']; $status = $_GET['status']; // "en_attente" passage à "approuvé"
$objProjectModel = new ProjectModel(); $objProjectModel = new ProjectModel();
// On passe le statut texte directement à ta méthode de modèle
if ($objProjectModel->updateImageStatus($idImg, $status)) { if ($objProjectModel->updateImageStatus($idImg, $status)) {
$_SESSION['success'] = "Le statut de l'image est désormais : " . ucfirst($status); $_SESSION['success'] = "Le statut de l'image est désormais : " . ucfirst($status);
} }
} }
// La redirection : Si on sait d'où on vient, on y retourne, sinon index
$urlRedirect = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : "index.php"; $urlRedirect = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : "index.php";
header("Location: " . $urlRedirect); header("Location: " . $urlRedirect);
exit; exit;
@ -525,12 +545,14 @@
/** /**
* Fonction de validation de l'image de projet * Fonction de validation de l'image de projet
* @author Guillaume
*/ */
public function delete_image() { public function delete_image() {
// Vérifier l'id de l'image
$idImg = $_GET['id_img']; $idImg = $_GET['id_img'];
$objProjectModel = new ProjectModel(); $objProjectModel = new ProjectModel();
// Récupérer le nom du fichier pour le supprimer physiquement
$image = $objProjectModel->findImage($idImg); $image = $objProjectModel->findImage($idImg);
if ($image) { if ($image) {
$filePath = $_ENV['IMG_PROJECT_PATH'] . $image['image_name']; $filePath = $_ENV['IMG_PROJECT_PATH'] . $image['image_name'];
@ -540,10 +562,70 @@
$_SESSION['success'] = "Image supprimée !"; $_SESSION['success'] = "Image supprimée !";
} }
// La redirection : Si on sait d'où on vient, on y retourne, sinon index
$url = (isset($_SERVER['HTTP_REFERER'])) ? $_SERVER['HTTP_REFERER'] : "index.php"; $url = (isset($_SERVER['HTTP_REFERER'])) ? $_SERVER['HTTP_REFERER'] : "index.php";
header("Location: " . $url); header("Location: " . $url);
exit; exit;
} }
/**
* Fonction d'ajout des 20 images max du projet
* @author Guillaume
* @param string $fileName = le nom de l'image, int $projectId = L'Id du projet que l'on veut afficher, string $alt = qui affichera pars défaut "Image de projet"
* @return bool Est-ce que la requête s'est bien passée
*/
public function addImageInProject(string $fileName, int $projectId, string $alt = "Image de projet"): bool {
$strRq = "INSERT INTO image (
image_name,
image_alt,
image_status,
image_project
)
VALUES (:name, :alt, :status, :project)";
$rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(":name", $fileName, PDO::PARAM_STR);
$rqPrep->bindValue(":alt", $alt, PDO::PARAM_STR);
$rqPrep->bindValue(":status", "en_attente", PDO::PARAM_STR); // Valeur string en brute
$rqPrep->bindValue(":project", $projectId, PDO::PARAM_INT);
return $rqPrep->execute();
}
/**
* Fonction d'affichage des 20 images max du projet
* @author Guillaume
* @param array $ProjectId L'Id du projet que l'on veut afficher
* @return bool Est-ce que la requête s'est bien passée
*/
public function getImagesByProjectId(int $projectId): array {
$strRq = "SELECT image_id, image_name, image_alt, image_status
FROM image
WHERE image_project = :id";
$rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(":id", $projectId, PDO::PARAM_INT);
$rqPrep->execute();
return $rqPrep->fetchAll(PDO::FETCH_ASSOC);
}
/**
* Page mentions légales
*/
public function mentions(){
// Afficher
$this->_display("mentions");
}
/**
* Page à propos
*/
public function about(){
// Afficher
$this->_display("about");
}
} }

View file

@ -1,29 +1,22 @@
<?php <?php
namespace Controllers; require("models/user_model.php");
require("entities/user_entity.php");
use Models\UserModel; require("mother_controller.php");
use Models\ProjectModel; require("./models/project_model.php");
require("./entities/project_entity.php");
use Entities\User;
use Entities\Project;
/**
* Le controller de la page d'aide utilisateur
* @author Guillaume & Besnik & Yasser
*/
class UserCtrl extends MotherCtrl { class UserCtrl extends MotherCtrl {
/**
* Page Login
*/
public function login(){ public function login(){
$strMail = $_POST['user_mail']??""; $strMail = $_POST['user_mail']??"";
$strPwd = $_POST['user_password']??""; $strPwd = $_POST['user_password']??"";
// Tester le formulaire
$arrError = []; $arrError = [];
if (count($_POST) > 0) { if (count($_POST) > 0) {
// Vérifier le formulaire
if ($strMail == ""){ if ($strMail == ""){
$arrError['mail'] = "Le mail est obligatoire"; $arrError['mail'] = "Le mail est obligatoire";
} }
@ -31,12 +24,16 @@ class UserCtrl extends MotherCtrl {
$arrError['pwd'] = "Le mot de passe est obligatoire"; $arrError['pwd'] = "Le mot de passe est obligatoire";
} }
// Si le formulaire est rempli correctement
if (count($arrError) == 0){ if (count($arrError) == 0){
// Vérifier l'utilisateur en BDD
$objUserModel = new UserModel; $objUserModel = new UserModel;
$arrResult = $objUserModel->verifUser($strMail, $strPwd); $arrResult = $objUserModel->verifUser($strMail, $strPwd);
if ($arrResult === false){ //var_dump($arrResult);
if ($arrResult === false){ // Si la base de données ne renvoie rien
$arrError[] = "Mail ou mot de passe invalide"; $arrError[] = "Mail ou mot de passe invalide";
}else{ }else{
// Ajoute l'utilisateur en session
$_SESSION['user'] = $arrResult; $_SESSION['user'] = $arrResult;
$_SESSION['success'] = "Bienvenue, vous êtes bien connecté"; $_SESSION['success'] = "Bienvenue, vous êtes bien connecté";
if (isset($_POST['remember_me'])) { if (isset($_POST['remember_me'])) {
@ -58,9 +55,7 @@ class UserCtrl extends MotherCtrl {
} }
/**
* Fonction pour ce déconnecter
*/
public function logout(){ public function logout(){
if (isset($_COOKIE['remember_me'])) { if (isset($_COOKIE['remember_me'])) {
@ -79,30 +74,42 @@ class UserCtrl extends MotherCtrl {
exit; exit;
} }
/** /**
* Fonction d'inscription d'un utilisateur * Fonction d'inscription d'un utilisateur
* Effectue les validations du formulaire, * Effectue les validations du formulaire,
* vérifie l'unicité du mail et du pseudo, puis insère l'utilisateur en base de données * vérifie l'unicité du mail et du pseudo,
* puis insère l'utilisateur en base de données
* @return void * @return void
*/ */
public function signup(){ public function signup(){
// Entité pour réafficher les valeurs dans le formulaire
$objUser = new User(); $objUser = new User();
// Récupération des champs
$strPwdConfirm = $_POST['pwd_confirm'] ?? ""; $strPwdConfirm = $_POST['pwd_confirm'] ?? "";
// Tableau d'erreurs
$arrError = []; $arrError = [];
// Traitement du formulaire uniquement si POST
if (!empty($_POST)) { if (!empty($_POST)) {
// Hydratation
$objUser->setName($_POST['user_name'] ?? ""); $objUser->setName($_POST['user_name'] ?? "");
$objUser->setFirstname($_POST['user_firstname'] ?? ""); $objUser->setFirstname($_POST['user_firstname'] ?? "");
$objUser->setMail($_POST['user_mail'] ?? ""); $objUser->setMail($_POST['user_mail'] ?? "");
$objUser->setPseudo($_POST['user_pseudo'] ?? ""); $objUser->setPseudo($_POST['user_pseudo'] ?? "");
$objUser->setPwd($_POST['user_password'] ?? ""); $objUser->setPwd($_POST['user_password'] ?? "");
// Champs optionnels : on les stocke aussi même si ils sont vides
$objUser->setPhone($_POST['user_phone'] ?? ""); $objUser->setPhone($_POST['user_phone'] ?? "");
$objUser->setWork($_POST['user_work'] ?? ""); $objUser->setWork($_POST['user_work'] ?? "");
$objUser->setLocation($_POST['user_location'] ?? ""); $objUser->setLocation($_POST['user_location'] ?? "");
$objUser->setDescription($_POST['user_description'] ?? ""); $objUser->setDescription($_POST['user_description'] ?? "");
// --- VALIDATIONS (obligatoires) ---
if (trim($objUser->getName()) === "") { if (trim($objUser->getName()) === "") {
$arrError['user_name'] = "Le nom est obligatoire"; $arrError['user_name'] = "Le nom est obligatoire";
} }
@ -130,14 +137,21 @@ class UserCtrl extends MotherCtrl {
$arrError['pwd_confirm'] = "La confirmation du mot de passe ne correspond pas"; $arrError['pwd_confirm'] = "La confirmation du mot de passe ne correspond pas";
} }
// Si pas d'erreurs => insertion
if (count($arrError) === 0) { if (count($arrError) === 0) {
$objUserModel = new UserModel(); $objUserModel = new UserModel();
// Vérif mail
if ($objUserModel->mailExists($objUser->getMail())) { if ($objUserModel->mailExists($objUser->getMail())) {
$arrError['user_mail'] = "Impossible de créer le compte avec ces informations"; $arrError['user_mail'] = "Impossible de créer le compte avec ces informations";
} }
// Vérif pseudo
if ($objUserModel->pseudoExists($objUser->getPseudo())) { if ($objUserModel->pseudoExists($objUser->getPseudo())) {
$arrError['user_pseudo'] = "Ce pseudo existe déjà"; $arrError['user_pseudo'] = "Ce pseudo existe déjà";
} }
// Si aucune erreur => insert
if (count($arrError) === 0) { if (count($arrError) === 0) {
$boolInsert = $objUserModel->insert($objUser); $boolInsert = $objUserModel->insert($objUser);
@ -152,17 +166,37 @@ class UserCtrl extends MotherCtrl {
} }
} }
// Affichage de la vue inscription
$this->_arrData['objUser'] = $objUser; $this->_arrData['objUser'] = $objUser;
$this->_arrData['arrError'] = $arrError; $this->_arrData['arrError'] = $arrError;
$this->_display("signup"); $this->_display("signup");
} }
/** /**
* le controlleur affichage de la page user * le controlleur affichage de la page user
*/ */
public function user(){ public function user(){
/**$intId = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if ($intId <= 0) {
header("Location: index.php");
exit;
}
//affichage info utilisateur
$objUserModel = new UserModel;
$arrUserData = $objUserModel->findUserById($intId);
if ($arrUserData === false) {
header("Location: index.php");
exit;
}*/
$strPseudo = $_GET['pseudo']??''; $strPseudo = $_GET['pseudo']??'';
$objUserModel = new UserModel; $objUserModel = new UserModel;
@ -175,6 +209,8 @@ class UserCtrl extends MotherCtrl {
$objUser = new User; $objUser = new User;
$objUser->hydrate($arrUserData); $objUser->hydrate($arrUserData);
//affichage projet de l'utilisateur
$objProjectModel = new ProjectModel; $objProjectModel = new ProjectModel;
$arrProjects = $objProjectModel->findAll(0,'',$objUser->getId()); $arrProjects = $objProjectModel->findAll(0,'',$objUser->getId());
@ -190,14 +226,12 @@ class UserCtrl extends MotherCtrl {
$this->_display("user"); $this->_display("user");
} }
/**
* le controlleur de la modification d'un user
*/
public function edit(){ public function edit(){
if(!isset($_SESSION['user'])){ if(!isset($_SESSION['user'])){
header("Location: index.php"); header("Location: index.php");
exit; exit;
} }
$objUserModel = new UserModel; $objUserModel = new UserModel;
$arrError = []; $arrError = [];
$objUser = new User; $objUser = new User;
@ -214,6 +248,7 @@ class UserCtrl extends MotherCtrl {
$objUser->hydrate($_POST); $objUser->hydrate($_POST);
$objUser->setId($_SESSION['user']['user_id']); $objUser->setId($_SESSION['user']['user_id']);
// Vérification de l'image
$arrTypeAllowed = array('image/jpeg', 'image/png', 'image/webp'); $arrTypeAllowed = array('image/jpeg', 'image/png', 'image/webp');
$boolImageOk = true; $boolImageOk = true;
@ -244,6 +279,7 @@ class UserCtrl extends MotherCtrl {
} }
} }
// Traitement de l'image si pas d'erreur
if (count($arrError) == 0 && isset($strImageName)) { if (count($arrError) == 0 && isset($strImageName)) {
$strDest = $_ENV['IMG_USER_PATH'] . $strImageName; $strDest = $_ENV['IMG_USER_PATH'] . $strImageName;
$strSource = $_FILES['image']['tmp_name']; $strSource = $_FILES['image']['tmp_name'];

View file

View file

@ -1,253 +0,0 @@
CREATE DATABASE IF NOT EXISTS `projet_folliow`
DEFAULT CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
USE `projet_folliow`;
/*M!999999\- enable the sandbox mode */
-- MariaDB dump 10.19 Distrib 10.11.14-MariaDB, for debian-linux-gnu (x86_64)
--
-- Host: localhost Database: projet_folliow
-- ------------------------------------------------------
-- Server version 10.11.14-MariaDB-0+deb12u2
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `authorisation`
--
DROP TABLE IF EXISTS `authorisation`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `authorisation` (
`authorisation_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifiant unique des autorisations',
`authorisation_name` varchar(30) NOT NULL COMMENT 'Administrateur, modérateur, utilisateur',
PRIMARY KEY (`authorisation_id`),
UNIQUE KEY `uk_authorisation_name` (`authorisation_name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `authorisation`
--
LOCK TABLES `authorisation` WRITE;
/*!40000 ALTER TABLE `authorisation` DISABLE KEYS */;
INSERT INTO `authorisation` VALUES
(1,'Administrateur'),
(2,'Modérateur'),
(3,'Utilisateur');
/*!40000 ALTER TABLE `authorisation` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `category`
--
DROP TABLE IF EXISTS `category`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `category` (
`category_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifiant unique des catégorie du projet',
`category_name` varchar(150) NOT NULL COMMENT 'Nom de chaque catégorie',
`category_parent` int(10) unsigned DEFAULT NULL COMMENT 'ID de la catégorie parente (NULL = catégorie principale)',
PRIMARY KEY (`category_id`),
UNIQUE KEY `uk_category_name_parent` (`category_name`,`category_parent`),
KEY `fk_category_parent` (`category_parent`),
CONSTRAINT `fk_category_parent` FOREIGN KEY (`category_parent`) REFERENCES `category` (`category_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=54 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `category`
--
LOCK TABLES `category` WRITE;
/*!40000 ALTER TABLE `category` DISABLE KEYS */;
INSERT INTO `category` VALUES
(32,'3D',4),
(34,'Aquarelle',4),
(5,'Architecture',NULL),
(36,'Architecture d\'Intérieur',5),
(35,'Architecture Moderne',5),
(24,'Backend',2),
(33,'Bande Dessinée',4),
(1,'Design',NULL),
(2,'Développement Web',NULL),
(31,'Digital Art',4),
(30,'Événementiel',3),
(23,'Frontend',2),
(25,'Full-Stack',2),
(4,'Illustration',NULL),
(20,'Logo & Identité Visuelle',1),
(39,'Marketing',NULL),
(46,'Marketing',NULL),
(26,'Mobile',2),
(21,'Motion Design',1),
(38,'Patrimoine',5),
(28,'Paysage',3),
(3,'Photographie',NULL),
(27,'Portrait',3),
(22,'Print Design',1),
(40,'Rédaction',NULL),
(47,'Rédaction',NULL),
(29,'Sport',3),
(19,'UI/UX Design',1),
(37,'Urbanisme',5),
(41,'Vidéo',NULL),
(48,'Vidéo',NULL);
/*!40000 ALTER TABLE `category` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `image`
--
DROP TABLE IF EXISTS `image`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `image` (
`image_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'identifiant unique des images',
`image_name` varchar(150) NOT NULL COMMENT 'Chemin de l''image enregistrée',
`image_alt` varchar(255) DEFAULT NULL COMMENT 'Alt de l''image',
`image_status` varchar(50) NOT NULL DEFAULT 'en_attente' COMMENT 'Statut de modération de l''image',
`image_project` int(10) unsigned DEFAULT NULL COMMENT 'Identifiant du projet où se trouve l''image',
PRIMARY KEY (`image_id`),
KEY `fk_image_project` (`image_project`),
CONSTRAINT `fk_image_project` FOREIGN KEY (`image_project`) REFERENCES `project` (`project_id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `chk_image_status` CHECK (`image_status` in ('en_attente','approuvé','rejeté'))
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `image`
--
LOCK TABLES `image` WRITE;
/*!40000 ALTER TABLE `image` DISABLE KEYS */;
INSERT INTO `image` VALUES
(1,'/uploads/projects/ecommerce-01.jpg','Page d\'accueil du site e-commerce refondu','approuvé',1),
(2,'/uploads/projects/ecommerce-02.jpg','Interface mobile du processus de commande','approuvé',1),
(3,'/uploads/projects/taskmanager-01.jpg','Vue kanban de l\'application','approuvé',2),
(4,'/uploads/projects/urban-01.jpg','Architecture moderne à La Défense','en_attente',3);
/*!40000 ALTER TABLE `image` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `project`
--
DROP TABLE IF EXISTS `project`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `project` (
`project_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifiant unique du projet',
`project_title` varchar(150) NOT NULL COMMENT 'Titre du projet',
`project_description` text DEFAULT NULL COMMENT 'Description du projet',
`project_thumbnail` varchar(150) DEFAULT NULL COMMENT 'Image miniature du projet',
`project_content` text DEFAULT NULL COMMENT 'Contenu du projet',
`project_creation_date` date NOT NULL COMMENT 'Date de création du projet',
`project_status` varchar(30) NOT NULL DEFAULT 'brouillon' COMMENT 'Statut du projet : brouillon, publié, en_attente',
`project_user` int(10) unsigned DEFAULT NULL COMMENT 'Identifiant de l''user',
`project_category` int(10) unsigned DEFAULT NULL COMMENT 'Identifiant de la catégorie',
PRIMARY KEY (`project_id`),
KEY `fk_project_user` (`project_user`),
KEY `fk_project_category` (`project_category`),
KEY `idx_project_status` (`project_status`),
KEY `idx_project_creation_date` (`project_creation_date`),
CONSTRAINT `fk_project_category`
FOREIGN KEY (`project_category`)
REFERENCES `category` (`category_id`)
ON DELETE SET NULL
ON UPDATE CASCADE,
CONSTRAINT `fk_project_user`
FOREIGN KEY (`project_user`)
REFERENCES `users` (`user_id`)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `project`
--
LOCK TABLES `project` WRITE;
/*!40000 ALTER TABLE `project` DISABLE KEYS */;
INSERT INTO `project` VALUES
(1,'Refonte du site e-commerce','Refonte complète de l\'interface utilisateur d\'une boutique en ligne avec focus sur l\'expérience mobile','/uploads/projects/ecommerce-thumb.jpg','Ce projet visait à moderniser entièrement l\'interface d\'un site e-commerce existant. Les principales améliorations incluent une navigation simplifiée, un processus de commande optimisé et une interface responsive.','2025-12-01','publié',1,1),
(2,'Application de gestion de tâches','Développement d\'une application web pour la gestion collaborative de projets','/uploads/projects/taskmanager-thumb.jpg','Application web développée en React et Node.js permettant aux équipes de gérer leurs projets de manière collaborative. Fonctionnalités : kanban, calendrier, notifications en temps réel.','2025-12-15','publié',2,2),
(3,'Série photo urbaine','Collection de photographies capturant l\'architecture moderne de Paris','/uploads/projects/urban-thumb.jpg','Série de 30 photographies prises dans différents quartiers de Paris, mettant en valeur le contraste entre architecture classique et moderne. Travail sur la lumière naturelle et les perspectives.','2026-01-05','en_attente',3,3);
/*!40000 ALTER TABLE `project` ENABLE KEYS */;
UNLOCK TABLES;
--
-- Table structure for table `users`
--
DROP TABLE IF EXISTS `users`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8mb4 */;
CREATE TABLE `users` (
`user_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Identifiant unique de l''utilisateur',
`user_name` varchar(100) NOT NULL COMMENT 'Nom de l''utilisateur',
`user_firstname` varchar(100) NOT NULL COMMENT 'Prénom de l''utilisateur',
`user_pseudo` varchar(30) NOT NULL COMMENT 'Pseudo de l''utilisateur',
`user_image` varchar(150) DEFAULT NULL COMMENT 'Photo de profil de l''utilisateur',
`user_mail` varchar(100) NOT NULL COMMENT 'Mail de l''utilisateur',
`user_password` varchar(255) NOT NULL COMMENT 'Mot de passe de l''utilisateur',
`user_phone` varchar(20) DEFAULT NULL COMMENT 'Téléphone de l''utilisateur',
`user_work` varchar(50) DEFAULT NULL COMMENT 'Profession de l''utilisateur',
`user_birth` date DEFAULT NULL COMMENT 'Date de naissance de l''utilisateur',
`user_location` varchar(150) DEFAULT NULL COMMENT 'Localisation de l''utilisateur',
`user_description` varchar(255) DEFAULT NULL COMMENT 'Phrase d''accroche de l''utilisateur',
`user_account_creation` datetime NOT NULL DEFAULT current_timestamp() COMMENT 'Date et heure de création du compte',
`user_status` int(10) unsigned DEFAULT NULL COMMENT 'identifiant de niveau d''autorisation',
PRIMARY KEY (`user_id`),
UNIQUE KEY `uk_user_mail` (`user_mail`),
UNIQUE KEY `uk_user_pseudo` (`user_pseudo`),
KEY `fk_users_authorisation` (`user_status`),
KEY `idx_user_mail` (`user_mail`),
CONSTRAINT `fk_users_authorisation` FOREIGN KEY (`user_status`) REFERENCES `authorisation` (`authorisation_id`) ON DELETE SET NULL ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `users`
--
LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;
INSERT INTO `users` VALUES
(1,'Dupont','Marie','marie_design','/uploads/users/marie.jpg','marie.dupont@example.com','$2y$10$T5kWRD3NBqXKWtQqrBG3We1Qpq2Odum0/xYAoT2SaCclG7h2Y0Gvq','0612345678','Designer UI/UX','1995-03-15','Paris, France','Passionnée de design et d\'expérience utilisateur','2024-01-15 10:30:00',1),
(2,'Martin','Thomas','thomas_dev','/uploads/users/thomas.jpg','thomas.martin@example.com','$2y$10$T5kWRD3NBqXKWtQqrBG3We1Qpq2Odum0/xYAoT2SaCclG7h2Y0Gvq','0623456789','Développeur Full-Stack','1992-07-22','Lyon, France','Créateur d\'applications web modernes','2024-02-20 14:45:00',2),
(3,'Dubois','Sophie','sophie_photo','/uploads/users/sophie.jpg','sophie.dubois@example.com','$2y$10$T5kWRD3NBqXKWtQqrBG3We1Qpq2Odum0/xYAoT2SaCclG7h2Y0Gvq','0634567890','Photographe','1998-11-08','Marseille, France','Capturer l\'instant présent est ma passion','2024-03-10 09:15:00',3);
/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2026-01-09 17:33:08

View file

@ -1,53 +0,0 @@
<?php
namespace Entities;
/**
* Classe d'un objet Authorisation
* @author Laura
*/
class Authorisation extends Mother{
private int $_id;
private string $_name = '';
/**
* le constructeur de la table authorisation
*/
public function __construct(){
$this->_prefix = 'authorisation_';
}
/**
* Récuperation de l'id du statut d'un utilisateur
* @return int l'id du statut
*/
public function getId():int{
return $this->_id;
}
/**
* Mise à jour de l'id du statut d'un utilisateur
* @param int le nouvelle id du statut
*/
public function setId(int $id){
$this->_id = $id;
}
/**
* Récuperation de l'intitulé du statut d'un utilisateur
* @return string l'intitulé du statut
*/
public function getName():string{
return $this->_name;
}
/**
* Mise à jour de l'intitulé du statut d'un utilisateur
* @return string le nouvel intitulé du statut
*/
public function setName(string $name){
$this->_name = $name;
}
}

View file

@ -1,263 +0,0 @@
<?php
namespace Entities;
/**
* Classe d'un objet User
* @author Besnik & Laura
*/
class User extends Mother{
private int $_id;
private string $_name = '';
private string $_firstname = '';
private string $_pseudo = '';
private ?string $_image = null;
private string $_mail = '';
private string $_pwd;
private string $_phone = '';
private string $_work = '';
private ?string $_birth = null;
private string $_location = '';
private string $_description = '';
private string $_account_creation = '';
private int $_status;
/**
* le constructeur de la table user
*/
public function __construct(){
$this->_prefix = 'user_';
}
/**
* Récuperation de l'id d'un utilisateur
* @return int l'id de l'utilisateur
*/
public function getId():int{
return $this->_id;
}
/**
* Mise à jour de l'id d'un utilisateur
* @param int le nouvelle id de l'utilisateur
*/
public function setId(int $id){
$this->_id = $id;
}
/**
* Récuperation du nom d'un utilisateur
* @return string le nom de l'utilisateur
*/
public function getName():string{
return $this->nettoyer($this->_name);
}
/**
* Mise à jour du nom d'un utilisateur
* @return string le nouveau nom de l'utilisateur
*/
public function setName(string $name){
$this->_name = $name;
}
/**
* Récuperation du prénom d'un utilisateur
* @return string le prénom de l'utilisateur
*/
public function getFirstname():string{
return $this->nettoyer($this->_firstname);
}
/**
* Mise à jour du prénom d'un utilisateur
* @return string le nouveau prénom de l'utilisateur
*/
public function setFirstname(string $firstname){
$this->_firstname = $firstname;
}
/**
* Récuperation du pseudo unique d'un utilisateur
* @return string le pseudo de l'utilisateur
*/
public function getPseudo():string{
return $this->nettoyer($this->_pseudo);
}
/**
* Mise à jour du pseudo unique d'un utilisateur
* @return string le nouveau pseudo de l'utilisateur
*/
public function setPseudo(string $pseudo){
$this->_pseudo = $pseudo;
}
/**
* Récuperation du nom de l'image d'un utilisateur
* @return string du nom de l'image de l'utilisateur
*/
public function getImage():?string{
return $this->_image;
}
/**
* Mise à jour du nom de l'image d'un utilisateur
* @return string le nouveau nom de l'image de l'utilisateur
*/
public function setImage(?string $image){
$this->_image = $image;
}
/**
* Récuperation de l'email d'un utilisateur
* @return string l'email de l'utilisateur
*/
public function getMail():string{
return $this->_mail;
}
/**
* Mise à jour de l'email d'un utilisateur
* @return string le nouvel email de l'utilisateur
*/
public function setMail(string $mail){
$this->_mail = strtolower($mail);
}
/**
* Récuperation du mot de passe d'un utilisateur
* @return string le mot de passe de l'utilisateur
*/
public function getPwd():string{
return $this->_pwd;
}
/**
* Récuperation du mot de passe haché d'un utilisateur
* @return string le mot de passe haché de l'utilisateur
*/
public function getPwdHash():string{
return password_hash($this->_pwd, PASSWORD_DEFAULT);
}
/**
* Mise à jour du mot de passe d'un utilisateur
* @return string le nouveau mot de passe de l'utilisateur
*/
public function setPwd(string $pwd){
$this->_pwd = $pwd;
}
/**
* Récuperation du numéro de téléphone d'un utilisateur
* @return string le numéro de téléphone de l'utilisateur
*/
public function getPhone():string{
return $this->nettoyer($this->_phone);
}
/**
* Mise à jour du numéro de téléphone d'un utilisateur
* @return string le nouveau numéro de téléphone de l'utilisateur
*/
public function setPhone(string $phone){
$this->_phone = $phone;
}
/**
* Récuperation de la profession d'un utilisateur
* @return string la profession de l'utilisateur
*/
public function getWork():string{
return $this->nettoyer($this->_work);
}
/**
* Mise à jour de la profession d'un utilisateur
* @return string la nouvelle profession de l'utilisateur
*/
public function setWork(string $work){
$this->_work = $work;
}
/**
* Récuperation de la date de naissance d'un utilisateur
* @return string la date de naissance de l'utilisateur
*/
public function getBirth():?string{
return $this->_birth;
}
/**
* Mise à jour de la date de naissance d'un utilisateur
* @return string la nouvelle date de naissance de l'utilisateur
*/
public function setBirth(?string $birth){
$this->_birth = $birth;
}
/**
* Récuperation de la localisation d'un utilisateur
* @return string la localisation de l'utilisateur
*/
public function getLocation():string{
return $this->nettoyer($this->_location);
}
/**
* Mise à jour de la localisation d'un utilisateur
* @return string la nouvelle localisation de l'utilisateur
*/
public function setLocation(string $location){
$this->_location = $location;
}
/**
* Récuperation de la description d'un utilisateur
* @return string la description de l'utilisateur
*/
public function getDescription():string{
return $this->nettoyer($this->_description);
}
/**
* Mise à jour de la description d'un utilisateur
* @return string la nouvelle description de l'utilisateur
*/
public function setDescription(string $description){
$this->_description = $description;
}
/**
* Récuperation de la date de création d'un utilisateur
* @return string la date de création de l'utilisateur
*/
public function getAccountCreation():string{
return $this->_account_creation;
}
/**
* Mise à jour de la date de création d'un utilisateur
* @return string la nouvelle date de création de l'utilisateur
*/
public function setAccountCreation(string $account_creation){
$this->_account_creation = $account_creation;
}
/**
* Récuperation de l'id du statut d'un utilisateur
* @return int l'id du statut de l'utilisateur
*/
public function getStatus():int{
return $this->_status;
}
/**
* Mise à jour de l'id du statut d'un utilisateur
* @return int le nouvel id du statut de l'utilisateur
*/
public function setStatus(int $status){
$this->_status = $status;
}
}

View file

@ -0,0 +1,28 @@
<?php
require_once("mother_entity.php");
class Authorisation extends Entity{
private int $_id;
private string $_name = '';
public function __construct(){
$this->_prefix = 'authorisation_';
}
public function getId():int{
return $this->_id;
}
public function setId(int $id){
$this->_id = $id;
}
public function getName():string{
return $this->_name;
}
public function setName(string $name){
$this->_name = $name;
}
}

View file

@ -1,20 +1,20 @@
<?php <?php
namespace Entities; require_once("mother_entity.php");
/** /**
* Classe d'un objet Category * Classe d'un objet Projet
* @author Laura * @author Laura
*/ */
class Category extends Mother{ class Category extends Entity{
private ?int $_id = null; private ?int $_id = null;
protected string $_name = ''; protected string $_name = '';
protected ?int $_parent = null; protected ?int $_parent = null;
/** /**
* le constructeur de la table category * Constructeur (j'ai toujours pas compris à quoi ça sert)
*/ */
public function __construct(){ public function __construct(){
$this->_prefix = 'category_'; $this->_prefix = 'category_';

View file

@ -1,13 +1,13 @@
<?php <?php
namespace Entities; require_once("mother_entity.php");
/** /**
* Classe d'un objet Projet * Classe d'un objet Projet
* @author Laura * @author Laura
*/ */
class Image extends Mother{ class Image extends Entity{
private int $_id; private int $_id;
private string $_name = ''; private string $_name = '';
@ -16,9 +16,8 @@ class Image extends Mother{
private int $_project = 0; private int $_project = 0;
/**
* le constructeur de la table image //le construc habituel
*/
public function __construct(){ public function __construct(){
$this->_prefix = 'image_'; $this->_prefix = 'image_';
} }

View file

@ -1,13 +1,11 @@
<?php <?php
namespace Entities;
/** /**
* Classe d'un Mere de tout objet * Classe d'un Mere de tout objet
* @author Yass & Laura * @author Yass & Laura
*/ */
class Mother{ class Entity{
protected string $_prefix = ''; protected string $_prefix = '';

View file

@ -1,32 +1,27 @@
<?php <?php
namespace Entities; require_once("mother_entity.php");
use \DateTime;
use \IntlDateFormatter;
/** /**
* Classe d'un objet Projet * Classe d'un objet Projet
* @author Yass * @author Yass
*/ */
class Project extends Mother{ class Project extends Entity{
private ?int $_id = null; private ?int $_id = null;
private string $_title = ""; private string $_title = "";
private string $_description = ""; private string $_description = "";
private ?string $_thumbnail = null; private ?string $_thumbnail = null;
private string $_content = ""; private string $_content = "";
private string $_creation_date; private string $_creation_date;
private string $_status = "en_attente"; private string $_status = "en_attente";
private int $_user; private int $_user;
private int $_category = 0; private int $_category = 0;
private string $_creatorname; private string $_creatorname;
private ?string $_user_image = null; private ?string $_user_image = null;
private ?string $_project_deleted_at = null;
/** /**
* le constructeur de la table project * Constructeur (logique mdrr)
*/ */
public function __construct(){ public function __construct(){
$this->_prefix = 'project_'; $this->_prefix = 'project_';
@ -35,7 +30,7 @@ class Project extends Mother{
// Méthode Getter et Setter // Méthode Getter et Setter
/** /**
* Récuperation de l'id du projet * Récuperation de l'id du Projet
* @return int l'id du projet * @return int l'id du projet
*/ */
public function getId():?int{ public function getId():?int{
@ -56,7 +51,7 @@ class Project extends Mother{
* @return string tite du projet * @return string tite du projet
*/ */
public function getTitle(){ public function getTitle(){
return $this->nettoyer($this->_title); return $this->_title;
} }
/** /**
@ -72,7 +67,7 @@ class Project extends Mother{
* @return string description du projet * @return string description du projet
*/ */
public function getDescription(){ public function getDescription(){
return $this->nettoyer($this->_description) ; return $this->_description;
} }
/** /**
@ -101,16 +96,16 @@ class Project extends Mother{
} }
/** /**
* Récuperation du contenu * Récuperation du contenue
* @return string contenu du projet * @return string contenue du projet
*/ */
public function getContent(){ public function getContent(){
return $this->nettoyer($this->_content); return $this->_content;
} }
/** /**
* Mise à jour du contenu * Mise à jour du contenue
* @param string le nouveau contenu * @param string le nouveau contenue
*/ */
public function setContent($content){ public function setContent($content){
$this->_content = $content; $this->_content = $content;
@ -221,20 +216,6 @@ class Project extends Mother{
public function setUser_image($user_image){ public function setUser_image($user_image){
$this->_user_image = $user_image; $this->_user_image = $user_image;
} }
/**
* Récupération de la date du projet supprimer
* @return string date du projet
*/
public function getProject_deleted_at(){
return $this->_project_deleted_at;
}
/**
* Mise à jour de la date de suppression de projet
* @param string date du projet
*/
public function setProject_deleted_at($project_deleted_at){
$this->_project_deleted_at = $project_deleted_at;
}
} }

124
entities/user_entity.php Normal file
View file

@ -0,0 +1,124 @@
<?php
require_once("mother_entity.php");
class User extends Entity{
private int $_id;
private string $_name = '';
private string $_firstname = '';
private string $_pseudo = '';
private ?string $_image = null;
private string $_mail = '';
private string $_pwd;
private string $_phone = '';
private string $_work = '';
private ?string $_birth = null;
private string $_location = '';
private string $_description = '';
private string $_account_creation = '';
private int $_status;
public function __construct(){
$this->_prefix = 'user_';
}
public function getId():int{
return $this->_id;
}
public function setId(int $id){
$this->_id = $id;
}
public function getName():string{
return $this->_name;
}
public function setName(string $name){
$this->_name = $name;
}
public function getFirstname():string{
return $this->_firstname;
}
public function setFirstname(string $firstname){
$this->_firstname = $firstname;
}
public function getPseudo():string{
return $this->_pseudo;
}
public function setPseudo(string $pseudo){
$this->_pseudo = $pseudo;
}
public function getImage():?string{
return $this->_image;
}
public function setImage(?string $image){
$this->_image = $image;
}
public function getMail():string{
return $this->_mail;
}
public function setMail(string $mail){
$this->_mail = strtolower($mail);
}
public function getPwd():string{
return $this->_pwd;
}
public function getPwdHash():string{
return password_hash($this->_pwd, PASSWORD_DEFAULT);
}
public function setPwd(string $pwd){
$this->_pwd = $pwd;
}
public function getPhone():string{
return $this->_phone;
}
public function setPhone(string $phone){
$this->_phone = $phone;
}
public function getWork():string{
return $this->_work;
}
public function setWork(string $work){
$this->_work = $work;
}
public function getBirth():?string{
return $this->_birth;
}
public function setBirth(?string $birth){
$this->_birth = $birth;
}
public function getLocation():string{
return $this->_location;
}
public function setLocation(string $location){
$this->_location = $location;
}
public function getDescription():string{
return $this->_description;
}
public function setDescription(string $description){
$this->_description = $description;
}
public function getAccountCreation():string{
return $this->_account_creation;
}
public function setAccountCreation(string $account_creation){
$this->_account_creation = $account_creation;
}
public function getStatus():int{
return $this->_status;
}
public function setStatus(int $status){
$this->_status = $status;
}
}

View file

@ -1,31 +1,36 @@
<?php <?php
session_start(); session_start();
require(__DIR__ . "/vendor/autoload.php"); require(__DIR__ . "/vendor/autoload.php");
// Environnement //environnement
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->safeLoad(); $dotenv->safeLoad();
$strCtrl = $_GET['ctrl'] ?? 'project'; $strCtrl = $_GET['ctrl']??'project';
$strMethod = $_GET['action'] ?? 'home'; $strMethod = $_GET['action']??'home';
$strClassName = "Controllers\\" . ucfirst($strCtrl) . "Ctrl"; $boolError = false;
$strFileName = "./controllers/".$strCtrl."_controller.php";
$boolError = false; if(file_exists($strFileName)){
require($strFileName);
if (class_exists($strClassName)) { $strClassName = ucfirst($strCtrl)."Ctrl";
$objController = new $strClassName(); if(class_exists($strClassName)){
$objController = new $strClassName();
if (method_exists($objController, $strMethod)) { if(method_exists($objController,$strMethod)){
$objController->$strMethod(); $objController->$strMethod ();
} else { }else{
$boolError = true;
}
}else{
$boolError = true; $boolError = true;
} }
} else { }else{
$boolError = true; $boolError = true;
} }
if ($boolError) { if($boolError){
header("Location: index.php?ctrl=error&action=error_404"); header("Location:index.php?ctrl=error&action=error_404");
exit; }
}

View file

@ -1,24 +0,0 @@
<?php
namespace Models;
use \PDO;
class MotherModel {
protected $_db;
public function __construct(){
try{
$this->_db = new PDO(
"mysql:host=localhost;dbname=projet_folliow",
"projet_user",
"F0lliowRules!",
array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC)
);
$this->_db->exec("SET CHARACTER SET utf8");
$this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException$e) {
echo "Échec : " . $e->getMessage();
}
}
}

View file

@ -1,7 +1,5 @@
<?php <?php
namespace Models; require_once('mother_model.php');
use \PDO;
/** /**
@ -9,7 +7,7 @@
* @author : Laura * @author : Laura
*/ */
class AuthorisationModel extends MotherModel{ class AuthorisationModel extends Connect{
public function __construct(){ public function __construct(){
parent::__construct(); parent::__construct();

View file

@ -1,14 +1,12 @@
<?php <?php
namespace Models; require_once('mother_model.php');
use \PDO;
/** /**
* Traitement des requêtes pour les catégories * Traitement des requêtes pour les catégories
* @author : Laura * @author : Laura
*/ */
class CategoryModel extends MotherModel{ class CategoryModel extends Connect{
/** /**
* Fonction de récupération des catégories * Fonction de récupération des catégories

View file

@ -1,7 +1,5 @@
<?php <?php
namespace Models; require_once('mother_model.php');
use \PDO;
/** /**
@ -9,7 +7,7 @@
* @author Laura * @author Laura
*/ */
class ImageModel extends MotherModel{ class ImageModel extends Connect{
/** /**
* Fonction de récupération des images * Fonction de récupération des images

36
models/mother_model.php Normal file
View file

@ -0,0 +1,36 @@
<?php
class Connect {
protected $_db;
public function __construct(){
try{
// Connexion à la base de données
$this->_db = new PDO(
"mysql:host=boulayoune.com;dbname=projet_folliow", // Serveur et BDD "mysql:host=localhost;dbname=projet_folliow",
"projet_user", //Nom d'utilisateur de la base de données root
"F0lliowRules!",// Mot de passe de la base de données
array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC) // Mode de renvoi
);
// Pour résoudre les problèmes dencodage
$this->_db->exec("SET CHARACTER SET utf8");
// Configuration des exceptions
$this->_db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException$e) {
echo "Échec : " . $e->getMessage();
}
}
}
/**
*Pour passer sur le serveur de YASS:
*"mysql:host=boulayoune.com;dbname=projet_folliow", // Serveur et BDD
"projet_user", //Nom d'utilisateur de la base de données
"F0lliowRules!",// Mot de passe de la base de données
Site pour BDD: https://phpmyadmin.boulayoune.com/index.php?route=/sql&pos=0&db=projet_folliow&table=project
*Pour passer en local:
*"mysql:host=localhost;dbname=projet_folliow", // Serveur et BDD
*"root", //Nom d'utilisateur de la base de données
*"",// Mot de passe de la base de données
*/

View file

@ -1,16 +1,13 @@
<?php <?php
namespace Models; require_once('mother_model.php');
use \PDO;
/** /**
* Traitement des requêtes pour les projets * Traitement des requêtes pour les projets
* @author Laura & Guillaume * @author : Laura
*/ */
class ProjectModel extends MotherModel{ class ProjectModel extends Connect{
/** /**
@ -27,54 +24,80 @@
user_pseudo AS 'project_creatorname', user_pseudo AS 'project_creatorname',
user_image user_image
FROM project FROM project
INNER JOIN users ON user_id = project_user_id"; INNER JOIN users ON user_id = project_user_id
WHERE 1=1";
$strRq .= " WHERE project_deleted_at IS NULL";
$strAnd = " AND ";
if ($strKeywords != '') { if ($strKeywords != '') {
$strRq .= " AND (project_title LIKE :keywords OR project_content LIKE :keywords)";
$strSafeKeywords = $this->_db->quote("%" . $strKeywords . "%");
$strRq .= $strAnd. " (project_title LIKE ".$strSafeKeywords."
OR project_content LIKE ".$strSafeKeywords.") ";
} }
if ($intAuthor > 0){ if ($intAuthor > 0){
$strRq .= $strAnd." user_id = ".$intAuthor; $strRq .= " AND project_user_id = :author";
}
}
if ($intCategory > 0){ if ($intCategory > 0){
$strRq .= $strAnd." project_category = ".$intCategory; $strRq .= " AND project_category = :category";
} }
if ($boolOlderThan6Months === true) { if ($boolOlderThan6Months === true) {
$strRq .= $strAnd . " project_creation_date <= DATE_SUB(NOW(), INTERVAL 6 MONTH) "; $strRq .= " AND project_creation_date <= DATE_SUB(NOW(), INTERVAL 6 MONTH)";
} }
if ($intPeriod == 0){ if ($intPeriod == 0){
if ($strDate != ''){ if ($strDate != ''){
$strRq .= $strAnd." project_creation_date = '".$strDate."'"; $strRq .= " AND project_creation_date = :date_exacte";
} }
}else{ } else {
if ($strStartDate != '' && $strEndDate != ''){ if ($strStartDate != '' && $strEndDate != ''){
$strRq .= $strAnd." project_creation_date BETWEEN '".$strStartDate."' AND '".$strEndDate."'"; $strRq .= " AND project_creation_date BETWEEN :date_debut AND :date_fin";
}else{ } else {
if ($strStartDate != ''){ if ($strStartDate != ''){
$strRq .= $strAnd." project_creation_date >= '".$strStartDate."'"; $strRq .= " AND project_creation_date >= :date_debut";
}else if ($strEndDate != ''){ } else if ($strEndDate != ''){
$strRq .= $strAnd." project_creation_date <= '".$strEndDate."'"; $strRq .= " AND project_creation_date <= :date_fin";
} }
} }
} }
$strRq .= " ORDER BY project_creation_date DESC"; $strRq .= " ORDER BY project_creation_date DESC";
if ($intLimit > 0){ if ($intLimit > 0){
$strRq .= " LIMIT ".$intLimit; $strRq .= " LIMIT :limit";
} }
return $this->_db->query($strRq)->fetchAll(); $rqPrep = $this->_db->prepare($strRq);
if ($strKeywords != '') {
$rqPrep->bindValue(':keywords', '%' . $strKeywords . '%', PDO::PARAM_STR);
}
if ($intAuthor > 0){
$rqPrep->bindValue(':author', $intAuthor, PDO::PARAM_INT);
}
if ($intCategory > 0){
$rqPrep->bindValue(':category', $intCategory, PDO::PARAM_INT);
}
if ($intPeriod == 0){
if ($strDate != ''){
$rqPrep->bindValue(':date_exacte', $strDate, PDO::PARAM_STR);
}
} else {
if ($strStartDate != '' && $strEndDate != ''){
$rqPrep->bindValue(':date_debut', $strStartDate, PDO::PARAM_STR);
$rqPrep->bindValue(':date_fin', $strEndDate, PDO::PARAM_STR);
} else {
if ($strStartDate != ''){
$rqPrep->bindValue(':date_debut', $strStartDate, PDO::PARAM_STR);
} else if ($strEndDate != ''){
$rqPrep->bindValue(':date_fin', $strEndDate, PDO::PARAM_STR);
}
}
}
if ($intLimit > 0){
$rqPrep->bindValue(':limit', $intLimit, PDO::PARAM_INT);
}
$rqPrep->execute();
return $rqPrep->fetchAll();
} }
@ -98,9 +121,12 @@
$rqPrep->bindValue(":project_user_id", $objProject->getUser_id(), PDO::PARAM_STR); $rqPrep->bindValue(":project_user_id", $objProject->getUser_id(), PDO::PARAM_STR);
$rqPrep->bindValue(":project_category", $objProject->getCategory(), PDO::PARAM_STR); $rqPrep->bindValue(":project_category", $objProject->getCategory(), PDO::PARAM_STR);
// On met une variable boolOk pour récupérer l'id du projet
$boolOk = $rqPrep->execute(); $boolOk = $rqPrep->execute();
// Si boolOk est remplis
if ($boolOk) { if ($boolOk) {
// On récupère l'ID auto-incrémenté et on l'injecte dans l'objet
$objProject->setId($this->_db->lastInsertId()); $objProject->setId($this->_db->lastInsertId());
} }
@ -120,8 +146,7 @@
FROM project FROM project
INNER JOIN users ON users.user_id = project.project_user_id INNER JOIN users ON users.user_id = project.project_user_id
LEFT JOIN category ON category.category_id = project.project_category LEFT JOIN category ON category.category_id = project.project_category
WHERE project.project_id = :id WHERE project.project_id = :id";
AND project.project_deleted_at IS NULL";
$rqPrep = $this->_db->prepare($strRq); $rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(":id", $intId, PDO::PARAM_INT); $rqPrep->bindValue(":id", $intId, PDO::PARAM_INT);
@ -132,14 +157,14 @@
/** /**
* Fonction de changement de status (accepter) d'un projet en BDD * Fonction de changement de status (accepter) d'un projet en BDD
* @author Guillaume
* @param int $id l'id du projet * @param int $id l'id du projet
* @return bool Est-ce que la requête s'est bien passée * @return bool Est-ce que la requête s'est bien passée
*/ */
public function accept(int $id){ public function accept(int $id){
$strRq = "UPDATE project $strRq = "UPDATE project
SET project_status = 'publié', SET project_status= 'publié'
project_edit_date = NOW()
WHERE project_id =".$id; WHERE project_id =".$id;
return $this->_db->query($strRq); return $this->_db->query($strRq);
@ -147,14 +172,14 @@
/** /**
* Fonction de changement de status (refusé) d'un projet en BDD * Fonction de changement de status (refusé) d'un projet en BDD
* @author Guillaume
* @param int $id l'id du projet * @param int $id l'id du projet
* @return bool Est-ce que la requête s'est bien passée * @return bool Est-ce que la requête s'est bien passée
*/ */
public function refuse(int $id){ public function refuse(int $id){
$strRq = "UPDATE project $strRq = "UPDATE project
SET project_status = 'refusé', SET project_status= 'refusé'
project_edit_date = NOW()
WHERE project_id =".$id; WHERE project_id =".$id;
return $this->_db->query($strRq); return $this->_db->query($strRq);
@ -162,23 +187,21 @@
/** /**
* Fonction de suppression d'un projet en BDD * Fonction de suppression d'un projet en BDD
* @author Guillaume
* @param int $id l'id du projet * @param int $id l'id du projet
* @return bool Est-ce que la requête s'est bien passée * @return bool Est-ce que la requête s'est bien passée
*/ */
public function delete_soft_project(int $intId): bool { public function delete(int $id){
$strRq = "UPDATE project
SET project_deleted_at = NOW(),
project_edit_date = NOW()
WHERE project_id = :id";
$rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(":id", $intId, PDO::PARAM_INT);
return $rqPrep->execute(); $strRq = "DELETE FROM project
WHERE project_id =".$id;
return $this->_db->query($strRq);
} }
/** /**
* Fonction de mise à jour d'un projet en BDD * Fonction de mise à jour d'un projet en BDD
* @author Guillaume
* @param object $objProject L'objet utilisateur * @param object $objProject L'objet utilisateur
* @return bool Est-ce que la requête s'est bien passée * @return bool Est-ce que la requête s'est bien passée
*/ */
@ -188,9 +211,7 @@
SET project_title = :title, SET project_title = :title,
project_description = :description, project_description = :description,
project_content = :content, project_content = :content,
project_thumbnail = :thumbnail, project_thumbnail = :thumbnail
project_status = 'en_attente',
project_edit_date = NOW()
WHERE project_id = :id"; WHERE project_id = :id";
$rqPrep = $this->_db->prepare($strRq); $rqPrep = $this->_db->prepare($strRq);
@ -206,6 +227,7 @@
/** /**
* Fonction de récupération d'image d'un projet en BDD * Fonction de récupération d'image d'un projet en BDD
* @author Guillaume
* @param int $objProject L'Id du projet choisit * @param int $objProject L'Id du projet choisit
* @return array Un tableau avec les informations de la bdd * @return array Un tableau avec les informations de la bdd
*/ */
@ -223,6 +245,7 @@
/** /**
* Fonction de récupération d'image d'un projet en BDD * Fonction de récupération d'image d'un projet en BDD
* @author Guillaume
* @param int $id L'Id de l'image choisit * @param int $id L'Id de l'image choisit
* @return array Un tableau avec les informations de la bdd * @return array Un tableau avec les informations de la bdd
*/ */
@ -235,13 +258,12 @@
/** /**
* Fonction de modifications de status de l'image d'un projet en BDD * Fonction de modifications de status de l'image d'un projet en BDD
* @author Guillaume
* @param int $id L'Id de l'image choisit, string $status le status choisit * @param int $id L'Id de l'image choisit, string $status le status choisit
* @return array Un tableau avec les informations de la bdd * @return array Un tableau avec les informations de la bdd
*/ */
public function updateImageStatus(int $id, string $status): bool { public function updateImageStatus(int $id, string $status): bool {
$strRq = "UPDATE image $strRq = "UPDATE image SET image_status = :status WHERE image_id = :id";
SET image_status = :status
WHERE image_id = :id";
$rqPrep = $this->_db->prepare($strRq); $rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(':status', $status, PDO::PARAM_STR); $rqPrep->bindValue(':status', $status, PDO::PARAM_STR);
$rqPrep->bindValue(':id', $id, PDO::PARAM_INT); $rqPrep->bindValue(':id', $id, PDO::PARAM_INT);
@ -250,12 +272,12 @@
/** /**
* Fonction de récupération d'image d'un projet en BDD * Fonction de récupération d'image d'un projet en BDD
* @author Guillaume
* @param int $id L'Id de l'image choisit * @param int $id L'Id de l'image choisit
* @return array Un tableau avec les informations de la bdd * @return array Un tableau avec les informations de la bdd
*/ */
public function findImage(int $id): array|bool { public function findImage(int $id): array|bool {
$strRq = "SELECT * FROM image $strRq = "SELECT * FROM image WHERE image_id = :id";
WHERE image_id = :id";
$rqPrep = $this->_db->prepare($strRq); $rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(':id', $id, PDO::PARAM_INT); $rqPrep->bindValue(':id', $id, PDO::PARAM_INT);
$rqPrep->execute(); $rqPrep->execute();
@ -265,6 +287,7 @@
/** /**
* Ajoute une image liée à un projet dans la table 'image' * Ajoute une image liée à un projet dans la table 'image'
* @author Guillaume
* @param string $fileName Nom du fichier image * @param string $fileName Nom du fichier image
* @param int $projectId ID du projet parent * @param int $projectId ID du projet parent
* @param string $alt Texte alternatif * @param string $alt Texte alternatif
@ -283,10 +306,10 @@
$rqPrep->bindValue(":name", $fileName, PDO::PARAM_STR); $rqPrep->bindValue(":name", $fileName, PDO::PARAM_STR);
$rqPrep->bindValue(":alt", $alt, PDO::PARAM_STR); $rqPrep->bindValue(":alt", $alt, PDO::PARAM_STR);
// On met le statut par défaut en "en_attente" pour la modération
$rqPrep->bindValue(":status", "en_attente", PDO::PARAM_STR); $rqPrep->bindValue(":status", "en_attente", PDO::PARAM_STR);
$rqPrep->bindValue(":project", $projectId, PDO::PARAM_INT); $rqPrep->bindValue(":project", $projectId, PDO::PARAM_INT);
return $rqPrep->execute(); return $rqPrep->execute();
} }
}
}

View file

@ -1,16 +1,13 @@
<?php <?php
namespace Models; require_once('mother_model.php');
use \PDO;
/** /**
* Traitement des requêtes pour les utilisateurs * Traitement des requêtes pour les utilisateurs
* @author : Yasser, Guillaume & Besnik * @author : meilleurGroup
*/ */
class UserModel extends MotherModel{ class UserModel extends Connect{
public function __construct(){ public function __construct(){
parent::__construct(); parent::__construct();
@ -73,51 +70,28 @@
return $rqPrep->execute(); return $rqPrep->execute();
} }
/**
* Méthode pour sauvegarder l'utilisateur lorsqu'il veut être souvenue
* @param int $userId l'id de l'utilisateur a se rappeler
* @param string $token Token hashé unique lié à l'utilisateur à se rappeler
* @return bool Est-ce que la requête s'est bien passée
*/
public function remember(int $userId, string $token):bool{ public function remember(int $userId, string $token):bool{
$strRq = "INSERT INTO tokens (token_user_id, token_hash, token_created_at, token_expire_at) VALUES (:id, :token, NOW(), :exp)"; $strRq = "INSERT INTO tokens (token_user_id, token_hash, token_created_at, token_expire_at) VALUES (:id, :token, NOW(), :exp)";
$rqPrep = $this->_db->prepare($strRq); $rqPrep = $this->_db->prepare($strRq);
$rqPrep->bindValue(":id", $userId, PDO::PARAM_INT); $rqPrep->bindValue(":id", $userId, PDO::PARAM_INT);
$rqPrep->bindValue(":token", $token, PDO::PARAM_STR); $rqPrep->bindValue(":token", $token, PDO::PARAM_STR);
$rqPrep->bindValue(":exp", $rqPrep->bindValue(":exp",
//pour faire que le cookies soit valable 15 jours
date('Y-m-d H:i:s', time() + (15*24*60*60)) date('Y-m-d H:i:s', time() + (15*24*60*60))
, PDO::PARAM_STR); , PDO::PARAM_STR);
return $rqPrep->execute(); return $rqPrep->execute();
} }
/**
* Méthode pour récupperer l'utilisateur par rapport au cookie enregistrer
* @param string $hash Token hashé unique lié à l'utilisateur
* @return bool Est-ce que la requête s'est bien passée
*/
public function getTokenUser(string $hash){ public function getTokenUser(string $hash){
$strRq = $this->_db->prepare("SELECT token_user_id FROM tokens WHERE token_hash = :hash AND token_expire_at > NOW()"); $strRq = $this->_db->prepare("SELECT token_user_id FROM tokens WHERE token_hash = :hash AND token_expire_at > NOW()");
$strRq->execute(['hash' => $hash]); $strRq->execute(['hash' => $hash]);
return $strRq->fetch(); return $strRq->fetch();
} }
/**
* Méthode pour supprimer le token lors de la déconnexion
* @param string $hash Token hashé unique lié à l'utilisateur
* @return bool Est-ce que la requête s'est bien passée
*/
public function deleteToken(string $hash){ public function deleteToken(string $hash){
$strRq = $this->_db->prepare("DELETE FROM tokens WHERE token_hash = :hash"); $strRq = $this->_db->prepare("DELETE FROM tokens WHERE token_hash = :hash");
return $strRq->execute(['hash' => $hash]); return $strRq->execute(['hash' => $hash]);
} }
/**
* Méthode pour mettre a jour l'utilisateur
* @param object $objUser L'objet user a mettre à jour
* @return bool Est-ce que la requête s'est bien passée
*/
public function update(object $objUser):bool{ public function update(object $objUser):bool{
$strRq = "UPDATE users SET $strRq = "UPDATE users SET
user_name = :name, user_name = :name,
@ -215,11 +189,6 @@
return $prep->fetch(); return $prep->fetch();
} }
/**
* Récupère les informations d'un utilisateur par son ID
* @param string $strPseudo Pseudo de l'utilisateur
* @return array Tableau associatif (ou false si pas trouvé)
*/
public function findUserByPseudo(string $strPseudo): array|bool { public function findUserByPseudo(string $strPseudo): array|bool {
$strRq = "SELECT user_id,user_image, user_status ,user_name, user_firstname, user_pseudo, user_mail, user_phone, user_work, user_location, user_description, authorisation_name $strRq = "SELECT user_id,user_image, user_status ,user_name, user_firstname, user_pseudo, user_mail, user_phone, user_work, user_location, user_description, authorisation_name
@ -233,11 +202,6 @@
return $prep->fetch(); return $prep->fetch();
} }
/**
* Verifie sur le pseudo entré n'est pas déjà utilisé
* @param string $pseudo Pseudo a verifié
* @return array Tableau associatif (ou false si pas trouvé)
*/
public function pseudoExists(string $pseudo): bool{ public function pseudoExists(string $pseudo): bool{
$rq = $this->_db->prepare("SELECT 1 FROM users WHERE user_pseudo = :pseudo LIMIT 1"); $rq = $this->_db->prepare("SELECT 1 FROM users WHERE user_pseudo = :pseudo LIMIT 1");

View file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View file

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View file

@ -12,9 +12,7 @@ return array(
'Smarty\\' => array($vendorDir . '/smarty/smarty/src'), 'Smarty\\' => array($vendorDir . '/smarty/smarty/src'),
'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'), 'PhpOption\\' => array($vendorDir . '/phpoption/phpoption/src/PhpOption'),
'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'), 'PHPMailer\\PHPMailer\\' => array($vendorDir . '/phpmailer/phpmailer/src'),
'Models\\' => array($baseDir . '/models'), 'Guill\\Guillaume\\' => array($baseDir . '/src'),
'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'), 'GrahamCampbell\\ResultType\\' => array($vendorDir . '/graham-campbell/result-type/src'),
'Entities\\' => array($baseDir . '/entities'),
'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'), 'Dotenv\\' => array($vendorDir . '/vlucas/phpdotenv/src'),
'Controllers\\' => array($baseDir . '/controllers'),
); );

View file

@ -26,26 +26,15 @@ class ComposerStaticInit68f8d029d347b4c0c8cdbe33eeb96101
'PhpOption\\' => 10, 'PhpOption\\' => 10,
'PHPMailer\\PHPMailer\\' => 20, 'PHPMailer\\PHPMailer\\' => 20,
), ),
'M' =>
array (
'Models\\' => 7,
),
'G' => 'G' =>
array ( array (
'Guill\\Guillaume\\' => 16,
'GrahamCampbell\\ResultType\\' => 26, 'GrahamCampbell\\ResultType\\' => 26,
), ),
'E' =>
array (
'Entities\\' => 9,
),
'D' => 'D' =>
array ( array (
'Dotenv\\' => 7, 'Dotenv\\' => 7,
), ),
'C' =>
array (
'Controllers\\' => 12,
),
); );
public static $prefixDirsPsr4 = array ( public static $prefixDirsPsr4 = array (
@ -73,26 +62,18 @@ class ComposerStaticInit68f8d029d347b4c0c8cdbe33eeb96101
array ( array (
0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src', 0 => __DIR__ . '/..' . '/phpmailer/phpmailer/src',
), ),
'Models\\' => 'Guill\\Guillaume\\' =>
array ( array (
0 => __DIR__ . '/../..' . '/models', 0 => __DIR__ . '/../..' . '/src',
), ),
'GrahamCampbell\\ResultType\\' => 'GrahamCampbell\\ResultType\\' =>
array ( array (
0 => __DIR__ . '/..' . '/graham-campbell/result-type/src', 0 => __DIR__ . '/..' . '/graham-campbell/result-type/src',
), ),
'Entities\\' =>
array (
0 => __DIR__ . '/../..' . '/entities',
),
'Dotenv\\' => 'Dotenv\\' =>
array ( array (
0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src', 0 => __DIR__ . '/..' . '/vlucas/phpdotenv/src',
), ),
'Controllers\\' =>
array (
0 => __DIR__ . '/../..' . '/controllers',
),
); );
public static $classMap = array ( public static $classMap = array (

View file

@ -1,23 +1,34 @@
<footer class="py-3 mt-3 text-center" > <footer class="footer container-fluid d-flex justify-content-around mt-auto">
<p>Créé par YaLaGuBe</a></p> <div class="col-3">
<nav aria-label="Navigation pied de page"> <ul>
<ul class="list-inline"> <li><a href="#">Découvrir</a>
<li class="list-inline-item"> <li><a href="#">Customisation</a>
<a href="?ctrl=page&action=about">A propos</a> <li><a href="#">Emploi</a>
</li> <li><a href="?ctrl=project&action=about">A propos</a>
<li class="list-inline-item" aria-hidden="true">|</li> </ul>
<li class="list-inline-item"> </div>
<a href="index.php?ctrl=page&action=help">Aide et support</a> <div class="col-3">
</li> <ul>
<li class="list-inline-item" aria-hidden="true">|</li> <li><a href="#">Recruter</a>
<li class="list-inline-item"> <li><a href="#">Partenariat</a>
<a href="?ctrl=page&action=mentions">Mentions légales</a> <li><a href="#">Blog</a>
</li> <li><a href="index.php?ctrl=page&action=help">Aide et support</a>
</ul> </ul>
</nav> </div>
<div class="col-3">
<ul>
<li><a href="#">Politique de confidentialité</a>
<li><a href="?ctrl=project&action=mentions">Mentions légales</a>
<li><a href="#">CGU</a>
<li><a href="#">CGV</a>
</ul>
</div>
<div class="col-3">
<p>Suivez-nous</p>
</div>
</footer> </footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
<script src="assests/js/scripts.js"></script> <script src="assests/js/scripts.js"></script>
</body>
</html>

View file

@ -4,8 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="assests/css/style.css"> <link rel="stylesheet" href="assests/css/style.css">
<link rel="shortcut icon" href="assests/img/Group-49.ico" type="image/x-icon"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-sRIl4kxILFvY47J16cr9ZwB07vP4J8+LH7qKQnuqkuIAvNWLzeN8tE5YBujZqJLB" crossorigin="anonymous">
<script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script> <script src="https://use.fontawesome.com/releases/v6.3.0/js/all.js" crossorigin="anonymous"></script>
<title>Folliow{block name="title"}{/block}</title> <title>Folliow{block name="title"}{/block}</title>
@ -13,19 +12,22 @@
<body class="d-flex flex-column min-vh-100"> <body class="d-flex flex-column min-vh-100">
<nav class="navbar navbar-expand-lg navbar-light"> <nav class="navbar navbar-expand-lg navbar-light">
<div class="container-fluid"> <div class="container-fluid">
{* Logo *}
<a class="navbar-brand d-flex align-items-center" href="index.php"> <a class="navbar-brand d-flex align-items-center" href="index.php">
<img src="assests/img/logo.png" alt="Logo" class="logo-image"> <img src="assests/img/logo.png" alt="Logo" class="logo-image">
</a> </a>
{* Toggler pour mobile *}
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>
{* Menu de navigation *}
<div class="collapse navbar-collapse" id="navbarNav"> <div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto"> <ul class="navbar-nav me-auto">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="?ctrl=page&action=about">À propos</a> <a class="nav-link" href="?ctrl=project&action=about">À propos</a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
@ -43,8 +45,10 @@
{/if} {/if}
</ul> </ul>
{* Menu secondaire *}
<nav class="col-4 d-flex justify-content-end align-items-center" aria-label="Connexion utilisateur"> <nav class="col-4 d-flex justify-content-end align-items-center" aria-label="Connexion utilisateur">
{if !isset($smarty.session.user)} {if !isset($smarty.session.user)}
{* Utilisateur non connecté *}
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="index.php?ctrl=user&action=signup" title="Créer un compte" aria-label="Créer un compte"> <a class="nav-link" href="index.php?ctrl=user&action=signup" title="Créer un compte" aria-label="Créer un compte">
@ -58,10 +62,11 @@
</li> </li>
</ul> </ul>
{else} {else}
{* Utilisateur connecté *}
<ul class="navbar-nav"> <ul class="navbar-nav">
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="index.php?ctrl=user&action=user&pseudo={$smarty.session.user.user_pseudo}" title="Modifier mon compte" aria-label="Modifier mon compte"> <a class="nav-link" href="index.php?ctrl=user&action=user&pseudo={$smarty.session.user.user_pseudo}" title="Modifier mon compte" aria-label="Modifier mon compte">
<img src={$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($smarty.session.user.user_image))|file_exists}{$smarty.session.user.user_image}{else}images.jpg{/if} <img src="{$smarty.env.IMG_USER_PATH}{$smarty.session.user.user_image ?? "images.jpg"}"
class="rounded-circle flex-shrink-0 mt-2 ml-5" class="rounded-circle flex-shrink-0 mt-2 ml-5"
style="width: 36px; height: 36px; object-fit: cover;" style="width: 36px; height: 36px; object-fit: cover;"
alt="Photo de profil"> alt="Photo de profil">
@ -79,25 +84,4 @@
</div> </div>
</div> </div>
</nav> </nav>
<main id="main-content" class="container my-4">
<section
class="p-4 mb-4 text-center txt_title "
aria-labelledby="page-title"
>
<div class="col-lg-8 mx-auto">
<h2 id="page-title" class="display-5 fw-semibold mb-3">
{block name="h2"}{/block}
</h2>
<p class="lead mb-2">
{block name="p"}{/block}
</p>
<p class="text-muted small mb-0">
{block name="date_maj"}{/block}
</p>
</div>
</section>
</main>
</body>
{include file="views/_partial/messages.tpl"} {include file="views/_partial/messages.tpl"}

View file

@ -1,25 +1,27 @@
<article class="col-md-3 mb-5 {if isset($smarty.session.user) and $smarty.session.user.user_status == 2} pb-5 {/if}" style="border-radius: 100px ;"> <article class="col-md-3 mb-5 {if isset($smarty.session.user) and $smarty.session.user.user_status == 2} pb-5 {/if}" style="border-radius: 100px ;">
<div class="card h-100 shadow article-card rounded-4" style="border-width: 2px; overflow: hidden;"> <div class="card h-100 shadow article-card rounded-4" style="border-width: 2px; overflow: hidden;">
{* IMAGE (partie supérieure - plus grande) *}
<div class="ratio ratio-4x3"> <div class="ratio ratio-4x3">
<a href="index.php?ctrl=project&action=display&id={$objProject->getId()}"></a> <a href="index.php?ctrl=project&action=display&id={$objProject->getId()}"></a>
<img src="{$smarty.env.IMG_PROJECT_PATH}{if ($smarty.env.IMG_PROJECT_PATH|cat:$objProject->getThumbnail())|file_exists}{$objProject->getThumbnail()}{else}{math equation="rand(1,4)"}.jpg{/if}" <img src="{$smarty.env.IMG_PROJECT_PATH}{$objProject->getThumbnail()}"
class="w-100 h-100 object-fit-cover" class="w-100 h-100 object-fit-cover"
alt="" alt=""
loading="lazy"> loading="lazy">
</a> </a>
</div> </div>
{* CONTENU (photo profil + infos) *}
<div class="card-body p-3 bg-light"> <div class="card-body p-3 bg-light">
<div class="d-flex align-items-start gap-3"> <div class="d-flex align-items-start gap-3">
{* PHOTO DE PROFIL (cercle à gauche - plus grand) *}
<a href="index.php?ctrl=user&action=user&id={$objProject->getUser_id()}"> <a href="index.php?ctrl=user&action=user&id={$objProject->getUser_id()}">
<img src="{$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($objProject->getUser_image()))|file_exists}{$objProject->getUser_image()}{else}images.jpg{/if}" <img src="{$smarty.env.IMG_USER_PATH}{$objProject->getUser_image() ?? "images.jpg"}"
class="rounded-circle flex-shrink-0 border border-2 border-white" class="rounded-circle flex-shrink-0 border border-2 border-white"
style="width: 64px; height: 64px; object-fit: cover; margin-top: 8px;" style="width: 64px; height: 64px; object-fit: cover; margin-top: 8px;"
alt="Photo de profil"> alt="Photo de profil">
</a> </a>
{* INFOS À DROITE *}
<div class="flex-grow-1"> <div class="flex-grow-1">
<h3 class="h6 fw-bold mb-2 mt-1">{$objProject->getTitle()}</h3> <h3 class="h6 fw-bold mb-2 mt-1">{$objProject->getTitle()}</h3>
<p class="small text-muted mb-1"> <p class="small text-muted mb-1">
@ -31,14 +33,14 @@
</a> </a>
</p> </p>
<p class="small text-muted mb-0"> <p class="small text-muted mb-0">
<i class="bi bi-geo-alt">Colmar</i> <i class="bi bi-geo-alt"></i> Colmar
</p> </p>
</div> </div>
</div> </div>
<div class="d-flex justify-content-between align-items-center mt-3"> <div class="d-flex justify-content-between align-items-center mt-3">
<small class="text-muted"> <small class="text-muted">
<i class="bi bi-clock"><time>{$objProject->getCreation_date()}</time></i> <i class="bi bi-clock"></i> <time>{$objProject->getCreation_date()}</time>
</small> </small>
{if $objProject->getStatus() != "refusé"} {if $objProject->getStatus() != "refusé"}
<a href="index.php?ctrl=project&action=display&id={$objProject->getId()}" <a href="index.php?ctrl=project&action=display&id={$objProject->getId()}"
@ -59,6 +61,7 @@
{/if} {/if}
</div> </div>
{* BOUTONS EN BAS *}
{if isset($smarty.session.user) {if isset($smarty.session.user)
and $smarty.session.user.user_status == 2 and $smarty.session.user.user_status == 2
and $objProject->getStatus() == "en_attente"} and $objProject->getStatus() == "en_attente"}
@ -71,10 +74,8 @@
href="?ctrl=project&action=refuse&id={$objProject->getId()}" href="?ctrl=project&action=refuse&id={$objProject->getId()}"
name="toRefused">Refuser</a> name="toRefused">Refuser</a>
<a class="btn btn-sm btn-danger flex-fill" <a class="btn btn-sm btn-danger flex-fill"
href="index.php?ctrl=project&action=delete&id={$objProject->getId()}" href="?ctrl=project&action=delete&id={$objProject->getId()}"
name="toDelete" name="toDelete" onclick="return confirm('Attention ! Êtes-vous sûr de vouloir supprimer ce projet ? Cette action est irréversible.');">Supprimer</a>
onclick="return confirm('Attention ! Êtes-vous sûr de vouloir supprimer ce projet ? Cette action est irréversible.');">
Supprimer</a>
</div> </div>
</div> </div>
{elseif $objProject->getStatus() == "refusé"} {elseif $objProject->getStatus() == "refusé"}

View file

@ -1,158 +1,160 @@
{extends file="views/layout.tpl"} {extends file="views/layout.tpl"}
{block name="title" append} - À propos{/block} {block name="title" append} - À propos{/block}
{block name="h2"}À propos{/block} {block name="h2"}À propos de FOLLIOW{/block}
{block name="p"}Plateforme de partage de portfolio Projet pédagogique{/block} {block name="p"}Plateforme de partage de projets Projet pédagogique{/block}
{block name="content"} {block name="content"}
<section aria-label="À propos de FOLLIOW"> <section aria-label="À propos de FOLLIOW">
<div class="row g-5"> <div class="row g-5">
<div class="col-lg-8">
<!-- Présentation principale -->
<section aria-labelledby="presentation"> <div class="col-lg-8">
<h3 id="presentation" class="h4 mb-3">
<i class="fas fa-lightbulb me-2 text-primary"></i> <section aria-labelledby="presentation">
Présentation du projet <h3 id="presentation" class="h4 mb-3">
</h3> <i class="fas fa-lightbulb me-2 text-primary"></i>
Présentation du projet
<p> </h3>
<strong>FOLLIOW</strong> est une plateforme web développée dans le cadre dun projet pédagogique.
Elle permet aux utilisateurs de publier, consulter et partager des projets numériques <p>
à travers une interface simple et structurée. <strong>FOLLIOW</strong> est une plateforme web développée dans le cadre dun projet pédagogique.
</p> Elle permet aux utilisateurs de publier, consulter et partager des projets numériques
à travers une interface simple et structurée.
<p> </p>
Ce projet a été conçu afin de mettre en pratique les compétences acquises en
développement web, notamment larchitecture MVC, la gestion des bases de données <p>
et la sécurisation des échanges. Ce projet a été conçu afin de mettre en pratique les compétences acquises en
</p> développement web, notamment larchitecture MVC, la gestion des bases de données
</section> et la sécurisation des échanges.
</p>
<section aria-labelledby="fonctionnalites" class="mt-4"> </section>
<h3 id="fonctionnalites" class="h4 mb-3">
<i class="fas fa-cogs me-2 text-primary"></i> <section aria-labelledby="fonctionnalites" class="mt-4">
Fonctionnalités principales <h3 id="fonctionnalites" class="h4 mb-3">
</h3> <i class="fas fa-cogs me-2 text-primary"></i>
Fonctionnalités principales
<ul> </h3>
<li>Création et gestion de projets</li>
<li>Affichage dynamique des contenus</li> <ul>
<li>Gestion des utilisateurs</li> <li>Création et gestion de projets</li>
<li>Partage dun projet par email</li> <li>Affichage dynamique des contenus</li>
<li>Interface responsive et accessible</li> <li>Gestion des utilisateurs</li>
</ul> <li>Partage dun projet par email</li>
</section> <li>Interface responsive et accessible</li>
</ul>
<section aria-labelledby="objectifs" class="mt-4"> </section>
<h3 id="objectifs" class="h4 mb-3">
<i class="fas fa-bullseye me-2 text-primary"></i> <section aria-labelledby="objectifs" class="mt-4">
Objectifs pédagogiques <h3 id="objectifs" class="h4 mb-3">
</h3> <i class="fas fa-bullseye me-2 text-primary"></i>
Objectifs pédagogiques
<p> </h3>
Lobjectif principal de FOLLIOW est de démontrer la capacité à concevoir
une application web complète, structurée et sécurisée. <p>
</p> Lobjectif principal de FOLLIOW est de démontrer la capacité à concevoir
une application web complète, structurée et sécurisée.
<ul> </p>
<li>Structuration dun projet en architecture MVC</li>
<li>Manipulation de bases de données relationnelles</li> <ul>
<li>Validation et sécurisation des données</li> <li>Structuration dun projet en architecture MVC</li>
<li>Implémentation dun système denvoi demails</li> <li>Manipulation de bases de données relationnelles</li>
<li>Respect des bonnes pratiques (RGPD, accessibilité, organisation du code)</li> <li>Validation et sécurisation des données</li>
</ul> <li>Implémentation dun système denvoi demails</li>
</section> <li>Respect des bonnes pratiques (RGPD, accessibilité, organisation du code)</li>
</ul>
<section aria-labelledby="technologies" class="mt-4"> </section>
<h3 id="technologies" class="h4 mb-3">
<i class="fas fa-code me-2 text-primary"></i> <section aria-labelledby="technologies" class="mt-4">
Technologies utilisées <h3 id="technologies" class="h4 mb-3">
</h3> <i class="fas fa-code me-2 text-primary"></i>
Technologies utilisées
<div class="row g-3"> </h3>
<div class="col-md-6">
<div class="card h-100 border-0 shadow-sm"> <div class="row g-3">
<div class="card-body"> <div class="col-md-6">
<strong>Backend</strong> <div class="card h-100 border-0 shadow-sm">
<p class="small mb-0"> <div class="card-body">
PHP orienté objet Architecture MVC MySQL <strong>Backend</strong>
</p> <p class="small mb-0">
</div> PHP orienté objet Architecture MVC MySQL
</div> </p>
</div> </div>
</div>
<div class="col-md-6"> </div>
<div class="card h-100 border-0 shadow-sm">
<div class="card-body"> <div class="col-md-6">
<strong>Frontend</strong> <div class="card h-100 border-0 shadow-sm">
<p class="small mb-0"> <div class="card-body">
HTML5 CSS3 Bootstrap Smarty <strong>Frontend</strong>
</p> <p class="small mb-0">
</div> HTML5 CSS3 Bootstrap Smarty
</div> </p>
</div> </div>
</div>
<div class="col-md-6"> </div>
<div class="card h-100 border-0 shadow-sm">
<div class="card-body"> <div class="col-md-6">
<strong>Emails</strong> <div class="card h-100 border-0 shadow-sm">
<p class="small mb-0"> <div class="card-body">
PHPMailer SMTP Brevo <strong>Emails</strong>
</p> <p class="small mb-0">
</div> PHPMailer SMTP Brevo
</div> </p>
</div> </div>
</div>
<div class="col-md-6"> </div>
<div class="card h-100 border-0 shadow-sm">
<div class="card-body"> <div class="col-md-6">
<strong>Sécurité</strong> <div class="card h-100 border-0 shadow-sm">
<p class="small mb-0"> <div class="card-body">
Validation des données Protection des formulaires Gestion des sessions <strong>Sécurité</strong>
</p> <p class="small mb-0">
</div> Validation des données Protection des formulaires Gestion des sessions
</div> </p>
</div> </div>
</div> </div>
</section> </div>
</div>
</div> </section>
<!-- Sidebar --> </div>
<div class="col-lg-4">
<div class="card shadow-sm p-4"> <!-- Sidebar -->
<div class="col-lg-4">
<h4 class="h5 mb-3"> <div class="card shadow-sm p-4">
<i class="fas fa-graduation-cap me-2 text-primary"></i>
Projet pédagogique <h4 class="h5 mb-3">
</h4> <i class="fas fa-graduation-cap me-2 text-primary"></i>
Projet pédagogique
<p class="small"> </h4>
FOLLIOW a été réalisé dans le cadre dune formation en développement web.
Il sagit dun projet démonstratif à visée éducative. <p class="small">
</p> FOLLIOW a été réalisé dans le cadre dune formation en développement web.
Il sagit dun projet démonstratif à visée éducative.
<hr> </p>
<h4 class="h5 mb-3"> <hr>
<i class="fas fa-envelope me-2 text-primary"></i>
Contact <h4 class="h5 mb-3">
</h4> <i class="fas fa-envelope me-2 text-primary"></i>
Contact
<p class="small mb-1"> </h4>
Pour toute question :
</p> <p class="small mb-1">
Pour toute question :
<a href="mailto:projet.folliow@hotmail.com" class="small"> </p>
projet.folliow@hotmail.com
</a> <a href="mailto:projet.folliow@hotmail.com" class="small">
projet.folliow@hotmail.com
</div> </a>
</div>
</div>
</div> </div>
</section>
</div>
</section>
{/block} {/block}

View file

@ -1,9 +1,5 @@
{extends file="views/layout.tpl"} {extends file="views/layout.tpl"}
{block name="h2"}Ajouter un projet{/block}
{block name="p"}Ajouter un projet à votre portfolio{/block}
{block name="content"} {block name="content"}
<section class="container mt-4"> <section class="container mt-4">
{if isset($smarty.session.user)} {if isset($smarty.session.user)}
@ -60,10 +56,12 @@
<div class="alert alert-warning p-2"> <div class="alert alert-warning p-2">
<i class="fas fa-exclamation-triangle"></i> Quota de 20 photos atteint. <i class="fas fa-exclamation-triangle"></i> Quota de 20 photos atteint.
</div> </div>
{* On désactive l'input si le quota est plein *}
<input type="file" disabled class="form-control"> <input type="file" disabled class="form-control">
{/if} {/if}
</div> </div>
{* Affichage de Images du projet (s'il y en a)*}
<div class="row mt-4"> <div class="row mt-4">
<label class="h5">Galerie du projet</label> <label class="h5">Galerie du projet</label>
{foreach $arrImages as $image} {foreach $arrImages as $image}
@ -76,6 +74,7 @@
<div class="card-body p-2"> <div class="card-body p-2">
<span class="badge {if $image.image_status == 'approuvé'}bg-success{elseif $image.image_status == 'refusé'}bg-danger{else}bg-warning text-dark{/if}"> <span class="badge {if $image.image_status == 'approuvé'}bg-success{elseif $image.image_status == 'refusé'}bg-danger{else}bg-warning text-dark{/if}">
{*Permet de remplacer certains character par d'autre*}
{$image.image_status|replace:'_':' '} {$image.image_status|replace:'_':' '}
</span> </span>

View file

@ -1,8 +1,5 @@
{extends file="views/layout.tpl"} {extends file="views/layout.tpl"}
{block name="h2"}Admin{/block}
{block name="p"}Tableau de bord administrateur{/block}
{block name="content"} {block name="content"}
<section> <section>
@ -60,7 +57,7 @@
<input type="text" class="form-control" id="floatingInput" name="new_name"> <input type="text" class="form-control" id="floatingInput" name="new_name">
<label for="floatingInput">Nouveau nom de la catégorie</label> <label for="floatingInput">Nouveau nom de la catégorie</label>
</div> </div>
<button type="submit" class="btn bg-success text-light">Valider</button> <button type="submit" class="btn bg-success text-light rounded-circle"> ✓</button>
</form> </form>
<div> <div>
</div> </div>
@ -75,7 +72,7 @@
<label for="floatingInput">Nom de la nouvelle catégorie</label> <label for="floatingInput">Nom de la nouvelle catégorie</label>
</div> </div>
<div class="col-2"> <div class="col-2">
<button type="submit" class="btn bg-success text-light">Valider</button> <button type="submit" class="btn bg-success text-light rounded-circle"> ✓</button>
</div> </div>
</form> </form>
</div> </div>

View file

@ -1,9 +1,10 @@
{extends file="views/layout.tpl"} {extends file="views/layout.tpl"}
{block name="h2"}Bienvenue sur l'aide & support de Folliow !{/block}
{block name="p"}Ici, vous trouverez de l'aide pour naviguer sur notre site.{/block}
{block name="content"} {block name="content"}
<h1 class="display-2 text-center">Bienvenue sur l'aide & support de Folliow !</h1>
<br>
<p class="display-6 text-center">Ici, vous trouverez de l'aide pour naviguer sur notre site.</p>
<br>
<section class="container"> <section class="container">
{if isset($smarty.session.user)} {if isset($smarty.session.user)}

View file

@ -26,20 +26,8 @@
<h2 class="visually-hidden">Les 4 derniers articles</h2> <h2 class="visually-hidden">Les 4 derniers articles</h2>
<div class="row mb-2"> <div class="row mb-2">
{foreach from=$arrProjectToDisplay item=objProject} {foreach from=$arrProjectToDisplay item=objProject}
{include file="views/_partial/preview.tpl"}
{assign var="isAuthor" value=(isset($smarty.session.user) && $smarty.session.user.user_id == $objProject->getUser_id())} {/foreach}
{assign var="isModerator" value=(isset($smarty.session.user) && $smarty.session.user.user_status == 2)}
{assign var="isDeleted" value=($objProject->getProject_deleted_at() !== null)}
{assign var="isRefused" value=($objProject->getStatus() == "refusé")}
{if $isModerator
|| ($isAuthor && !$isDeleted)
|| (!$isRefused && !$isDeleted)}
{include file="views/_partial/preview.tpl"}
{/if}
{/foreach}
</section> </section>
{/block} {/block}

View file

@ -1,175 +0,0 @@
{extends file="views/layout.tpl"}
{block name="content"}
<main class="container py-5">
<div class="row justify-content-center position-relative">
<div class="col-12 col-md-10 col-lg-6">
<div class="card shadow-sm border-0 rounded-4 p-4 p-lg-5">
<h1 class="h3 fw-bold mb-1">Inscription</h1>
<p class="text-secondary mb-4">Créez votre compte utilisateur.</p>
{if (isset($arrError) && count($arrError) > 0) }
<div class="alert alert-danger">
{foreach $arrError as $strError}
<p>{$strError}</p>
{/foreach}
</div>
{/if}
<form method="POST">
<div class="row g-3">
<div class="col-md-6">
<label class="form-label" for="user_firstname">
Prénom *
</label>
<input
class="form-control"
type="text"
id="user_firstname"
name="user_firstname"
required >
</div>
<div class="col-md-6">
<label class="form-label" for="user_name">
Nom *
</label>
<input
class="form-control"
type="text"
id="user_name"
name="user_name"
required>
</div>
<div class="col-12">
<label class="form-label" for="user_pseudo">
Pseudo *
</label>
<div class="input-group">
<span class="input-group-text">@</span>
<input
class="form-control"
type="text"
id="user_pseudo"
name="user_pseudo"
required
>
</div>
</div>
<!-- Champ : adresse e-mail -->
<div class="col-12">
<label class="form-label" for="user_mail">
Adresse e-mail *
</label>
<input
class="form-control"
type="email"
id="user_mail"
name="user_mail"
required
>
</div>
<!-- Champ : mot de passe -->
<div class="col-12">
<label class="form-label" for="user_password">
Mot de passe *
</label>
<input
class="form-control"
type="password"
id="user_password"
name="user_password"
required
>
</div>
<!-- Champ : confirmer le mot de passe -->
<div class="col-12">
<label class="form-label" for="pwd_confirm">
Confirmer le Mot de passe *
</label>
<input
class="form-control"
type="password"
id="pwd_confirm"
name="pwd_confirm"
required
>
</div>
<!-- Champ optionnel : numéro de téléphone -->
<div class="col-12">
<label class="form-label" for="user_phone">
Téléphone
</label>
<input
class="form-control"
type="text"
id="user_phone"
name="user_phone"
>
</div>
<!-- Champ optionnel : profession de l'utilisateur -->
<div class="col-12">
<label class="form-label" for="user_work">
Profession
</label>
<input
class="form-control"
type="text"
id="user_work"
name="user_work"
>
</div>
<!-- Champ optionnel : localisation de l'utilisateur -->
<div class="col-12">
<label class="form-label" for="user_location">
Localisation
</label>
<input
class="form-control"
type="text"
id="user_location"
name="user_location"
>
</div>
<!-- Champ optionnel : phrase d'accroche -->
<div class="col-12">
<label class="form-label" for="user_description">
Phrase d'accroche
</label>
<textarea
class="form-control"
id="user_description"
name="user_description"
rows="3"
></textarea>
</div>
<!-- Bouton de soumission du formulaire -->
<div class="col-12 d-grid mt-2">
<button type="submit" class="btn btn-primary btn-lg rounded-3">
Créer mon compte
</button>
</div>
<!-- Lien vers la page de connexion -->
<div class="col-12 text-center">
<small class="text-secondary">
Déjà un compte ?
<a href="index.php?ctrl=user&action=login">Se connecter</a>
</small>
</div>
</form>
</div>
</div>
</div>
</div>
</main>
{/block}

View file

@ -1,6 +1,6 @@
{include file="views/_partial/header.tpl"} {include file="views/_partial/header.tpl"}
<main class="container mb-4 mt-1"> <main class="container">
{block name="content"} {block name="content"}
{/block} {/block}
</main> </main>

View file

@ -1,288 +1,288 @@
{extends file="views/layout.tpl"} {extends file="views/layout.tpl"}
{block name="title" append} - Mentions légales{/block} {block name="title" append} - Mentions légales{/block}
{block name="h2"}Mentions légales{/block} {block name="h2"}Mentions légales{/block}
{block name="p"}Informations légales et politique de confidentialité{/block} {block name="p"}Informations légales et politique de confidentialité{/block}
{block name="date_maj"} {block name="date_maj"}
<p class="text-muted small mb-0"> <p class="text-muted small mb-0">
<i class="fas fa-calendar-alt me-2" aria-hidden="true"></i> <i class="fas fa-calendar-alt me-2" aria-hidden="true"></i>
Dernière mise à jour : <time datetime="2026-02-20">20 février 2026</time> Dernière mise à jour : <time datetime="2026-02-20">20 février 2026</time>
</p> </p>
{/block} {/block}
{block name="js_footer" append} {block name="js_footer" append}
<script> <script>
{literal} {literal}
document.querySelectorAll('a[href^="#"]').forEach(anchor => { document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) { anchor.addEventListener('click', function (e) {
e.preventDefault(); e.preventDefault();
const target = document.querySelector(this.getAttribute('href')); const target = document.querySelector(this.getAttribute('href'));
if (target) { if (target) {
target.scrollIntoView({ target.scrollIntoView({
behavior: 'smooth', behavior: 'smooth',
block: 'start' block: 'start'
}); });
target.focus(); target.focus();
} }
}); });
}); });
{/literal} {/literal}
</script> </script>
{/block} {/block}
{block name="content"} {block name="content"}
<section aria-label="Mentions légales"> <section aria-label="Mentions légales">
<h2 class="visually-hidden">Mentions légales</h2> <h2 class="visually-hidden">Mentions légales</h2>
<div class="row g-5"> <div class="row g-5">
<div class="col-md-12"> <div class="col-md-12">
<!-- Table des matières --> <!-- Table des matières -->
<nav class="table-of-contents" aria-labelledby="toc-heading"> <nav class="table-of-contents" aria-labelledby="toc-heading">
<h3 id="toc-heading" class="h5 mb-3"> <h3 id="toc-heading" class="h5 mb-3">
<i class="fas fa-list me-2" aria-hidden="true"></i> <i class="fas fa-list me-2" aria-hidden="true"></i>
Sommaire Sommaire
</h3> </h3>
<ul class="list-unstyled ms-3"> <ul class="list-unstyled ms-3">
<li class="mb-2"><a href="#editeur">1. Éditeur du site</a></li> <li class="mb-2"><a href="#editeur">1. Éditeur du site</a></li>
<li class="mb-2"><a href="#hebergeur">2. Hébergement</a></li> <li class="mb-2"><a href="#hebergeur">2. Hébergement</a></li>
<li class="mb-2"><a href="#propriete">3. Propriété intellectuelle</a></li> <li class="mb-2"><a href="#propriete">3. Propriété intellectuelle</a></li>
<li class="mb-2"><a href="#rgpd">4. Protection des données personnelles (RGPD)</a></li> <li class="mb-2"><a href="#rgpd">4. Protection des données personnelles (RGPD)</a></li>
<li class="mb-2"><a href="#cookies">5. Cookies</a></li> <li class="mb-2"><a href="#cookies">5. Cookies</a></li>
<li class="mb-2"><a href="#responsabilite">6. Limitation de responsabilité</a></li> <li class="mb-2"><a href="#responsabilite">6. Limitation de responsabilité</a></li>
<li class="mb-2"><a href="#liens">7. Liens hypertextes</a></li> <li class="mb-2"><a href="#liens">7. Liens hypertextes</a></li>
<li class="mb-2"><a href="#droit">8. Droit applicable</a></li> <li class="mb-2"><a href="#droit">8. Droit applicable</a></li>
</ul> </ul>
</nav> </nav>
<!-- Section 1 : Éditeur --> <!-- Section 1 : Éditeur -->
<section id="editeur" class="legal-section" aria-labelledby="editeur-heading"> <section id="editeur" class="legal-section" aria-labelledby="editeur-heading">
<h3 id="editeur-heading" class="h4"> <h3 id="editeur-heading" class="h4">
<i class="fas fa-building me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-building me-2 text-primary" aria-hidden="true"></i>
1. Éditeur du site 1. Éditeur du site
</h3> </h3>
<p class="text-muted"> <p class="text-muted">
FOLLIOW est un <strong>projet pédagogique</strong> réalisé dans le cadre dun exercice de formation. FOLLIOW est un <strong>projet pédagogique</strong> réalisé dans le cadre dun exercice de formation.
</p> </p>
<dl class="row"> <dl class="row">
<dt class="col-sm-3">Nom du projet</dt> <dt class="col-sm-3">Nom du projet</dt>
<dd class="col-sm-9">FOLLIOW</dd> <dd class="col-sm-9">FOLLIOW</dd>
<dt class="col-sm-3">Nature</dt> <dt class="col-sm-3">Nature</dt>
<dd class="col-sm-9">Projet scolaire / démonstration technique</dd> <dd class="col-sm-9">Projet scolaire / démonstration technique</dd>
<dt class="col-sm-3">Établissement</dt> <dt class="col-sm-3">Établissement</dt>
<dd class="col-sm-9">FOLLIOW</dd> <dd class="col-sm-9">FOLLIOW</dd>
<dt class="col-sm-3">Forme juridique</dt> <dt class="col-sm-3">Forme juridique</dt>
<dd class="col-sm-9">Non applicable (projet pédagogique)</dd> <dd class="col-sm-9">Non applicable (projet pédagogique)</dd>
<dt class="col-sm-3">Capital social</dt> <dt class="col-sm-3">Capital social</dt>
<dd class="col-sm-9">Non applicable</dd> <dd class="col-sm-9">Non applicable</dd>
<dt class="col-sm-3">Adresse</dt> <dt class="col-sm-3">Adresse</dt>
<dd class="col-sm-9">4 Rue du Rhin, 68000 Colmar</dd> <dd class="col-sm-9">4 Rue du Rhin, 68000 Colmar</dd>
<dt class="col-sm-3">Téléphone</dt> <dt class="col-sm-3">Téléphone</dt>
<dd class="col-sm-9">03 68 67 20 00</dd> <dd class="col-sm-9">03 68 67 20 00</dd>
<dt class="col-sm-3">Email</dt> <dt class="col-sm-3">Email</dt>
<dd class="col-sm-9"> <dd class="col-sm-9">
<a href="mailto:projet.folliow@hotmail.com">projet.folliow@hotmail.com</a> <a href="mailto:projet.folliow@hotmail.com">projet.folliow@hotmail.com</a>
</dd> </dd>
<dt class="col-sm-3">Directeur de publication</dt> <dt class="col-sm-3">Directeur de publication</dt>
<dd class="col-sm-9">Léquipe du projet FOLLIOW</dd> <dd class="col-sm-9">Léquipe du projet FOLLIOW</dd>
<dt class="col-sm-3">SIRET</dt> <dt class="col-sm-3">SIRET</dt>
<dd class="col-sm-9">Non applicable (projet scolaire)</dd> <dd class="col-sm-9">Non applicable (projet scolaire)</dd>
</dl> </dl>
</section> </section>
<!-- Section 2 : Hébergeur --> <!-- Section 2 : Hébergeur -->
<section id="hebergeur" class="legal-section" aria-labelledby="hebergeur-heading"> <section id="hebergeur" class="legal-section" aria-labelledby="hebergeur-heading">
<h3 id="hebergeur-heading" class="h4"> <h3 id="hebergeur-heading" class="h4">
<i class="fas fa-server me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-server me-2 text-primary" aria-hidden="true"></i>
2. Hébergement 2. Hébergement
</h3> </h3>
<p>Le site est hébergé sur une infrastructure pédagogique mise à disposition pour le projet :</p> <p>Le site est hébergé sur une infrastructure pédagogique mise à disposition pour le projet :</p>
<dl class="row"> <dl class="row">
<dt class="col-sm-3">Hébergeur</dt> <dt class="col-sm-3">Hébergeur</dt>
<dd class="col-sm-9">OVH<dd> <dd class="col-sm-9">OVH<dd>
<dt class="col-sm-3">Domaine / accès</dt> <dt class="col-sm-3">Domaine / accès</dt>
<dd class="col-sm-9">php.boulayoune.com</dd> <dd class="col-sm-9">php.boulayoune.com</dd>
<dt class="col-sm-3">Adresse</dt> <dt class="col-sm-3">Adresse</dt>
<dd class="col-sm-9">4 Rue du Rhin, 68000 Colmar</dd> <dd class="col-sm-9">4 Rue du Rhin, 68000 Colmar</dd>
<dt class="col-sm-3">Téléphone</dt> <dt class="col-sm-3">Téléphone</dt>
<dd class="col-sm-9">03 68 67 20 00</dd> <dd class="col-sm-9">03 68 67 20 00</dd>
</dl> </dl>
</section> </section>
<!-- Section 3 : Propriété intellectuelle --> <!-- Section 3 : Propriété intellectuelle -->
<section id="propriete" class="legal-section" aria-labelledby="propriete-heading"> <section id="propriete" class="legal-section" aria-labelledby="propriete-heading">
<h3 id="propriete-heading" class="h4"> <h3 id="propriete-heading" class="h4">
<i class="fas fa-copyright me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-copyright me-2 text-primary" aria-hidden="true"></i>
3. Propriété intellectuelle 3. Propriété intellectuelle
</h3> </h3>
<p> <p>
Sauf mention contraire, lensemble des contenus présents sur FOLLIOW (textes, visuels, logo, éléments dinterface) Sauf mention contraire, lensemble des contenus présents sur FOLLIOW (textes, visuels, logo, éléments dinterface)
est utilisé dans le cadre du projet et reste la propriété de leurs auteurs respectifs. est utilisé dans le cadre du projet et reste la propriété de leurs auteurs respectifs.
</p> </p>
<p> <p>
Toute reproduction ou réutilisation à des fins commerciales est interdite sans autorisation préalable. Toute reproduction ou réutilisation à des fins commerciales est interdite sans autorisation préalable.
</p> </p>
<p> <p>
Les éventuels contenus tiers (images, icônes, bibliothèques) restent soumis à leurs licences dorigine. Les éventuels contenus tiers (images, icônes, bibliothèques) restent soumis à leurs licences dorigine.
</p> </p>
</section> </section>
<!-- Section 4 : RGPD --> <!-- Section 4 : RGPD -->
<section id="rgpd" class="legal-section" aria-labelledby="rgpd-heading"> <section id="rgpd" class="legal-section" aria-labelledby="rgpd-heading">
<h3 id="rgpd-heading" class="h4"> <h3 id="rgpd-heading" class="h4">
<i class="fas fa-shield-alt me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-shield-alt me-2 text-primary" aria-hidden="true"></i>
4. Protection des données personnelles (RGPD) 4. Protection des données personnelles (RGPD)
</h3> </h3>
<h4 class="h5 mt-4">4.1 Responsable du traitement</h4> <h4 class="h5 mt-4">4.1 Responsable du traitement</h4>
<p> <p>
Le responsable du traitement est léquipe du projet FOLLIOW (projet pédagogique). Le responsable du traitement est léquipe du projet FOLLIOW (projet pédagogique).
</p> </p>
<h4 class="h5 mt-4">4.2 Données collectées</h4> <h4 class="h5 mt-4">4.2 Données collectées</h4>
<p>Selon lutilisation du site, les données pouvant être collectées sont :</p> <p>Selon lutilisation du site, les données pouvant être collectées sont :</p>
<ul> <ul>
<li>Nom / Prenom <li> <li>Nom / Prenom <li>
<li>Pseudo </li> <li>Pseudo </li>
<li>Adresse email (inscription, connexion, partage de projet par email)</li> <li>Adresse email (inscription, connexion, partage de projet par email)</li>
<li>Contenus déposés par lutilisateur (projets, descriptions, images)</li> <li>Contenus déposés par lutilisateur (projets, descriptions, images)</li>
<li>Données techniques minimales (logs de sécurité, adresse IP) à des fins de protection et de diagnostic</li> <li>Données techniques minimales (logs de sécurité, adresse IP) à des fins de protection et de diagnostic</li>
</ul> </ul>
<h4 class="h5 mt-4">4.3 Finalités du traitement</h4> <h4 class="h5 mt-4">4.3 Finalités du traitement</h4>
<ul> <ul>
<li>Création et gestion de compte</li> <li>Création et gestion de compte</li>
<li>Publication et affichage de projets</li> <li>Publication et affichage de projets</li>
<li>Partage dun projet par email à la demande de lutilisateur</li> <li>Partage dun projet par email à la demande de lutilisateur</li>
<li>Sécurisation du site et prévention des abus</li> <li>Sécurisation du site et prévention des abus</li>
</ul> </ul>
<h4 class="h5 mt-4">4.4 Durée de conservation</h4> <h4 class="h5 mt-4">4.4 Durée de conservation</h4>
<p> <p>
Dans le cadre de ce projet pédagogique, les données sont conservées pendant la durée du projet et des évaluations, Dans le cadre de ce projet pédagogique, les données sont conservées pendant la durée du projet et des évaluations,
puis supprimées ou anonymisées, sauf obligation légale contraire. puis supprimées ou anonymisées, sauf obligation légale contraire.
</p> </p>
<h4 class="h5 mt-4">4.5 Vos droits</h4> <h4 class="h5 mt-4">4.5 Vos droits</h4>
<p>Conformément au RGPD, vous disposez de droits daccès, de rectification, deffacement et dopposition.</p> <p>Conformément au RGPD, vous disposez de droits daccès, de rectification, deffacement et dopposition.</p>
<p> <p>
Pour exercer ces droits, contactez-nous à : Pour exercer ces droits, contactez-nous à :
<a href="mailto:projet.folliow@hotmail.com">projet.folliow@hotmail.com</a> <a href="mailto:projet.folliow@hotmail.com">projet.folliow@hotmail.com</a>
</p> </p>
<p> <p>
Vous pouvez également introduire une réclamation auprès de la CNIL Vous pouvez également introduire une réclamation auprès de la CNIL
(<a href="https://www.cnil.fr" target="_blank" rel="noopener">www.cnil.fr</a>). (<a href="https://www.cnil.fr" target="_blank" rel="noopener">www.cnil.fr</a>).
</p> </p>
</section> </section>
<!-- Section 5 : Cookies --> <!-- Section 5 : Cookies -->
<section id="cookies" class="legal-section" aria-labelledby="cookies-heading"> <section id="cookies" class="legal-section" aria-labelledby="cookies-heading">
<h3 id="cookies-heading" class="h4"> <h3 id="cookies-heading" class="h4">
<i class="fas fa-cookie-bite me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-cookie-bite me-2 text-primary" aria-hidden="true"></i>
5. Cookies 5. Cookies
</h3> </h3>
<p> <p>
FOLLIOW peut utiliser des cookies <strong>strictement nécessaires</strong> au fonctionnement du site FOLLIOW peut utiliser des cookies <strong>strictement nécessaires</strong> au fonctionnement du site
(ex : session de connexion). Aucun cookie publicitaire nest utilisé. (ex : session de connexion). Aucun cookie publicitaire nest utilisé.
</p> </p>
<h4 class="h5 mt-4">5.1 Quest-ce quun cookie ?</h4> <h4 class="h5 mt-4">5.1 Quest-ce quun cookie ?</h4>
<p> <p>
Un cookie est un petit fichier texte déposé sur votre appareil lors de la visite dun site. Un cookie est un petit fichier texte déposé sur votre appareil lors de la visite dun site.
Il permet notamment de conserver une session ou des préférences. Il permet notamment de conserver une session ou des préférences.
</p> </p>
<h4 class="h5 mt-4">5.2 Types de cookies utilisés</h4> <h4 class="h5 mt-4">5.2 Types de cookies utilisés</h4>
<ul> <ul>
<li><strong>Cookies techniques</strong> : indispensables (session, sécurité)</li> <li><strong>Cookies techniques</strong> : indispensables (session, sécurité)</li>
<li><strong>Cookies de préférence</strong> : éventuels (langue, affichage) si implémentés</li> <li><strong>Cookies de préférence</strong> : éventuels (langue, affichage) si implémentés</li>
</ul> </ul>
<h4 class="h5 mt-4">5.3 Gestion des cookies</h4> <h4 class="h5 mt-4">5.3 Gestion des cookies</h4>
<p> <p>
Vous pouvez configurer votre navigateur pour refuser les cookies. Certaines fonctionnalités du site Vous pouvez configurer votre navigateur pour refuser les cookies. Certaines fonctionnalités du site
peuvent alors ne pas fonctionner correctement. peuvent alors ne pas fonctionner correctement.
</p> </p>
</section> </section>
<!-- Section 6 : Limitation de responsabilité --> <!-- Section 6 : Limitation de responsabilité -->
<section id="responsabilite" class="legal-section" aria-labelledby="responsabilite-heading"> <section id="responsabilite" class="legal-section" aria-labelledby="responsabilite-heading">
<h3 id="responsabilite-heading" class="h4"> <h3 id="responsabilite-heading" class="h4">
<i class="fas fa-exclamation-triangle me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-exclamation-triangle me-2 text-primary" aria-hidden="true"></i>
6. Limitation de responsabilité 6. Limitation de responsabilité
</h3> </h3>
<p> <p>
Les informations présentées sur FOLLIOW sont fournies à titre démonstratif dans le cadre dun projet pédagogique. Les informations présentées sur FOLLIOW sont fournies à titre démonstratif dans le cadre dun projet pédagogique.
Léquipe sefforce de maintenir le site accessible, sans garantie dabsence derreurs ou dinterruptions. Léquipe sefforce de maintenir le site accessible, sans garantie dabsence derreurs ou dinterruptions.
</p> </p>
<p> <p>
Léquipe FOLLIOW ne pourra être tenue responsable des dommages directs ou indirects résultant de lutilisation du site, Léquipe FOLLIOW ne pourra être tenue responsable des dommages directs ou indirects résultant de lutilisation du site,
notamment en cas dindisponibilité ou de perte de données. notamment en cas dindisponibilité ou de perte de données.
</p> </p>
</section> </section>
<!-- Section 7 : Liens hypertextes --> <!-- Section 7 : Liens hypertextes -->
<section id="liens" class="legal-section" aria-labelledby="liens-heading"> <section id="liens" class="legal-section" aria-labelledby="liens-heading">
<h3 id="liens-heading" class="h4"> <h3 id="liens-heading" class="h4">
<i class="fas fa-link me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-link me-2 text-primary" aria-hidden="true"></i>
7. Liens hypertextes 7. Liens hypertextes
</h3> </h3>
<p> <p>
Le site peut contenir des liens vers des sites tiers. FOLLIOW nexerce aucun contrôle sur ces sites et décline toute Le site peut contenir des liens vers des sites tiers. FOLLIOW nexerce aucun contrôle sur ces sites et décline toute
responsabilité quant à leur contenu ou leur disponibilité. responsabilité quant à leur contenu ou leur disponibilité.
</p> </p>
</section> </section>
<!-- Section 8 : Droit applicable --> <!-- Section 8 : Droit applicable -->
<section id="droit" class="legal-section" aria-labelledby="droit-heading"> <section id="droit" class="legal-section" aria-labelledby="droit-heading">
<h3 id="droit-heading" class="h4"> <h3 id="droit-heading" class="h4">
<i class="fas fa-gavel me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-gavel me-2 text-primary" aria-hidden="true"></i>
8. Droit applicable et juridiction compétente 8. Droit applicable et juridiction compétente
</h3> </h3>
<p> <p>
Les présentes mentions légales sont régies par le droit français. En cas de litige, et à défaut daccord amiable, Les présentes mentions légales sont régies par le droit français. En cas de litige, et à défaut daccord amiable,
les tribunaux français seront seuls compétents. les tribunaux français seront seuls compétents.
</p> </p>
</section> </section>
<!-- Contact --> <!-- Contact -->
<section class="mt-5 p-4 bg-light rounded" aria-labelledby="contact-legal"> <section class="mt-5 p-4 bg-light rounded" aria-labelledby="contact-legal">
<h3 id="contact-legal" class="h4 mb-3"> <h3 id="contact-legal" class="h4 mb-3">
<i class="fas fa-envelope me-2 text-primary" aria-hidden="true"></i> <i class="fas fa-envelope me-2 text-primary" aria-hidden="true"></i>
Questions ou réclamations Questions ou réclamations
</h3> </h3>
<p> <p>
Pour toute question concernant ces mentions légales ou pour exercer vos droits, vous pouvez nous contacter : Pour toute question concernant ces mentions légales ou pour exercer vos droits, vous pouvez nous contacter :
</p> </p>
<ul class="list-unstyled"> <ul class="list-unstyled">
<li class="mb-2"> <li class="mb-2">
<i class="fas fa-envelope me-2" aria-hidden="true"></i> <i class="fas fa-envelope me-2" aria-hidden="true"></i>
Par email : <a href="mailto:projet.folliow@hotmail.com">projet.folliow@hotmail.com</a> Par email : <a href="mailto:projet.folliow@hotmail.com">projet.folliow@hotmail.com</a>
</li> </li>
</ul> </ul>
</section> </section>
</div> </div>
</div> </div>
</section> </section>
{/block} {/block}

View file

@ -21,7 +21,7 @@
{$arrProject.category_name ?? 'Général'} {$arrProject.category_name ?? 'Général'}
</p> </p>
<div class="mb-4 shadow-sm {if !($smarty.env.IMG_PROJECT_PATH|cat:$objProject->getThumbnail())|file_exists}d-none{/if}" > <div class="mb-4 shadow-sm">
<img src="{$smarty.env.IMG_PROJECT_PATH}{$objProject->getThumbnail()}" <img src="{$smarty.env.IMG_PROJECT_PATH}{$objProject->getThumbnail()}"
class="img-fluid rounded w-100"> class="img-fluid rounded w-100">
</div> </div>
@ -30,7 +30,7 @@
<h4 class="border-bottom pb-2">Description</h4> <h4 class="border-bottom pb-2">Description</h4>
<p class="lead">{$objProject->getDescription()}</p> <p class="lead">{$objProject->getDescription()}</p>
<div class="mt-4" style="white-space: pre-wrap;"> <div class="mt-4">
{$objProject->getContent()} {$objProject->getContent()}
</div> </div>
</div> </div>
@ -42,10 +42,10 @@
<div class="row"> <div class="row">
{foreach $arrImages as $image} {foreach $arrImages as $image}
{* On affiche l'image si elle est approuvée OU si l'utlilisateur possède le projet OU si l'utlilisateur est Modérateur ET que l'image est disponible sur le serveur*} {* On affiche l'image si elle est approuvée OU si l'utlilisateur possède le projet OU si l'utlilisateur est Modérateur*}
{if (($image.image_status == 'approuvé') || {if ($image.image_status == 'approuvé') ||
(isset($smarty.session.user) && $smarty.session.user.user_status == 2) || (isset($smarty.session.user) && $smarty.session.user.user_status == 2) ||
(isset($smarty.session.user) && $smarty.session.user.user_id == $objProject->getUser_id())) && (($smarty.env.IMG_PROJECT_PATH|cat:$objProject->getThumbnail())|file_exists)} (isset($smarty.session.user) && $smarty.session.user.user_id == $objProject->getUser_id())}
<div class="col-md-4 mb-4"> <div class="col-md-4 mb-4">
<div class="card {if $image.image_status != 'approuvé'}border-warning shadow-none opacity-75{/if}"> <div class="card {if $image.image_status != 'approuvé'}border-warning shadow-none opacity-75{/if}">
@ -99,7 +99,7 @@
<div class="col-lg-4"> <div class="col-lg-4">
<div class="card text-center shadow-sm p-4"> <div class="card text-center shadow-sm p-4">
<a href="index.php?ctrl=user&action=user&id={$objProject->getUser_id()}" class="text-decoration-none text-dark"> <a href="index.php?ctrl=user&action=user&id={$objProject->getUser_id()}" class="text-decoration-none text-dark">
<img src="{$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($objProject->getUser_image()))|file_exists}{$objProject->getUser_image()}{else}images.jpg{/if}" <img src="{$smarty.env.IMG_USER_PATH}{$objProject->getUser_image() ?? "images.jpg"}"
class="rounded-circle mb-3 mx-auto" class="rounded-circle mb-3 mx-auto"
style="width:100px;height:100px;object-fit:cover;"> style="width:100px;height:100px;object-fit:cover;">
</a> </a>

View file

@ -1,33 +1,35 @@
{extends file="views/layout.tpl"} {extends file="views/layout.tpl"}
{block name="title" append} - Rechercher{/block} {block name="title" append} - Rechercher{/block}
{block name="h2"}Rechercher{/block}
{block name="p"}Recherche de projets par mot clés, date, auteur et catégorie.{/block}
{block name="content"} {block name="content"}
<section aria-label="Blog"> <section aria-label="Blog">
<h2 class="visually-hidden">Rechercher parmi les projets</h2> <h2 class="visually-hidden">Rechercher parmi les articles</h2>
<div class="row mb-2"> <div class="row mb-2">
<section class="mb-5" aria-labelledby="search-heading"> <section class="mb-5" aria-labelledby="search-heading">
<form name="formSearch" method="post" action="?ctrl=project&action=search" class="border rounded p-4 bg-light"> <form name="formSearch" method="post" action="?ctrl=project&action=search" class="border rounded p-4 bg-light">
<h3 id="search-heading" class="h4 mb-4"> <h3 id="search-heading" class="h4 mb-4">
<i class="fas fa-search me-2" aria-hidden="true"></i> <i class="fas fa-search me-2" aria-hidden="true"></i>
Rechercher des projets Rechercher des articles
</h3> </h3>
<div class="row g-3"> <div class="row g-3">
<div class="col-md-6"> <div class="col-md-6">
<label for="keywords" class="form-label">Mots-clés</label> <label for="keywords" class="form-label">Mots-clés</label>
<input <input
value="{$strKeywords}" type="text" class="form-control" id="keywords" name="keywords" placeholder="Design, IA, back-end" aria-describedby="keywords-help"> value=""
type="text"
class="form-control"
id="keywords"
name="keywords"
placeholder="Design, IA, back-end"
aria-describedby="keywords-help">
<small id="keywords-help" class="form-text text-muted"> <small id="keywords-help" class="form-text text-muted">
Recherchez dans les titres et contenus Recherchez dans les titres et contenus
</small> </small>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<label for="author" class="form-label">Auteurs</label> <label for="author" class="form-label">Auteur</label>
<select class="form-select" id="author" name="author"> <select class="form-select" id="author" name="author">
<option value="0" {if $intAuthor == 0}selected{/if}>Tous les auteurs</option> <option value="0" {if $intAuthor == 0}selected{/if}>Tous les auteurs</option>
{foreach $arrUser as $arrDetUser} {foreach $arrUser as $arrDetUser}
@ -111,6 +113,7 @@
</div> </div>
</div> </div>
</div> </div>
<!-- AJOUT RECHERCHE PAR CATEGORIE -->
<div class="col-6"> <div class="col-6">
<fieldset> <fieldset>
<legend class="form-label">Recherche par catégories</legend> <legend class="form-label">Recherche par catégories</legend>
@ -143,6 +146,7 @@
</form> </form>
</section> </section>
<!-- Liste des articles -->
<section aria-labelledby="articles-heading"> <section aria-labelledby="articles-heading">
<h3 id="articles-heading" class="visually-hidden">Liste des projets</h3> <h3 id="articles-heading" class="visually-hidden">Liste des projets</h3>
<div class="row mb-2"> <div class="row mb-2">
@ -151,26 +155,15 @@
<p>Pas de résultats</p> <p>Pas de résultats</p>
</div> </div>
{/if} {/if}
{foreach from=$arrProjectToDisplay item=objProject} {foreach $arrProjectToDisplay as $objProject}
{include file="views/_partial/preview.tpl"}
{assign var="isAuthor" value=(isset($smarty.session.user) && $smarty.session.user.user_id == $objProject->getUser_id())} {/foreach}
{assign var="isModerator" value=(isset($smarty.session.user) && $smarty.session.user.user_status == 2)}
{assign var="isDeleted" value=($objProject->getProject_deleted_at() !== null)}
{assign var="isRefused" value=($objProject->getStatus() == "refusé")}
{if $isModerator
|| ($isAuthor && !$isDeleted)
|| (!$isRefused && !$isDeleted)}
{include file="views/_partial/preview.tpl"}
{/if}
{/foreach}
</div> </div>
</section> </section>
</div> </div>
</section> </section>
<script> <script>
// Gestion de l'affichage des champs de date
const periodRadios = document.querySelectorAll('input[name="period"]'); const periodRadios = document.querySelectorAll('input[name="period"]');
const dateExact = document.getElementById('date-exact'); const dateExact = document.getElementById('date-exact');
const dateRange = document.getElementById('date-range'); const dateRange = document.getElementById('date-range');
@ -190,6 +183,8 @@
periodRadios.forEach(radio => { periodRadios.forEach(radio => {
radio.addEventListener('change', toggleDateFields); radio.addEventListener('change', toggleDateFields);
}); });
// Initialisation au chargement
toggleDateFields(); toggleDateFields();
</script> </script>
{/block} {/block}

View file

@ -5,7 +5,7 @@
<section class="user-profile mb-5 mt-5/*vh /*"> <section class="user-profile mb-5 mt-5/*vh /*">
<div class="row"> <div class="row">
<div class="col-md-4 text-center"> <div class="col-md-4 text-center">
<img src="{$smarty.env.IMG_USER_PATH}{if ($smarty.env.IMG_USER_PATH|cat:($user->getImage()))|file_exists}{$user->getImage()}{else}images.jpg{/if}" alt="Avatar de {$user->getPseudo()}" class="rounded-circle flex-shrink-0 border border-2 border-white" <img src="{$smarty.env.IMG_USER_PATH}{$user->getImage() ?? "images.jpg"}" alt="Avatar de {$user->getPseudo()}" class="rounded-circle flex-shrink-0 border border-2 border-white"
style="width: 256px; height: 256px; object-fit: cover; margin-top: 8px;" style="width: 256px; height: 256px; object-fit: cover; margin-top: 8px;"
> >
</div> </div>