Adds share feature

This commit is contained in:
Michel 2024-10-31 15:34:57 +01:00
parent 287c1f67c5
commit 15a9dcf09b
14 changed files with 379 additions and 23 deletions

View file

@ -3,6 +3,7 @@ declare(strict_types=1);
namespace GamesShop\Entities;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use GamesShop\Entities\Account\User;
@ -35,6 +36,7 @@ final class GamesList
{
$this->owner = $owner;
$this->name = $name;
$this->claimer = new ArrayCollection([$owner]);
}
@ -53,10 +55,13 @@ final class GamesList
return $this->name;
}
public function getClaimer(): array
public function getClaimer(): Collection
{
return $this->claimer;
}
public function addClaimer(User $claimer): void
{
$this->claimer[] = $claimer;
}
}

View file

@ -119,7 +119,7 @@ final class GameImporter
}
}
if ($values['key'] === null || $values['name'] === null || $values['store'] === null) {
if (empty($values['key']) || empty($values['name']) || empty($values['store'])) {
continue;
}

View file

@ -12,5 +12,6 @@ final class DataTablesAPIRoutes
AccountsEndpoint::applyRoutes($group);
$group->get('/keys/provider', ProviderKeysEndpoint::class);
$group->get('/list/users', SharedUsersEndpoint::class);
}
}

View file

@ -0,0 +1,63 @@
<?php
namespace GamesShop\Routing\Api\DataTables;
use Doctrine\ORM\EntityManager;
use GamesShop\Entities\Account\User;
use GamesShop\Entities\GamesList;
use GamesShop\Login\LoginHandler;
use GamesShop\Login\UserPermission;
use Laminas\Diactoros\Response\JsonResponse;
use League\Route\Http\Exception\BadRequestException;
use League\Route\Http\Exception\ForbiddenException;
use League\Route\Http\Exception\UnauthorizedException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
final class SharedUsersEndpoint
{
public function __construct(
private readonly LoginHandler $loginHandler,
private readonly EntityManager $entityManager,
) { }
/**
* @throws UnauthorizedException
* @throws ForbiddenException
*/
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
if (!$this->loginHandler->isLoggedIn()) {
throw new UnauthorizedException();
}
$user = $this->loginHandler->getCurrentUser();
if (!$user->getPermission()->hasLevel(UserPermission::PROVIDER)) {
throw new ForbiddenException();
}
$body = $request->getQueryParams();
if (!array_key_exists('listid', $body)) {
throw new BadRequestException();
}
$list = $this->entityManager->getRepository(GamesList::class)->findOneBy([ 'owner' => $user, 'id' => $body['listid'] ]);
$claimer = $list->getClaimer();
return new JsonResponse(
[ 'data' => $claimer
->filter(fn ($claimerUser) => $claimerUser !== $user)
->map(
function (User $user) {
return [
'id' => $user->getId(),
'name' => $user->getName(),
'icon' => $user->getProfilePictureUrl()
];
}
)->toArray()
]
);
}
}

View file

@ -0,0 +1,61 @@
<?php
namespace GamesShop\Routing\Api\Web;
use Doctrine\ORM\EntityManager;
use GamesShop\Entities\Account\User;
use GamesShop\Entities\GamesList;
use GamesShop\Login\LoginHandler;
use GamesShop\Login\UserPermission;
use Laminas\Diactoros\Response;
use League\Route\Http\Exception\BadRequestException;
use League\Route\Http\Exception\ForbiddenException;
use League\Route\Http\Exception\UnauthorizedException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class AddUserToList
{
public function __construct(
private readonly LoginHandler $loginHandler,
private readonly EntityManager $entityManager,
)
{
}
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
if (!$this->loginHandler->isLoggedIn()) {
throw new UnauthorizedException();
}
$user = $this->loginHandler->getCurrentUser();
if (!$user->getPermission()->hasLevel(UserPermission::PROVIDER)) {
throw new ForbiddenException();
}
$body = $request->getParsedBody();
if (!array_key_exists('listid', $body)) {
throw new BadRequestException();
}
$list = $this->entityManager->getRepository(GamesList::class)->findOneBy([ 'owner' => $user, 'id' => $body['listid'] ]);
if (!$list instanceof GamesList) {
throw new BadRequestException();
}
$requestedUser = $this->entityManager->getRepository(User::class)
->find($body['requested']);
if ($list->getClaimer()->contains($requestedUser)) {
return new Response();
}
$list->addClaimer($requestedUser);
$this->entityManager->flush();
return new Response();
}
}

View file

@ -0,0 +1,60 @@
<?php
namespace GamesShop\Routing\Api\Web;
use Doctrine\ORM\EntityManager;
use GamesShop\Entities\Account\User;
use GamesShop\Entities\GamesList;
use GamesShop\Login\LoginHandler;
use GamesShop\Login\UserPermission;
use Laminas\Diactoros\Response;
use League\Route\Http\Exception\BadRequestException;
use League\Route\Http\Exception\ForbiddenException;
use League\Route\Http\Exception\UnauthorizedException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
class RemoveUserFromList
{
public function __construct(
private readonly LoginHandler $loginHandler,
private readonly EntityManager $entityManager,
)
{
}
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
if (!$this->loginHandler->isLoggedIn()) {
throw new UnauthorizedException();
}
$user = $this->loginHandler->getCurrentUser();
if (!$user->getPermission()->hasLevel(UserPermission::PROVIDER)) {
throw new ForbiddenException();
}
$body = $request->getParsedBody();
if (!array_key_exists('listid', $body)) {
throw new BadRequestException();
}
$list = $this->entityManager->getRepository(GamesList::class)->findOneBy([ 'owner' => $user, 'id' => $body['listid'] ]);
if (!$list instanceof GamesList) {
throw new BadRequestException();
}
$requestedUser = $this->entityManager->getRepository(User::class)
->find($body['requestedUser']);
if ($requestedUser === $user) {
return new Response();
}
$list->getClaimer()->removeElement($requestedUser);
$this->entityManager->flush();
return new Response();
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace GamesShop\Routing\Api\Web;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\EntityManager;
use GamesShop\Entities\Account\User;
use GamesShop\Login\LoginHandler;
use GamesShop\Login\UserPermission;
use Laminas\Diactoros\Response\JsonResponse;
use League\Route\Http\Exception\ForbiddenException;
use League\Route\Http\Exception\UnauthorizedException;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
final class SearchForUsers
{
public function __construct(
private readonly LoginHandler $loginHandler,
private readonly EntityManager $entityManager,
) { }
/**
* @throws ForbiddenException
* @throws UnauthorizedException
*/
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
if (!$this->loginHandler->isLoggedIn()) {
throw new UnauthorizedException();
}
$user = $this->loginHandler->getCurrentUser();
if (!$user->getPermission()->hasLevel(UserPermission::PROVIDER)) {
throw new ForbiddenException();
}
$searchQuery = $request->getQueryParams()['query'] ?? '';
$repo = $this->entityManager->getRepository(User::class);
$criteria = Criteria::create();
$criteria->where(Criteria::expr()->contains('name', $searchQuery));
$criteria->setMaxResults(10);
$values = $repo->matching($criteria);
return new JsonResponse(
$values
->filter(fn ($value) => $value !== $user)
->map(function (User $user) {
return [
'value' => $user->getId(),
'label' => $user->getName()
];
})
->toArray()
);
}
}

View file

@ -14,5 +14,9 @@ final class WebAPIRoutes
$group->post('/keys/import/perform', ImportKeysRoute::class);
$group->post('/keys/list/create', CreateKeyListRoute::class);
$group->get('/share/search', SearchForUsers::class);
$group->post('/share/add', AddUserToList::class);
$group->post('/share/remove', RemoveUserFromList::class);
}
}

View file

@ -20,21 +20,12 @@ use Psr\Http\Message\ServerRequestInterface;
final class Router
{
public function __construct(
private ResourceRoute $resourceRoute
)
{
}
public function route(): ResponseInterface
{
$request = ServerRequestFactory::fromGlobals(
$_SERVER, $_GET, $_POST, $_COOKIE, $_FILES
);
if ($this->resourceRoute->isValid($request->getUri())) {
return $this->resourceRoute->getResponse($request->getUri());
}
$router = new \League\Route\Router;
$strategy = (new ApplicationStrategy)->setContainer(ContainerHandler::getInstance());
$router->setStrategy($strategy);