Add Administration API for teams's administration panel (#97)
continuous-integration/drone/push Build is passing Details

Co-authored-by: Override-6 <maximebatista18@gmail.com>
Co-authored-by: samuel <Samuel.BERION@etu.uca.fr>
Co-authored-by: sam <sam@LAPTOPSam.lan>
Co-authored-by: sam <sam@laptop.lan>
Reviewed-on: #97
Co-authored-by: Samuel BERION <samuel.berion@etu.uca.fr>
Co-committed-by: Samuel BERION <samuel.berion@etu.uca.fr>
shareTactic^2
Samuel BERION 1 year ago committed by Maxime BATISTA
parent 93612c473b
commit 55d5970055

@ -21,14 +21,21 @@ function _asset(string $assetURI): string {
function _init_database(PDO $pdo): void {
$accounts = new AccountGateway(new Connection($pdo));
$teams = new \IQBall\Core\Gateway\TeamGateway((new Connection($pdo)));
$defaultAccounts = ["maxime", "mael", "yanis", "vivien"];
$defaultTeams = ["Lakers", "Celtics", "Bulls"];
foreach ($defaultAccounts as $name) {
$email = "$name@mail.com";
$id = $accounts->insertAccount($name, $email, AuthModel::generateToken(), password_hash("123456", PASSWORD_DEFAULT), "https://cdn.pixabay.com/photo/2015/10/05/22/37/blank-profile-picture-973460_960_720.png");
$accounts->setIsAdmin($id, true);
}
foreach ($defaultTeams as $name) {
$id = $teams->insert($name, "https://lebasketographe.fr/wp-content/uploads/2019/11/nom-equipes-nba.jpg", "#1a2b3c", "#FF00AA");
}
}
function _get_base_path(): string {

@ -33,6 +33,7 @@ function getAccountController(): APIAccountsController {
$con = new Connection(get_database());
$gw = new AccountGateway($con);
return new APIAccountsController(new AuthModel($gw), $gw);
}
function getServerController(): APIServerController {
@ -40,6 +41,13 @@ function getServerController(): APIServerController {
return new APIServerController($basePath, get_database());
}
function getAPITeamController(): \IQBall\Api\Controller\APITeamController {
$con = new Connection(get_database());
return new \IQBall\Api\Controller\APITeamController(new \IQBall\Core\Model\TeamModel(new \IQBall\Core\Gateway\TeamGateway($con), new \IQBall\Core\Gateway\MemberGateway($con), new AccountGateway($con)));
}
function getRoutes(): AltoRouter {
global $basePath;
$router = new AltoRouter();
@ -48,7 +56,6 @@ function getRoutes(): AltoRouter {
$router->map("POST", "/auth", Action::noAuth(fn() => getAuthController()->authorize()));
$router->map("POST", "/tactic/[i:id]/edit/name", Action::auth(fn(int $id, Account $acc) => getTacticController()->updateName($id, $acc)));
$router->map("POST", "/tactic/[i:id]/save", Action::auth(fn(int $id, Account $acc) => getTacticController()->saveContent($id, $acc)));
$router->map("GET", "/admin/list-users", Action::noAuth(fn() => getAccountController()->listUsers($_GET)));
$router->map("GET", "/admin/user/[i:id]", Action::noAuth(fn(int $id) => getAccountController()->getUser($id)));
$router->map("GET", "/admin/user/[i:id]/space", Action::noAuth(fn(int $id) => getTacticController()->getUserTactics($id)));
@ -56,6 +63,12 @@ function getRoutes(): AltoRouter {
$router->map("POST", "/admin/user/remove-all", Action::noAuth(fn() => getAccountController()->removeUsers()));
$router->map("POST", "/admin/user/[i:id]/update", Action::noAuth(fn(int $id) => getAccountController()->updateUser($id)));
$router->map("GET", "/admin/server-info", Action::noAuth(fn() => getServerController()->getServerInfo()));
$router->map("GET", "/admin/list-team", Action::noAuth(fn() => getAPITeamController()->listTeams($_GET)));
$router->map("POST", "/admin/add-team", Action::noAuth(fn() => getAPITeamController()->addTeam()));
$router->map("POST", "/admin/delete-teams", Action::noAuth(fn() => getAPITeamController()->deleteTeamSelected()));
$router->map("POST", "/admin/team/[i:id]/update", Action::noAuth(fn(int $id) => getAPITeamController()->updateTeam($id)));
return $router;
}

@ -1,5 +1,9 @@
<?php
use IQBall\Core\Connection;
use IQBall\Core\Gateway\AccountGateway;
use IQBall\Core\Model\AuthModel;
/**
* @return PDO The PDO instance of the configuration's database connexion.
*/

@ -17,6 +17,7 @@ class API {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: *');
foreach ($response->getHeaders() as $header => $value) {
header("$header: $value");
}

@ -3,7 +3,6 @@
namespace IQBall\Api\Controller;
use IQBall\Api\APIControl;
use IQBall\App\Control;
use IQBall\Core\Data\Account;
use IQBall\Core\Gateway\AccountGateway;
use IQBall\Core\Http\HttpCodes;
@ -25,6 +24,7 @@ class APIAccountsController {
public function __construct(AuthModel $model, AccountGateway $accounts) {
$this->accounts = $accounts;
$this->authModel = $model;
}
@ -34,6 +34,7 @@ class APIAccountsController {
*/
public function listUsers(array $request): HttpResponse {
return APIControl::runCheckedFrom($request, [
'start' => [DefaultValidators::isUnsignedInteger()],
'n' => [DefaultValidators::isIntInRange(0, 250)],
'search' => [DefaultValidators::lenBetween(0, 256)],

@ -77,6 +77,7 @@ class APITacticController {
'name' => $t->getName(),
'court' => $t->getCourtType(),
'creation_date' => $t->getCreationDate(),
], $tactics);
return new JsonHttpResponse($response);

@ -0,0 +1,79 @@
<?php
namespace IQBall\Api\Controller;
use IQBall\Api\APIControl;
use IQBall\Core\Data\Account;
use IQBall\Core\Data\Team;
use IQBall\Core\Data\TeamInfo;
use IQBall\Core\Gateway\TeamGateway;
use IQBall\Core\Http\HttpCodes;
use IQBall\Core\Http\HttpRequest;
use IQBall\Core\Http\HttpResponse;
use IQBall\Core\Http\JsonHttpResponse;
use IQBall\Core\Model\TeamModel;
use IQBall\Core\Validation\DefaultValidators;
class APITeamController {
private TeamModel $teamModel;
/**
* @param TeamModel $teamModel
*/
public function __construct(TeamModel $teamModel) {
$this->teamModel = $teamModel;
}
/**
* @param array<string, mixed> $req_params
* @return HttpResponse
*/
public function listTeams(array $req_params): HttpResponse {
return APIControl::runCheckedFrom($req_params, [
'start' => [DefaultValidators::isUnsignedInteger()],
'n' => [DefaultValidators::isUnsignedInteger()],
], function (HttpRequest $req) {
$teams = $this->teamModel->listAll(intval($req['start']), intval($req['n']));
return new JsonHttpResponse([
"totalCount" => $this->teamModel->countTeam(),
"teams" => $teams,
]);
});
}
public function addTeam(): HttpResponse {
return APIControl::runChecked([
'name' => [DefaultValidators::name()],
'picture' => [DefaultValidators::isURL()],
'mainColor' => [DefaultValidators::hexColor()],
'secondaryColor' => [DefaultValidators::hexColor()],
], function (HttpRequest $req) {
$this->teamModel->createTeam($req['name'], $req['picture'], $req['mainColor'], $req['secondaryColor']);
return HttpResponse::fromCode(HttpCodes::OK);
});
}
public function deleteTeamSelected(): HttpResponse {
return APIControl::runChecked([
'teams' => [],
], function (HttpRequest $req) {
$this->teamModel->deleteTeamSelected($req['teams']);
return HttpResponse::fromCode(HttpCodes::OK);
});
}
public function updateTeam(int $id): HttpResponse {
return APIControl::runChecked([
'name' => [DefaultValidators::name()],
'picture' => [DefaultValidators::isURL()],
'mainColor' => [DefaultValidators::hexColor()],
'secondaryColor' => [DefaultValidators::hexColor()],
], function (HttpRequest $req) {
$this->teamModel->editTeam($req['id'], $req['name'], $req['picture'], $req['mainColor'], $req['secondaryColor']);
return HttpResponse::fromCode(HttpCodes::OK);
});
}
}

@ -12,7 +12,6 @@ use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
use Twig\Loader\FilesystemLoader;
class App {
/**
@ -90,6 +89,7 @@ class App {
if ($action->getAuthType() == Action::AUTH_ADMIN && !$account->getUser()->isAdmin()) {
return new JsonHttpResponse([ValidationFail::unauthorized()], HttpCodes::UNAUTHORIZED);
}
}
return $action->run($params, $session);

@ -24,6 +24,7 @@ class Control {
if (!$payload_obj instanceof \stdClass) {
$fail = new ValidationFail("bad-payload", "request body is not a valid json object");
return $errorFactory->apply([$fail]);
}
$payload = get_object_vars($payload_obj);
return self::runCheckedFrom($payload, $schema, $run, $errorFactory);
@ -44,6 +45,7 @@ class Control {
if (!empty($fails)) {
return $errorFactory->apply($fails);
}
return call_user_func_array($run, [$request]);

@ -24,7 +24,7 @@ class User implements \JsonSerializable {
private string $profilePicture;
/**
* @var bool isAdmin
* @var bool true if the user is an administrator
*/
private bool $isAdmin;

@ -47,7 +47,6 @@ class AccountGateway {
return !empty($result);
}
/**
* promote or demote a user to server administrator
* @param int $id
@ -60,6 +59,7 @@ class AccountGateway {
} else {
$stmnt = $this->con->prepare("DELETE FROM Admins WHERE id = :id");
}
$stmnt->bindValue(':id', $id);
$stmnt->execute();
@ -155,6 +155,7 @@ class AccountGateway {
]
);
return array_map(fn(array $acc) => new Account($acc["token"], new User($acc["email"], $acc["username"], $acc["id"], $acc["profile_picture"], $this->isAdmin($acc["id"]))), $res);
}
/**

@ -47,6 +47,7 @@ class MemberGateway {
]
);
return array_map(fn($row) => new Member(new User($row['email'], $row['username'], $row['id'], $row['profile_picture'], $row['is_admin']), $teamId, $row['role']), $rows);
}
/**

@ -3,6 +3,8 @@
namespace IQBall\Core\Gateway;
use IQBall\Core\Connection;
use IQBall\Core\Data\Color;
use IQBall\Core\Data\Team;
use IQBall\Core\Data\TeamInfo;
use PDO;
@ -46,6 +48,7 @@ class TeamGateway {
"id" => [$id, PDO::PARAM_INT],
]
);
return array_map(fn($row) => new TeamInfo($row['id'], $row['name'], $row['picture'], $row['main_color'], $row['second_color']), $result);
}
@ -137,5 +140,47 @@ class TeamGateway {
);
}
/**
* @param int $start
* @param int $n
* @return TeamInfo[]
*/
public function listAll(int $start, int $n): array {
$rows = $this->con->fetch(
"SELECT * FROM Team LIMIT :start, :n",
[
":start" => [$start, PDO::PARAM_INT],
":n" => [$n, PDO::PARAM_INT],
]
);
return array_map(fn($row) => new TeamInfo($row['id'], $row['name'], $row['picture'], $row['main_color'], $row['second_color']), $rows);
}
public function countTeam(): int {
$result = $this->con->fetch(
"SELECT count(*) as count FROM Team",
[]
);
if (empty($result) || !isset($result[0]['count'])) {
return 0;
}
return $result[0]['count'];
}
/**
* @param array<Team> $selectedTeams
* @return void
*/
public function deleteTeamSelected(array $selectedTeams): void {
foreach ($selectedTeams as $team) {
$this->con->exec(
"DELETE FROM TEAM WHERE id=:team",
[
"team" => [$team, PDO::PARAM_INT],
]
);
}
}
}

@ -45,10 +45,10 @@ class TeamModel {
*/
public function addMember(string $mail, int $teamId, string $role): int {
$user = $this->users->getAccountFromMail($mail);
if($user == null) {
if ($user == null) {
return -1;
}
if(!$this->members->isMemberOfTeam($teamId, $user->getUser()->getId())) {
if (!$this->members->isMemberOfTeam($teamId, $user->getUser()->getId())) {
$this->members->insert($teamId, $user->getUser()->getId(), $role);
return 1;
}
@ -70,7 +70,7 @@ class TeamModel {
* @return Team|null
*/
public function getTeam(int $idTeam, int $idCurrentUser): ?Team {
if(!$this->members->isMemberOfTeam($idTeam, $idCurrentUser)) {
if (!$this->members->isMemberOfTeam($idTeam, $idCurrentUser)) {
return null;
}
$teamInfo = $this->teams->getTeamById($idTeam);
@ -86,7 +86,7 @@ class TeamModel {
*/
public function deleteMember(int $idMember, int $teamId): int {
$this->members->remove($teamId, $idMember);
if(empty($this->members->getMembersOfTeam($teamId))) {
if (empty($this->members->getMembersOfTeam($teamId))) {
$this->teams->deleteTeam($teamId);
return -1;
}
@ -100,7 +100,7 @@ class TeamModel {
* @return int
*/
public function deleteTeam(string $email, int $idTeam): int {
if($this->members->isCoach($email, $idTeam)) {
if ($this->members->isCoach($email, $idTeam)) {
$this->teams->deleteTeam($idTeam);
return 0;
}
@ -139,4 +139,26 @@ class TeamModel {
public function getAll(int $user): array {
return $this->teams->getAll($user);
}
/**
* @param int $start
* @param int $n
* @return TeamInfo[]
*/
public function listAll(int $start, int $n) {
return $this->teams->listAll($start, $n);
}
public function countTeam(): int {
return $this->teams->countTeam();
}
/**
* @param array<Team> $selectedTeams
* @return void
*/
public function deleteTeamSelected(array $selectedTeams) {
$this->teams->deleteTeamSelected($selectedTeams);
}
}

Loading…
Cancel
Save