updated this branch comparing to the branch soutenance + added the edit of a team
continuous-integration/drone/push Build is failing Details

pull/84/head
Maël DAIM 1 year ago
parent 5aa6a76027
commit dcf118d12b

@ -5,7 +5,7 @@
height: 100%;
}
header{
header {
display: flex;
justify-content: center;
background-color: #525252;
@ -13,7 +13,7 @@ header{
margin-bottom: 5px;
}
header h1 a{
header h1 a {
color: orange;
text-decoration: none;
font-size: 1.5em;
@ -22,33 +22,34 @@ header h1 a{
.square {
width: 50px;
height: 50px;
border: 2px white solid;
}
#main_color {
border: solid;
}
#teamInfo{
#teamInfo {
display: flex;
flex-direction: column;
align-items: center;
width: 60%;
background-color: #8F8F8F;
background-color: #8f8f8f;
padding-bottom: 10px;
border-radius: 10px;
}
#firstPart{
#firstPart {
display: flex;
flex-direction: column;
align-items: center;
}
#teamName{
#teamName {
font-size: 2.8em;
}
#colors{
#colors {
display: flex;
flex-direction: column;
}
@ -57,7 +58,7 @@ header h1 a{
justify-content: space-between;
}
#colorsTitle{
#colorsTitle {
width: 110%;
display: flex;
flex-direction: row;
@ -66,54 +67,61 @@ header h1 a{
color: white;
}
#actualColors{
#actualColors {
display: flex;
flex-direction: row;
justify-content: space-around;
}
#logo {
width: 90%;
aspect-ratio: 3/2;
object-fit: contain;
max-width: 50%;
max-height: 50%;
max-width: 70%;
max-height: 70%;
}
#delete{
border-radius:10px ;
#delete {
border-radius: 10px;
background-color: red;
color: white;
margin-top: 10px;
margin-bottom: 10px;
margin-right: 5px;
}
#headMembers{
#edit{
border-radius: 10px;
background-color: orange;
color: white;
margin-top: 10px;
margin-bottom: 10px;
}
#headMembers {
width: 33%;
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
#addMember{
#addMember {
height: 30px;
aspect-ratio: 1/1;
border-radius: 100%;
align-self: center;
}
#Members{
#Members {
display: flex;
flex-direction: column;
background-color: #BCBCBC;
background-color: #bcbcbc;
width: 60%;
align-items: center;
justify-content: space-around;
border-radius: 10px;
}
.Member{
.Member {
width: 60%;
background-color: white;
display: flex;
@ -123,11 +131,9 @@ header h1 a{
border-radius: 10px;
margin-top: 5px;
margin-bottom: 5px;
}
#profilePicture{
height:40px;
width:40px;
}
#profilePicture {
height: 40px;
width: 40px;
}

@ -1,24 +1,38 @@
import '../style/team_panel.css';
import {BASE} from "../Constants";
import {Team,TeamInfo,Color,User,Member} from "../model/Team/Team"
import "../style/team_panel.css"
import { BASE } from "../Constants"
import { Team, TeamInfo, Color, User, Member } from "../model/team/Team"
export default function TeamPanel({isCoach, team,currentUserId}: {isCoach: boolean, team: Team,currentUserId:number}){
export default function TeamPanel({
isCoach,
team,
currentUserId,
}: {
isCoach: boolean
team: Team
currentUserId: number
}) {
return (
<div id="mainDiv">
<header>
<h1><a href="/" >IQBall</a></h1>
<h1>
<a href={BASE + "/"}>IQBall</a>
</h1>
</header>
<TeamDisplay team={team.info}/>
<TeamDisplay team={team.info} />
{isCoach && <CoachOptions id={team.info.id}/>}
{isCoach && <CoachOptions id={team.info.id} />}
<MembersDisplay members={team.members} isCoach={isCoach} idTeam={team.info.id} currentUserId={currentUserId}/>
<MembersDisplay
members={team.members}
isCoach={isCoach}
idTeam={team.info.id}
currentUserId={currentUserId}
/>
</div>
)
}
function TeamDisplay({ team}: {team : TeamInfo}) {
function TeamDisplay({ team }: { team: TeamInfo }) {
return (
<div id="teamInfo">
<div id="firstPart">
@ -31,53 +45,124 @@ function TeamDisplay({ team}: {team : TeamInfo}) {
<p>Couleur secondaire</p>
</div>
<div id="actualColors">
<ColorDisplay color={team.mainColor}/>
<ColorDisplay color={team.secondColor}/>
<ColorDisplay color={team.mainColor} />
<ColorDisplay color={team.secondColor} />
</div>
</div>
</div>
)
}
function ColorDisplay({color}: {color : Color}){
return(
<div className="square" style={{backgroundColor: color.hex}}/>
)
function ColorDisplay({ color }: { color: Color }) {
return <div className="square" style={{ backgroundColor: color.hex }} />
}
function CoachOptions ({id}:{id:number}){
function CoachOptions({ id }: { id: number }) {
return (
<div>
<button id="delete" onClick={()=>confirm('Êtes-vous sûr de supprimer cette équipe?') ? window.location.href=`${BASE}/team/${id}/delete` : {}}>Supprimer</button>
<button
id="delete"
onClick={() =>
confirm("Êtes-vous sûr de supprimer cette équipe?")
? (window.location.href = `${BASE}/team/${id}/delete`)
: {}
}>
Supprimer
</button>
<button
id="edit"
onClick={() =>
(window.location.href = `${BASE}/team/${id}/edit`)
}>
Modifier
</button>
</div>
)
}
function MembersDisplay({members,isCoach,idTeam,currentUserId}:{members : Member[], isCoach : boolean,idTeam : number,currentUserId:number}){
const listMember = members.map((member) =>
<MemberDisplay member={member} isCoach={isCoach} idTeam={idTeam} currentUserId={currentUserId}/>
);
function MembersDisplay({
members,
isCoach,
idTeam,
currentUserId,
}: {
members: Member[]
isCoach: boolean
idTeam: number
currentUserId: number
}) {
const listMember = members.map((member) => (
<MemberDisplay
member={member}
isCoach={isCoach}
idTeam={idTeam}
currentUserId={currentUserId}
/>
))
return (
<div id="Members">
<div id="headMembers">
<h2>Membres :</h2>
{isCoach && <button id="addMember" onClick={()=> window.location.href=`${BASE}/team/${idTeam}/addMember`}>+</button>}
{isCoach && (
<button
id="addMember"
onClick={() =>
(window.location.href = `${BASE}/team/${idTeam}/addMember`)
}>
+
</button>
)}
</div>
{listMember}
</div>
)
}
function MemberDisplay({member,isCoach,idTeam,currentUserId}: {member : Member,isCoach : boolean,idTeam:number,currentUserId:number}){
function MemberDisplay({
member,
isCoach,
idTeam,
currentUserId,
}: {
member: Member
isCoach: boolean
idTeam: number
currentUserId: number
}) {
return (
<div className="Member">
<img id="profilePicture" src={member.user.profilePicture} alt="Photo de profile"/>
<img
id="profilePicture"
src={member.user.profilePicture}
alt="Photo de profile"
/>
<p>{member.user.name}</p>
<p>{member.role}</p>
<p>{member.user.email}</p>
{isCoach && currentUserId !== member.user.id && <button id="delete" onClick={()=>confirm("Êtes-vous sûr de retirer ce membre de l'équipe?") ? window.location.href=`${BASE}/team/${idTeam}/remove/${member.user.id}` : {}}>Retirer</button>}
{isCoach && currentUserId == member.user.id && <button id="delete" onClick={()=>confirm("Êtes-vous sûr de quitter cette équipe?") ? window.location.href=`${BASE}/team/${idTeam}/remove/${member.user.id}` : {}}>Quitter</button>}
{isCoach && currentUserId !== member.user.id && (
<button
id="delete"
onClick={() =>
confirm(
"Êtes-vous sûr de retirer ce membre de l'équipe?",
)
? (window.location.href = `${BASE}/team/${idTeam}/remove/${member.user.id}`)
: {}
}>
Retirer
</button>
)}
{isCoach && currentUserId == member.user.id && (
<button
id="delete"
onClick={() =>
confirm("Êtes-vous sûr de quitter cette équipe?")
? (window.location.href = `${BASE}/team/${idTeam}/remove/${member.user.id}`)
: {}
}>
Quitter
</button>
)}
</div>
)
}
}

@ -1,6 +1,5 @@
<?php
require "../vendor/autoload.php";
require "../config.php";
require "../sql/database.php";
@ -39,7 +38,7 @@ function getConnection(): Connection {
}
function getUserController(): UserController {
return new UserController(new TacticModel(new TacticInfoGateway(getConnection())));
return new UserController(new TacticModel(new TacticInfoGateway(getConnection())), new TeamModel(new TeamGateway(getConnection()), new MemberGateway(getConnection()), new AccountGateway(getConnection())));
}
function getVisualizerController(): VisualizerController {
@ -103,10 +102,13 @@ function getRoutes(): AltoRouter {
$ar->map("GET", "/team/search", Action::auth(fn(SessionHandle $s) => getTeamController()->displayListTeamByName($s)));
$ar->map("POST", "/team/search", Action::auth(fn(SessionHandle $s) => getTeamController()->listTeamByName($_POST, $s)));
$ar->map("GET", "/team/[i:id]", Action::auth(fn(int $id, SessionHandle $s) => getTeamController()->displayTeam($id, $s)));
$ar->map("GET", "/team/[i:id]/delete", Action::auth(fn(int $id,SessionHandle $s) => getTeamController()->deleteTeamById($id,$s)));
$ar->map("GET", "/team/[i:id]/addMember", Action::auth(fn(int $id,SessionHandle $s) => getTeamController()->displayAddMember($id,$s)));
$ar->map("POST", "/team/[i:id]/addMember", Action::auth(fn(int $id,SessionHandle $s) => getTeamController()->addMember($id,$_POST, $s)));
$ar->map("GET", "/team/[i:idTeam]/remove/[i:idMember]", Action::auth(fn(int $idTeam,int $idMember,SessionHandle $s) => getTeamController()->deleteMember($idTeam,$idMember, $s)));
$ar->map("GET", "/team/[i:id]/delete", Action::auth(fn(int $id, SessionHandle $s) => getTeamController()->deleteTeamById($id, $s)));
$ar->map("GET", "/team/[i:id]/addMember", Action::auth(fn(int $id, SessionHandle $s) => getTeamController()->displayAddMember($id, $s)));
$ar->map("POST", "/team/[i:id]/addMember", Action::auth(fn(int $id, SessionHandle $s) => getTeamController()->addMember($id, $_POST, $s)));
$ar->map("GET", "/team/[i:idTeam]/remove/[i:idMember]", Action::auth(fn(int $idTeam, int $idMember, SessionHandle $s) => getTeamController()->deleteMember($idTeam, $idMember, $s)));
$ar->map("GET", "/team/[i:id]/edit", Action::auth(fn(int $idTeam,SessionHandle $s) => getTeamController()->displayEditTeam($idTeam,$s)));
$ar->map("POST", "/team/[i:id]/edit", Action::auth(fn(int $idTeam,SessionHandle $s) => getTeamController()->editTeam($idTeam,$_POST,$s)));
return $ar;
}
@ -119,11 +121,10 @@ function runMatch($match, MutableSessionHandle $session): HttpResponse {
], HttpCodes::NOT_FOUND);
}
return App::runAction($basePath . '/login', $match['target'], $match['params'], $session);
return App::runAction('/login', $match['target'], $match['params'], $session);
}
//this is a global variable
$basePath = get_public_path(__DIR__);
App::render(runMatch(getRoutes()->match(), PhpSessionHandle::init()), fn() => getTwig());
App::render(runMatch(getRoutes()->match(), PhpSessionHandle::init()), fn() => getTwig());

@ -64,7 +64,7 @@ class TeamController {
}
$teamId = $this->model->createTeam($request['name'], $request['picture'], $request['main_color'], $request['second_color']);
$this->model->addMember($session->getAccount()->getUser()->getEmail(),$teamId,'COACH');
return ViewHttpResponse::redirect('/team/'.$teamId);
return HttpResponse::redirect('/team/'.$teamId);
}
/**
@ -101,6 +101,7 @@ class TeamController {
}
/**
* Delete a team with its id
* @param int $id
* @param SessionHandle $session
* @return HttpResponse
@ -111,10 +112,11 @@ class TeamController {
if($ret != 0){
return ViewHttpResponse::twig('display_team.html.twig',['notDeleted' => true]);
}
return ViewHttpResponse::redirect('/');
return HttpResponse::redirect('/');
}
/**
* Display a team with its id
* @param int $id
* @param SessionHandle $session
* @return ViewHttpResponse a view that displays given team information
@ -141,6 +143,7 @@ class TeamController {
}
/**
* @param int $idTeam
* @param SessionHandle $session
* @return ViewHttpResponse the team panel to add a member
*/
@ -150,6 +153,7 @@ class TeamController {
/**
* add a member to a team
* @param int $idTeam
* @param array<string, mixed> $request
* @param SessionHandle $session
* @return HttpResponse
@ -158,7 +162,7 @@ class TeamController {
$errors = [];
if(!$this->model->isCoach($idTeam,$session->getAccount()->getUser()->getEmail())){
return ViewHttpResponse::twig('error.html.twig', [
'failures' => [ValidationFail::unauthorized("Vous n'avez pas accès à cette équipe.")],
'failures' => [ValidationFail::unauthorized("Vous n'avez pas accès à cette action pour cette équipe.")],
], HttpCodes::FORBIDDEN);
}
$request = HttpRequest::from($request, $errors, [
@ -175,22 +179,68 @@ class TeamController {
case -2:
return ViewHttpResponse::twig('add_member.html.twig',['alreadyExisting' => true,'idTeam'=> $idTeam]);
default:
return ViewHttpResponse::redirect('/team/'.$idTeam);
return HttpResponse::redirect('/team/'.$idTeam);
}
}
/**
* remove a member from a team
* @param array<string, mixed> $request
* remove a member from a team with their ids
* @param int $idTeam
* @param int $idMember
* @param SessionHandle $session
* @return HttpResponse
*/
public function deleteMember(int $idTeam,int $idMember, SessionHandle $session): HttpResponse {
$ret = $this->model->deleteMember($idMember,$idTeam);
if($ret == -1 || $session->getAccount()->getUser()->getId() == $idMember ){
return ViewHttpResponse::redirect('/');
if(!$this->model->isCoach($idTeam,$session->getAccount()->getUser()->getEmail())){
return ViewHttpResponse::twig('error.html.twig', [
'failures' => [ValidationFail::unauthorized("Vous n'avez pas accès à cette action pour cette équipe.")],
], HttpCodes::FORBIDDEN);
}
return $this->displayTeam($ret,$session);
$teamId = $this->model->deleteMember($idMember,$idTeam);
if($teamId == -1 || $session->getAccount()->getUser()->getId() == $idMember ){
return HttpResponse::redirect('/');
}
return $this->displayTeam($teamId,$session);
}
/**
* @param int $idTeam
* @param SessionHandle $session
* @return ViewHttpResponse
*/
public function displayEditTeam(int $idTeam,SessionHandle $session): ViewHttpResponse {
return ViewHttpResponse::twig("edit_team.html.twig", ['team' => $this->model->getTeam($idTeam,$session->getAccount()->getUser()->getId())]);
}
/**
* @param int $idTeam
* @param array $request
* @param SessionHandle $session
* @return HttpResponse
*/
public function editTeam(int $idTeam,array $request,SessionHandle $session): HttpResponse{
if(!$this->model->isCoach($idTeam,$session->getAccount()->getUser()->getEmail())){
return ViewHttpResponse::twig('error.html.twig', [
'failures' => [ValidationFail::unauthorized("Vous n'avez pas accès à cette action pour cette équipe.")],
], HttpCodes::FORBIDDEN);
}
$failures = [];
$request = HttpRequest::from($request, $failures, [
"name" => [Validators::lenBetween(1, 32), Validators::nameWithSpaces()],
"main_color" => [Validators::hexColor()],
"second_color" => [Validators::hexColor()],
"picture" => [Validators::isURL()],
]);
if (!empty($failures)) {
$badFields = [];
foreach ($failures as $e) {
if ($e instanceof FieldValidationFail) {
$badFields[] = $e->getFieldName();
}
}
return ViewHttpResponse::twig('edit_team.html.twig', ['bad_fields' => $badFields]);
}
$this->model->editTeam($idTeam,$request['name'], $request['picture'], $request['main_color'], $request['second_color']);
return HttpResponse::redirect('/team/'.$idTeam);
}
}

@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Insertion view</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f1f1f1;
}
.container {
max-width: 400px;
margin: 5px auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h2 {
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
{% for item in bad_fields %}
#{{ item }}{
border-color: red;
}{% endfor %} input[type="text"], input[type="password"] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
input[type="submit"] {
background-color: #007bff;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
</style>
</head>
<body>
<div class="container">
<h2>Modifier votre équipe</h2>
<form action="{{ path('/team/' ~ team.getInfo().getId() ~ '/edit') }}" method="post">
<div class="form-group">
<label for="name">Nom de l'équipe :</label>
<input type="text" id="name" name="name" value="{{ team.getInfo().getName() }}" required>
<label for="picture">Logo:</label>
<input type="text" id="picture" name="picture" value="{{ team.getInfo().getPicture() }}" required>
<label for="main_color">Couleur principale</label>
<input type="color" value="{{ team.getInfo().getMainColor().getValue() }}" id="main_color" name="main_color" required>
<label for="second_color">Couleur secondaire</label>
<input type="color" id="second_color" name="second_color" value="{{ team.getInfo().getSecondColor().getValue() }}" required>
</div>
<div class="form-group">
<input type="submit" value="Confirmer">
</div>
</form>
</div>
</body>
</html>

@ -41,7 +41,7 @@ class MemberGateway {
*/
public function getMembersOfTeam(int $teamId): array {
$rows = $this->con->fetch(
"SELECT a.id,a.email,a.username,a.profilePicture,m.role FROM Account a,Team t,Member m WHERE t.id = :id AND m.id_team = t.id AND m.id_user = a.id",
"SELECT a.id,a.email,a.username,a.profilePicture,m.role FROM Account a,team t,Member m WHERE t.id = :id AND m.id_team = t.id AND m.id_user = a.id",
[
":id" => [$teamId, PDO::PARAM_INT],
]

@ -23,7 +23,7 @@ class TeamGateway {
*/
public function insert(string $name, string $picture, string $mainColor, string $secondColor): int {
$this->con->exec(
"INSERT INTO Team(name, picture, main_color, second_color) VALUES (:team_name , :picture, :main_color, :second_color)",
"INSERT INTO team(name, picture, main_color, second_color) VALUES (:team_name , :picture, :main_color, :second_color)",
[
":team_name" => [$name, PDO::PARAM_STR],
":picture" => [$picture, PDO::PARAM_STR],
@ -41,7 +41,7 @@ class TeamGateway {
*/
public function listByName(string $name,int $id): array {
$result = $this->con->fetch(
"SELECT t.* FROM Team t, Member m WHERE t.name LIKE '%' || :name || '%' AND t.id=m.id_team AND m.id_user=:id",
"SELECT t.* FROM team t, Member m WHERE t.name LIKE '%' || :name || '%' AND t.id=m.id_team AND m.id_user=:id",
[
":name" => [$name, PDO::PARAM_STR],
"id" => [$id, PDO::PARAM_INT]
@ -56,7 +56,7 @@ class TeamGateway {
*/
public function getTeamById(int $id): ?TeamInfo {
$row = $this->con->fetch(
"SELECT * FROM Team WHERE id = :id",
"SELECT * FROM team WHERE id = :id",
[
":id" => [$id, PDO::PARAM_INT],
]
@ -73,7 +73,7 @@ class TeamGateway {
*/
public function getTeamIdByName(string $name): ?int {
return $this->con->fetch(
"SELECT id FROM Team WHERE name = :name",
"SELECT id FROM team WHERE name = :name",
[
":name" => [$name, PDO::PARAM_INT],
]
@ -98,4 +98,30 @@ class TeamGateway {
);
}
/**
* @param int $idTeam
* @param string $newName
* @param string $newPicture
* @param string $newMainColor
* @param string $newSecondColor
* @return void
*/
public function editTeam(int $idTeam,string $newName,string $newPicture, string $newMainColor, string $newSecondColor){
$this->con->exec(
"UPDATE team
SET name = :newName,
picture = :newPicture,
main_color = :newMainColor,
second_color = :newSecondColor
WHERE id = :team",
[
"team" => [$idTeam, PDO::PARAM_INT],
"newName" => [$newName, PDO::PARAM_STR],
"newPicture" => [$newPicture, PDO::PARAM_STR],
"newMainColor" => [$newMainColor, PDO::PARAM_STR],
"newSecondColor" => [$newSecondColor, PDO::PARAM_STR],
]
);
}
}

@ -26,6 +26,7 @@ class TeamModel {
}
/**
* Create a team
* @param string $name
* @param string $picture
* @param string $mainColor
@ -37,7 +38,7 @@ class TeamModel {
}
/**
* adds a member to a team
* add a member to a team
* @param string $mail
* @param int $teamId
* @param string $role
@ -67,7 +68,7 @@ class TeamModel {
/**
* @param int $idTeam
* @param int $idCurrentUser
* @return ?Team
* @return Team|null
*/
public function getTeam(int $idTeam, int $idCurrentUser): ?Team {
if(!$this->members->isMemberOfTeam($idTeam,$idCurrentUser)){
@ -80,7 +81,7 @@ class TeamModel {
/**
* delete a member from given team identifier
* @param string $mail
* @param int $idMember
* @param int $teamId
* @return int
*/
@ -93,6 +94,12 @@ class TeamModel {
return $teamId;
}
/**
* Delete a team
* @param string $email
* @param int $idTeam
* @return int
*/
public function deleteTeam(string $email, int $idTeam): int{
if($this->members->isCoach($email,$idTeam)){
$this->teams->deleteTeam($idTeam);
@ -101,7 +108,27 @@ class TeamModel {
return -1;
}
/**
* Verify if the account associated to an email is in a specific team indicated with its id
* @param int $idTeam
* @param string $email
* @return bool
*/
public function isCoach(int $idTeam, string $email): bool{
return $this->members->isCoach($email,$idTeam);
}
/**
* Edit a team with its id, and replace the current attributes with the new ones
* @param int $idTeam
* @param string $newName
* @param string $newPicture
* @param string $newMainColor
* @param string $newSecondColor
* @return void
*/
public function editTeam(int $idTeam,string $newName,string $newPicture, string $newMainColor, string $newSecondColor){
$this->teams->editTeam($idTeam,$newName,$newPicture, $newMainColor, $newSecondColor);
}
}

Loading…
Cancel
Save