Skip to content

Commit

Permalink
Multiple ESI Tokens #32
Browse files Browse the repository at this point in the history
- Implement API to add, list, update and delete eve logins.
  • Loading branch information
tkhamez committed Jul 24, 2021
1 parent e599fe2 commit b8d2d77
Show file tree
Hide file tree
Showing 7 changed files with 488 additions and 9 deletions.
5 changes: 5 additions & 0 deletions backend/config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use Neucore\Controller\User\ServiceAdminController;
use Neucore\Controller\User\ServiceController;
use Neucore\Controller\User\SettingsController;
use Neucore\Controller\User\SettingsEveLoginController;
use Neucore\Controller\User\StatisticsController;
use Neucore\Controller\User\WatchlistController;

Expand Down Expand Up @@ -155,6 +156,10 @@
'/api/user/settings/system/send-invalid-token-mail' => ['POST', [SettingsController::class, 'sendInvalidTokenMail']],
'/api/user/settings/system/send-missing-character-mail' => ['POST', [SettingsController::class, 'sendMissingCharacterMail']],
'/api/user/settings/system/validate-director/{name}' => ['PUT', [SettingsController::class, 'validateDirector']],
'/api/user/settings/eve-login/list' => ['GET' => [SettingsEveLoginController::class, 'list']],
'/api/user/settings/eve-login' => ['PUT' => [SettingsEveLoginController::class, 'update']],
'/api/user/settings/eve-login/{id}' => ['POST' => [SettingsEveLoginController::class, 'create'],
'DELETE' => [SettingsEveLoginController::class, 'delete']],

'/api/user/watchlist/create' => ['POST', [WatchlistController::class, 'create']],
'/api/user/watchlist/{id}/rename' => ['PUT', [WatchlistController::class, 'rename']],
Expand Down
6 changes: 4 additions & 2 deletions backend/config/security.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,10 @@
'/api/user/player/{id}/set-status/' => [Role::USER_MANAGER],
'/api/user/player' => [Role::USER_ADMIN],

'/api/user/settings/system/list' => [Role::ANONYMOUS, Role::USER],
'/api/user/settings/system' => [Role::SETTINGS],
'/api/user/settings/system/list' => [Role::ANONYMOUS, Role::USER],
'/api/user/settings/system' => [Role::SETTINGS],
'/api/user/settings/eve-login/list' => [Role::ANONYMOUS, Role::USER],
'/api/user/settings/eve-login' => [Role::SETTINGS],

'/api/user/watchlist/list-available-manage' => [Role::WATCHLIST_MANAGER],
'/api/user/watchlist/list-available' => [Role::WATCHLIST],
Expand Down
191 changes: 191 additions & 0 deletions backend/src/Controller/User/SettingsEveLoginController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
<?php

declare(strict_types=1);

namespace Neucore\Controller\User;

use Neucore\Controller\BaseController;
use Neucore\Entity\EveLogin;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

class SettingsEveLoginController extends BaseController
{
/**
* @var string
*/
private $idPattern = "/^[-._a-zA-Z0-9]+$/";

/**
* @OA\Post(
* path="/user/settings/eve-login/{id}",
* operationId="userSettingsEveLoginCreate",
* summary="Create a new login.",
* description="Needs role: settings",
* tags={"Settings"},
* security={{"Session"={}, "CSRF"={}}},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* description="The new login ID.",
* @OA\Schema(type="string", maxLength=20, pattern="^[-._a-zA-Z0-9]+$")
* ),
* @OA\Response(
* response="201",
* description="The new login.",
* @OA\JsonContent(ref="#/components/schemas/EveLogin")
* ),
* @OA\Response(
* response="400",
* description="Login ID is invalid."
* ),
* @OA\Response(
* response="403",
* description="Not authorized."
* ),
* @OA\Response(
* response="409",
* description="A login with this ID already exists."
* )
* )
*/
public function create(string $id): ResponseInterface
{
if (!preg_match($this->idPattern, $id) || strpos($id, EveLogin::INTERNAL_LOGINS_PREFIX) === 0) {
return $this->response->withStatus(400);
}

$existingLogin = $this->repositoryFactory->getEveLoginRepository()->find($id);
if ($existingLogin) {
return $this->response->withStatus(409);
}

$login = (new EveLogin())->setId($id);
$this->objectManager->persist($login);

return $this->flushAndReturn(201, $login);
}

/**
* @OA\Delete(
* path="/user/settings/eve-login/{id}",
* operationId="userSettingsEveLoginDelete",
* summary="Delete login.",
* description="Needs role: settings",
* tags={"Settings"},
* security={{"Session"={}, "CSRF"={}}},
* @OA\Parameter(
* name="id",
* in="path",
* required=true,
* description="The login ID.",
* @OA\Schema(type="string", maxLength=20, pattern="^[-._a-zA-Z0-9]+$")
* ),
* @OA\Response(
* response="204",
* description="Login was deleted."
* ),
* @OA\Response(
* response="400",
* description="Protected login ID."
* ),
* @OA\Response(
* response="403",
* description="Not authorized."
* ),
* @OA\Response(
* response="404",
* description="Login not found."
* )
* )
*/
public function delete(string $id): ResponseInterface
{
if (in_array($id, EveLogin::INTERNAL_LOGINS)) {
return $this->response->withStatus(400);
}

$login = $this->repositoryFactory->getEveLoginRepository()->find($id);
if (!$login) {
return $this->response->withStatus(404);
}

$this->objectManager->remove($login);

return $this->flushAndReturn(204);
}

/**
* @OA\Get(
* path="/user/settings/eve-login/list",
* operationId="userSettingsEveLoginList",
* summary="List all logins.",
* description="Needs role: anonymous or user",
* tags={"Settings"},
* security={{"Session"={}}},
* @OA\Response(
* response="200",
* description="List of logins.",
* @OA\JsonContent(type="array", @OA\Items(ref="#/components/schemas/EveLogin"))
* )
* )
*/
public function list(): ResponseInterface
{
$logins = $this->repositoryFactory->getEveLoginRepository()->findBy([]);
return $this->withJson($logins);
}

/**
* @OA\Put(
* path="/user/settings/eve-login",
* operationId="userSettingsEveLoginUpdate",
* summary="Update login.",
* description="Needs role: settings",
* tags={"Settings"},
* security={{"Session"={}, "CSRF"={}}},
* @OA\RequestBody(
* required=true,
* description="JSON encoded data.",
* @OA\MediaType(mediaType="application/json", @OA\Schema(ref="#/components/schemas/EveLogin"))
* ),
* @OA\Response(
* response="200",
* description="The updated login.",
* @OA\JsonContent(ref="#/components/schemas/EveLogin")
* ),
* @OA\Response(
* response="400",
* description="Invalid body."
* ),
* @OA\Response(
* response="403",
* description="Not authorized."
* ),
* @OA\Response(
* response="404",
* description="Login not found."
* )
* )
*/
public function update(ServerRequestInterface $request): ResponseInterface
{
$data = $request->getParsedBody();
if (!$data instanceof \stdClass || !EveLogin::isValidObject($data) || empty($data->id)) {
return $this->response->withStatus(400);
}

$login = $this->repositoryFactory->getEveLoginRepository()->find($data->id);
if (!$login) {
return $this->response->withStatus(404);
}

$login->setName($data->name);
$login->setDescription($data->description);
$login->setEsiScopes($data->esiScopes);
$login->setEveRoles($data->eveRoles);

return $this->flushAndReturn(200, $login);
}
}
33 changes: 26 additions & 7 deletions backend/src/Entity/EveLogin.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,40 @@
*/
class EveLogin implements \JsonSerializable
{
/**
* Prefix of all internal login IDs.
*/
public const INTERNAL_LOGINS_PREFIX = 'core.';

/**
* Default login.
*/
public const ID_DEFAULT = 'core.default';
public const ID_DEFAULT = self::INTERNAL_LOGINS_PREFIX . 'default';

/**
* Alternative character login.
*/
public const ID_ALT = 'core.alt';
public const ID_ALT = self::INTERNAL_LOGINS_PREFIX . 'alt';

/**
* Login for "managed" accounts.
*/
public const ID_MANAGED = 'core.managed';
public const ID_MANAGED = self::INTERNAL_LOGINS_PREFIX . 'managed';

/**
* Login for "managed" alt characters.
*/
public const ID_MANAGED_ALT = 'core.managed-alt';
public const ID_MANAGED_ALT = self::INTERNAL_LOGINS_PREFIX . 'managed-alt';

/**
* Login of the character that is used to send mails.
*/
public const ID_MAIL = 'core.mail';
public const ID_MAIL = self::INTERNAL_LOGINS_PREFIX . 'mail';

/**
* Login of the character with director roles for the member tracking functionality.
*/
public const ID_DIRECTOR = 'core.director';
public const ID_DIRECTOR = self::INTERNAL_LOGINS_PREFIX . 'director';

/**
* All internal login IDs.
Expand Down Expand Up @@ -104,7 +109,11 @@ class EveLogin implements \JsonSerializable
private $esiScopes = '';

/**
* @OA\Property(maxLength=1024)
* @OA\Property(
* type="array",
* @OA\Items(type="string"),
* description="Maximum length of all roles separated by comma: 1024."
* )
* @ORM\Column(type="string", name="eve_roles", length=1024)
* @var string
*/
Expand All @@ -117,6 +126,16 @@ class EveLogin implements \JsonSerializable
*/
private $esiTokens;

public static function isValidObject(\stdClass $data): bool
{
return
property_exists($data, 'id') && is_string($data->id) &&
property_exists($data, 'name') && is_string($data->name) &&
property_exists($data, 'description') && is_string($data->description) &&
property_exists($data, 'esiScopes') && is_string($data->esiScopes) &&
property_exists($data, 'eveRoles') && is_array($data->eveRoles);
}

public function jsonSerialize(): array
{
return [
Expand Down
Loading

0 comments on commit b8d2d77

Please sign in to comment.