all datas are displayed in react - still have to fix the css
continuous-integration/drone/push Build is failing Details

pull/84/head
Maël DAIM 1 year ago
parent 18eda07d2c
commit f550bd19f7

@ -2,7 +2,7 @@ import CourtSvg from "../../assets/basketball_court.svg?react"
import "../../style/basket_court.css"
import { RefObject, useRef } from "react"
import CourtPlayer from "./CourtPlayer"
import { Player } from "../../tactic/Player"
import { Player } from "../../model/tactic/Player"
export interface BasketCourtProps {
players: Player[]

@ -4,7 +4,7 @@ import RemoveIcon from "../../assets/icon/remove.svg?react"
import { BallPiece } from "./BallPiece"
import Draggable from "react-draggable"
import { PlayerPiece } from "./PlayerPiece"
import { Player } from "../../tactic/Player"
import { Player } from "../../model/tactic/Player"
import { calculateRatio } from "../../Utils"
export interface PlayerProps {

@ -1,6 +1,6 @@
import React from "react"
import "../../style/player.css"
import { Team } from "../../tactic/Team"
import { Team } from "../../model/tactic/Team"
export interface PlayerPieceProps {
team: Team

@ -0,0 +1,28 @@
export interface TeamInfo{
id: number
name: string
picture: string
mainColor: Color
secondColor: Color
}
export interface Color{
hex: string
}
export interface Team {
info: TeamInfo
members: Member[]
}
export interface Member{
user: User
role: string
}
export interface User{
id: number
name: string
email: string
profilePicture: string
}

@ -1,5 +1,5 @@
body {
background-color: #f1f1f1;
background-color: var(--background-color);
display: flex;
flex-direction: column;
align-items: center;

@ -17,10 +17,10 @@ import { Rack } from "../components/Rack"
import { PlayerPiece } from "../components/editor/PlayerPiece"
import { BallPiece } from "../components/editor/BallPiece"
import { Player } from "../tactic/Player"
import { Tactic, TacticContent } from "../tactic/Tactic"
import { Player } from "../model/tactic/Player"
import { Tactic, TacticContent } from "../model/tactic/Tactic"
import { fetchAPI } from "../Fetcher"
import { Team } from "../tactic/Team"
import { Team } from "../model/tactic/Team"
import { calculateRatio } from "../Utils"
import SavingState, {
SaveState,

@ -1,42 +1,20 @@
import '../style/teamPanel.css'
interface TeamInfo{
id: number
name: string
picture: string
mainColor: string
secondColor: string
}
interface Team {
info: TeamInfo
members: Member[]
}
interface Member{
id: number
name: string
mail: string
profilePicture: string
role: string
}
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}: {isCoach: boolean, team: Team }){
return (
<div>
<div>
<TeamDisplay team={team.info}/>
</div>
<div>
{isCoach ? () : ()}
</div>
<TeamDisplay team={team.info}/>
{isCoach && <CoachOptions id={team.info.id}/>}
<div>
<h2>Membres :</h2>
<MembersDisplay members={team.members}/>
</div>
</div>
)
)
}
function TeamDisplay({ team}: {team : TeamInfo}) {
@ -47,27 +25,36 @@ function TeamDisplay({ team}: {team : TeamInfo}) {
<img src={team.picture} alt="Logo d'équipe" />
</div>
<div id="colors">
<Color color={team.mainColor}/>
<Color color={team.secondColor}/>
<p>Couleur principale</p>
<ColorDisplay color={team.mainColor.hex}/>
<p>Couleur secondaire</p>
<ColorDisplay color={team.secondColor.hex}/>
</div>
</div>
)
}
function Color({color}: {color : string}){
function ColorDisplay({color}: {color : string}){
return(
<div className="color"><p>Couleur principale : </p>
<div className="square" style={{backgroundColor: color}}></div>
</div>
<div className="square" style={{backgroundColor: color}}/>
)
}
function CoachOptions (){
function CoachOptions ({id}:{id:number}){
return (
<div>
<button id="delete" onClick={confirm('Êtes-vous sûr de supprimer cette équipe?') ? window.location.href = '' : {}}>Supprimer</button>
<button id="delete" onClick={()=>confirm('Êtes-vous sûr de supprimer cette équipe?') ? window.location.href=`${BASE}/team/${id}/delete` : {}}>Supprimer</button>
</div>
)
}
function MembersDisplay({members}:{members : Member[]}){
const listMember = members.map((member) =>
<MemberDisplay member={member}/>
);
return (
<div>
{listMember}
</div>
)
}
@ -75,10 +62,10 @@ function CoachOptions (){
function MemberDisplay({member}: {member : Member}){
return (
<div>
<img src={member.profilePicture} alt="Photo de profile"/>
<p>{member.name}</p>
<img src={member.user.profilePicture} alt="Photo de profile"/>
<p>{member.user.name}</p>
<p>{member.role}</p>
<p>{member.mail}</p>
<p>{member.user.email}</p>
</div>
)
}

@ -51,7 +51,6 @@ function tryGetAuthorization(): ?Account {
$session = PhpSessionHandle::init();
return $session->getAccount();
}
$token = $headers['Authorization'];
$gateway = new AccountGateway(new Connection(get_database()));
return $gateway->getAccountFromToken($token);

@ -103,7 +103,7 @@ 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]/delete", Action::auth(fn(int $id,SessionHandle $s) => getTeamController()->deleteTeamById($id,$s)));
$ar->map("GET", "/team/members/add", Action::auth(fn(SessionHandle $s) => getTeamController()->displayAddMember($s)));
$ar->map("POST", "/team/members/add", Action::auth(fn(SessionHandle $s) => getTeamController()->addMember($_POST, $s)));
$ar->map("GET", "/team/members/remove", Action::auth(fn(SessionHandle $s) => getTeamController()->displayDeleteMember($s)));

@ -11,6 +11,7 @@ CREATE TABLE Account
username varchar NOT NULL,
token varchar UNIQUE NOT NULL,
hash varchar NOT NULL,
profilePicture varchar NOT NULL
);
CREATE TABLE Tactic

@ -63,7 +63,7 @@ class EditorController {
return $this->openTestEditor($type);
}
$tactic = $this->model->makeNewDefault($session->getAccount()->getId(), $type);
$tactic = $this->model->makeNewDefault($session->getAccount()->getUser()->getId(), $type);
return $this->openEditorFor($tactic);
}
@ -76,7 +76,7 @@ class EditorController {
public function openEditor(int $id, SessionHandle $session): ViewHttpResponse {
$tactic = $this->model->get($id);
$failure = TacticValidator::validateAccess($id, $tactic, $session->getAccount()->getId());
$failure = TacticValidator::validateAccess($id, $tactic, $session->getAccount()->getUser()->getId());
if ($failure != null) {
return ViewHttpResponse::twig('error.html.twig', ['failures' => [$failure]], HttpCodes::NOT_FOUND);

@ -73,7 +73,7 @@ class TeamController {
return ViewHttpResponse::twig('insert_team.html.twig', ['bad_fields' => $badFields]);
}
$teamId = $this->model->createTeam($request['name'], $request['picture'], $request['main_color'], $request['second_color']);
$this->model->addMember($session->getAccount()->getEmail(),$teamId,'Coach');
$this->model->addMember($session->getAccount()->getUser()->getEmail(),$teamId,'COACH');
return $this->displayTeam($teamId, $session);
}
@ -102,12 +102,11 @@ class TeamController {
return ViewHttpResponse::twig('list_team_by_name.html.twig', ['bad_field' => $badField]);
}
$teams = $this->model->listByName($request['name'],$session->getAccount()->getId());
$teams = $this->model->listByName($request['name'],$session->getAccount()->getUser()->getId());
if (empty($teams)) {
return ViewHttpResponse::twig('display_teams.html.twig', []);
}
return ViewHttpResponse::twig('display_teams.html.twig', ['teams' => $teams]);
}
@ -116,9 +115,9 @@ class TeamController {
* @param SessionHandle $session
* @return HttpResponse
*/
public function deleteTeamByid(int $id,SessionHandle $session):HttpResponse{
public function deleteTeamById(int $id, SessionHandle $session):HttpResponse{
$a = $session->getAccount();
$ret = $this->model->deleteTeam($a->getEmail(),$id);
$ret = $this->model->deleteTeam($a->getUser()->getEmail(),$id);
if($ret != 0){
return ViewHttpResponse::twig('display_team.html.twig',['notDeleted' => true]);
}
@ -131,19 +130,18 @@ class TeamController {
* @return ViewHttpResponse a view that displays given team information
*/
public function displayTeam(int $id, SessionHandle $session): ViewHttpResponse {
$result = $this->model->getTeam($id,$session->getAccount()->getId());
$result = $this->model->getTeam($id,$session->getAccount()->getUser()->getId());
if($result == null){
return ViewHttpResponse::twig('error.html.twig', [
'failures' => [ValidationFail::unauthorized("Vous n'avez pas accès à cette équipe.")],
], HttpCodes::FORBIDDEN);
}
else{
$role = $this->model->isCoach($id,$session->getAccount()->getEmail());
$role = $this->model->isCoach($id,$session->getAccount()->getUser()->getEmail());
return ViewHttpResponse::react('views/TeamPanel.tsx', [
'team' => [
"info" => [
"id" => 1
]
"info" => $result->getInfo(),
"members" => $result->listMembers()
], 'isCoach' => $role]);
}
}

@ -28,7 +28,7 @@ class VisualizerController {
public function openVisualizer(int $id, SessionHandle $session): HttpResponse {
$tactic = $this->tacticModel->get($id);
$failure = TacticValidator::validateAccess($id, $tactic, $session->getAccount()->getId());
$failure = TacticValidator::validateAccess($id, $tactic, $session->getAccount()->getUser()->getId());
if ($failure != null) {
return ViewHttpResponse::twig('error.html.twig', ['failures' => [$failure]], HttpCodes::NOT_FOUND);

@ -8,10 +8,6 @@ namespace IQBall\Core\Data;
* to share to other users, or non-needed public information
*/
class Account {
/**
* @var string $email account's mail address
*/
private string $email;
/**
* @var string string token
@ -19,43 +15,28 @@ class Account {
private string $token;
/**
* @var string the account's username
*/
private string $name;
/**
* @var int
* @var User contains all the account's "public" information
*/
private int $id;
private User $user;
/**
* @param string $email
* @param string $name
* @param string $token
* @param int $id
* @param User $user
*/
public function __construct(string $email, string $name, string $token, int $id) {
$this->email = $email;
$this->name = $name;
public function __construct(string $token, User $user) {
$this->token = $token;
$this->id = $id;
}
public function getId(): int {
return $this->id;
}
public function getEmail(): string {
return $this->email;
$this->user = $user;
}
public function getToken(): string {
return $this->token;
}
public function getName(): string {
return $this->name;
/**
* @return User
*/
public function getUser(): User {
return $this->user;
}
}

@ -4,7 +4,7 @@ namespace IQBall\Core\Data;
use InvalidArgumentException;
class Color {
class Color implements \JsonSerializable {
/**
* @var string that represents an hexadecimal color code
*/
@ -41,4 +41,10 @@ class Color {
}
return new Color($value);
}
public function jsonSerialize() {
return get_object_vars($this);
}
}

@ -5,11 +5,9 @@ namespace IQBall\Core\Data;
/**
* information about a team member
*/
class Member {
/**
* @var int The member's user account
*/
private int $userId;
class Member implements \JsonSerializable {
private User $user;
/**
* @var int The member's team id
@ -17,32 +15,25 @@ class Member {
private int $teamId;
/**
* @var MemberRole the member's role
* @var string the member's role
*/
private MemberRole $role;
private string $role;
/**
* @param int $userId
* @param MemberRole $role
* @param User $user
* @param int $teamId
* @param string $role
*/
public function __construct(int $userId, int $teamId, MemberRole $role) {
$this->userId = $userId;
public function __construct(User $user, int $teamId, string $role) {
$this->user = $user;
$this->teamId = $teamId;
$this->role = $role;
}
/**
* @return int
*/
public function getUserId(): int {
return $this->userId;
}
/**
* @return MemberRole
* @return string
*/
public function getRole(): MemberRole {
public function getRole(): string {
return $this->role;
}
@ -52,4 +43,16 @@ class Member {
public function getTeamId(): int {
return $this->teamId;
}
/**
* @return User
*/
public function getUser(): User {
return $this->user;
}
public function jsonSerialize() {
return get_object_vars($this);
}
}

@ -1,68 +0,0 @@
<?php
namespace IQBall\Core\Data;
use InvalidArgumentException;
/**
* Enumeration class workaround
* As there is no enumerations in php 7.4, this class
* encapsulates an integer value and use it as a variant discriminant
*/
final class MemberRole {
private const ROLE_PLAYER = 0;
private const ROLE_COACH = 1;
private const MIN = self::ROLE_PLAYER;
private const MAX = self::ROLE_COACH;
private int $value;
private function __construct(int $val) {
if (!$this->isValid($val)) {
throw new InvalidArgumentException("Valeur du rôle invalide");
}
$this->value = $val;
}
public static function player(): MemberRole {
return new MemberRole(MemberRole::ROLE_PLAYER);
}
public static function coach(): MemberRole {
return new MemberRole(MemberRole::ROLE_COACH);
}
public function name(): string {
switch ($this->value) {
case self::ROLE_COACH:
return "COACH";
case self::ROLE_PLAYER:
return "PLAYER";
}
die("unreachable");
}
public static function fromName(string $name): ?MemberRole {
switch ($name) {
case "COACH":
return MemberRole::coach();
case "PLAYER":
return MemberRole::player();
default:
return null;
}
}
private function isValid(int $val): bool {
return ($val <= self::MAX and $val >= self::MIN);
}
public function isPlayer(): bool {
return ($this->value == self::ROLE_PLAYER);
}
public function isCoach(): bool {
return ($this->value == self::ROLE_COACH);
}
}

@ -2,7 +2,7 @@
namespace IQBall\Core\Data;
class Team {
class Team implements \JsonSerializable {
private TeamInfo $info;
/**
@ -29,4 +29,10 @@ class Team {
public function listMembers(): array {
return $this->members;
}
public function jsonSerialize() {
return get_object_vars($this);
}
}

@ -2,7 +2,7 @@
namespace IQBall\Core\Data;
class TeamInfo {
class TeamInfo implements \JsonSerializable {
private int $id;
private string $name;
private string $picture;
@ -45,5 +45,9 @@ class TeamInfo {
return $this->secondColor;
}
public function jsonSerialize() {
return get_object_vars($this);
}
}

@ -0,0 +1,73 @@
<?php
namespace IQBall\Core\Data;
use _PHPStan_4c4f22f13\Nette\Utils\Json;
class User implements \JsonSerializable {
/**
* @var string $email user's mail address
*/
private string $email;
/**
* @var string the user's username
*/
private string $name;
/**
* @var int the user's id
*/
private int $id;
/**
* @var string user's profile picture
*/
private string $profilePicture;
/**
* @param string $email
* @param string $name
* @param int $id
* @param string $profilePicture
*/
public function __construct(string $email, string $name, int $id, string $profilePicture) {
$this->email = $email;
$this->name = $name;
$this->id = $id;
$this->profilePicture = $profilePicture;
}
/**
* @return string
*/
public function getEmail(): string {
return $this->email;
}
/**
* @return string
*/
public function getName(): string {
return $this->name;
}
/**
* @return int
*/
public function getId(): int {
return $this->id;
}
/**
* @return string
*/
public function getProfilePicture(): string {
return $this->profilePicture;
}
public function jsonSerialize() {
return get_object_vars($this);
}
}

@ -4,6 +4,7 @@ namespace IQBall\Core\Gateway;
use IQBall\Core\Connection;
use IQBall\Core\Data\Account;
use IQBall\Core\Data\User;
use PDO;
class AccountGateway {
@ -16,13 +17,13 @@ class AccountGateway {
$this->con = $con;
}
public function insertAccount(string $name, string $email, string $token, string $hash): int {
$this->con->exec("INSERT INTO Account(username, hash, email, token) VALUES (:username,:hash,:email,:token)", [
public function insertAccount(string $name, string $email, string $token, string $hash,string $profilePicture): int {
$this->con->exec("INSERT INTO Account(username, hash, email, token,profilePicture) VALUES (:username,:hash,:email,:token,:profilePic)", [
':username' => [$name, PDO::PARAM_STR],
':hash' => [$hash, PDO::PARAM_STR],
':email' => [$email, PDO::PARAM_STR],
':token' => [$token, PDO::PARAM_STR],
':profilePic' => [$profilePicture, PDO::PARAM_STR]
]);
return intval($this->con->lastInsertId());
}
@ -65,7 +66,7 @@ class AccountGateway {
return null;
}
return new Account($email, $acc["username"], $acc["token"], $acc["id"]);
return new Account($acc["token"],new User($email,$acc["username"],$acc["id"],$acc["profilePicture"]));
}
/**
@ -78,7 +79,7 @@ class AccountGateway {
return null;
}
return new Account($acc["email"], $acc["username"], $acc["token"], $acc["id"]);
return new Account($acc["token"],new User($acc["email"],$acc["username"],$acc["id"],$acc["profilePicture"]));
}

@ -4,7 +4,7 @@ namespace IQBall\Core\Gateway;
use IQBall\Core\Connection;
use IQBall\Core\Data\Member;
use IQBall\Core\Data\MemberRole;
use IQBall\Core\Data\User;
use PDO;
class MemberGateway {
@ -41,13 +41,12 @@ class MemberGateway {
*/
public function getMembersOfTeam(int $teamId): array {
$rows = $this->con->fetch(
"SELECT a.id,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],
]
);
return array_map(fn($row) => new Member($row['id'], $teamId, MemberRole::fromName($row['role'])), $rows);
return array_map(fn($row) => new Member(new User($row['email'],$row['username'],$row['id'],$row['profilePicture']), $teamId, $row['role']),$rows);
}
/**

@ -52,7 +52,7 @@ class TeamGateway {
/**
* @param int $id
* @return ?TeamInfo
* @return TeamInfo|null
*/
public function getTeamById(int $id): ?TeamInfo {
$row = $this->con->fetch(
@ -80,6 +80,9 @@ class TeamGateway {
)[0]['id'] ?? null;
}
/**
* @param int $idTeam
*/
public function deleteTeam(int $idTeam): void {
$this->con->exec(
"DELETE FROM Member WHERE id_team=:team",

@ -2,13 +2,16 @@
namespace IQBall\Core\Model;
use Exception;
use IQBall\Core\Data\Account;
use IQBall\Core\Data\User;
use IQBall\Core\Gateway\AccountGateway;
use IQBall\Core\Validation\FieldValidationFail;
use IQBall\Core\Validation\ValidationFail;
class AuthModel {
private AccountGateway $gateway;
private const DEFAULT_PROFILE_PICTURE = "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png";
/**
* @param AccountGateway $gateway
@ -17,7 +20,6 @@ class AuthModel {
$this->gateway = $gateway;
}
/**
* @param string $username
* @param string $password
@ -25,6 +27,7 @@ class AuthModel {
* @param string $email
* @param ValidationFail[] $failures
* @return Account|null the registered account or null if failures occurred
* @throws Exception
*/
public function register(string $username, string $password, string $confirmPassword, string $email, array &$failures): ?Account {
@ -43,13 +46,14 @@ class AuthModel {
$hash = password_hash($password, PASSWORD_DEFAULT);
$token = $this->generateToken();
$accountId = $this->gateway->insertAccount($username, $email, $token, $hash);
return new Account($email, $username, $token, $accountId);
$accountId = $this->gateway->insertAccount($username, $email, $token, $hash,self::DEFAULT_PROFILE_PICTURE);
return new Account($token,new User($email,$username,$accountId,self::DEFAULT_PROFILE_PICTURE));
}
/**
* Generate a random base 64 string
* @return string
* @throws Exception
*/
private function generateToken(): string {
return base64_encode(random_bytes(64));
@ -70,5 +74,4 @@ class AuthModel {
return $this->gateway->getAccountFromMail($email);
}
}

@ -44,7 +44,7 @@ class TeamModel {
* @return void
*/
public function addMember(string $mail, int $teamId, string $role): void {
$userId = $this->users->getAccountFromMail($mail)->getId();
$userId = $this->users->getAccountFromMail($mail)->getUser()->getId();
$this->members->insert($teamId, $userId, $role);
}
@ -78,7 +78,7 @@ class TeamModel {
* @return int
*/
public function deleteMember(string $mail, int $teamId): int {
$userId = $this->users->getAccountFromMail($mail)->getId();
$userId = $this->users->getAccountFromMail($mail)->getUser()->getId();
$this->members->remove($teamId, $userId);
return $teamId;
}

Loading…
Cancel
Save