parent
24f50f6c15
commit
26f794c9ab
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Character;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
|
||||
#[AsController]
|
||||
final class GetDojoCharacters
|
||||
{
|
||||
|
||||
public function __invoke($dojoId, EntityManagerInterface $em): iterable
|
||||
{
|
||||
return $em->getRepository(Character::class)->findBy([
|
||||
'dojo' => $dojoId
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\Character;
|
||||
use App\Entity\Dojo;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpKernel\Attribute\AsController;
|
||||
|
||||
#[AsController]
|
||||
final class GetOwnDojoCharacters
|
||||
{
|
||||
|
||||
public function __construct(private Security $security)
|
||||
{}
|
||||
|
||||
public function __invoke(EntityManagerInterface $em): iterable
|
||||
{
|
||||
$dojo = $em->getRepository(Dojo::class)->findOneByOwner($this->security->getUser());
|
||||
|
||||
return $em->getRepository(Character::class)->findBy([
|
||||
'dojo' => $dojo->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping\Column;
|
||||
use Doctrine\ORM\Mapping\Entity;
|
||||
use Doctrine\ORM\Mapping\JoinColumn;
|
||||
use Doctrine\ORM\Mapping\OneToOne;
|
||||
|
||||
#[Entity]
|
||||
class Technique extends Thing
|
||||
{
|
||||
|
||||
/**
|
||||
* For now we calculate costs for mastering a technique.
|
||||
*/
|
||||
#[Column]
|
||||
public int $costs;
|
||||
|
||||
/**
|
||||
* Forumula to calculate the damage based on the stats.
|
||||
*/
|
||||
#[Column]
|
||||
public string $damage;
|
||||
|
||||
/**
|
||||
* Forumula to calculate the damage based on the stats.
|
||||
*/
|
||||
#[Column]
|
||||
public string $energy;
|
||||
|
||||
/**
|
||||
* Forumula to calculate the damage based on the stats.
|
||||
*/
|
||||
#[Column]
|
||||
public string $accuracy;
|
||||
|
||||
/**
|
||||
* Technique that is required to be learned before this Technique.
|
||||
*/
|
||||
#[OneToOne()]
|
||||
#[JoinColumn(onDelete: 'SET NULL', nullable: true)]
|
||||
public ?Technique $prerequisite;
|
||||
|
||||
public function getCosts(): ?int
|
||||
{
|
||||
return $this->costs;
|
||||
}
|
||||
|
||||
public function setCosts(int $costs): static
|
||||
{
|
||||
$this->costs = $costs;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDamage(): ?string
|
||||
{
|
||||
return $this->damage;
|
||||
}
|
||||
|
||||
public function setDamage(string $damage): static
|
||||
{
|
||||
$this->damage = $damage;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEnergy(): ?string
|
||||
{
|
||||
return $this->energy;
|
||||
}
|
||||
|
||||
public function setEnergy(string $energy): static
|
||||
{
|
||||
$this->energy = $energy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAccuracy(): ?string
|
||||
{
|
||||
return $this->accuracy;
|
||||
}
|
||||
|
||||
public function setAccuracy(string $accuracy): static
|
||||
{
|
||||
$this->accuracy = $accuracy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPrerequisite(): ?self
|
||||
{
|
||||
return $this->prerequisite;
|
||||
}
|
||||
|
||||
public function setPrerequisite(?self $prerequisite): static
|
||||
{
|
||||
$this->prerequisite = $prerequisite;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Entity\Character;
|
||||
use Zenstruck\Foundry\ModelFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @extends ModelFactory<Character>
|
||||
*
|
||||
* @method Character|Proxy create(array|callable $attributes = [])
|
||||
* @method static Character|Proxy createOne(array $attributes = [])
|
||||
* @method static Character|Proxy find(object|array|mixed $criteria)
|
||||
* @method static Character|Proxy findOrCreate(array $attributes)
|
||||
* @method static Character|Proxy first(string $sortedField = 'id')
|
||||
* @method static Character|Proxy last(string $sortedField = 'id')
|
||||
* @method static Character|Proxy random(array $attributes = [])
|
||||
* @method static Character|Proxy randomOrCreate(array $attributes = [])
|
||||
* @method static EntityRepository|RepositoryProxy repository()
|
||||
* @method static Character[]|Proxy[] all()
|
||||
* @method static Character[]|Proxy[] createMany(int $number, array|callable $attributes = [])
|
||||
* @method static Character[]|Proxy[] createSequence(iterable|callable $sequence)
|
||||
* @method static Character[]|Proxy[] findBy(array $attributes)
|
||||
* @method static Character[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
|
||||
* @method static Character[]|Proxy[] randomSet(int $number, array $attributes = [])
|
||||
*/
|
||||
final class CharacterFactory extends ModelFactory
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||
*
|
||||
* @todo inject services if required
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
|
||||
*
|
||||
* @todo add your default values here
|
||||
*/
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'name' => self::faker()->text(),
|
||||
'strength' => self::faker()->numberBetween(1, 4),
|
||||
'constitution' => self::faker()->numberBetween(1, 4),
|
||||
'agility' => self::faker()->numberBetween(1, 4),
|
||||
'techniques' => TechniqueFactory::createMany(2)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
|
||||
*/
|
||||
protected function initialize(): self
|
||||
{
|
||||
return $this;
|
||||
// ->afterInstantiate(function(Character $character): void {})
|
||||
}
|
||||
|
||||
protected static function getClass(): string
|
||||
{
|
||||
return Character::class;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
namespace App\Factory;
|
||||
|
||||
use App\Entity\Technique;
|
||||
use Zenstruck\Foundry\ModelFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* @extends ModelFactory<Technique>
|
||||
*
|
||||
* @method Technique|Proxy create(array|callable $attributes = [])
|
||||
* @method static Technique|Proxy createOne(array $attributes = [])
|
||||
* @method static Technique|Proxy find(object|array|mixed $criteria)
|
||||
* @method static Technique|Proxy findOrCreate(array $attributes)
|
||||
* @method static Technique|Proxy first(string $sortedField = 'id')
|
||||
* @method static Technique|Proxy last(string $sortedField = 'id')
|
||||
* @method static Technique|Proxy random(array $attributes = [])
|
||||
* @method static Technique|Proxy randomOrCreate(array $attributes = [])
|
||||
* @method static EntityRepository|RepositoryProxy repository()
|
||||
* @method static Technique[]|Proxy[] all()
|
||||
* @method static Technique[]|Proxy[] createMany(int $number, array|callable $attributes = [])
|
||||
* @method static Technique[]|Proxy[] createSequence(iterable|callable $sequence)
|
||||
* @method static Technique[]|Proxy[] findBy(array $attributes)
|
||||
* @method static Technique[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
|
||||
* @method static Technique[]|Proxy[] randomSet(int $number, array $attributes = [])
|
||||
*/
|
||||
final class TechniqueFactory extends ModelFactory
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
|
||||
*
|
||||
* @todo inject services if required
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
|
||||
*
|
||||
* @todo add your default values here
|
||||
*/
|
||||
protected function getDefaults(): array
|
||||
{
|
||||
return [
|
||||
'accuracy' => self::faker()->text(),
|
||||
'costs' => self::faker()->numberBetween(1, 2),
|
||||
'damage' => self::faker()->text(),
|
||||
'energy' => self::faker()->text(),
|
||||
'prerequisite' => self::faker()->boolean() ? NULL : self::new()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
|
||||
*/
|
||||
protected function initialize(): self
|
||||
{
|
||||
return $this;
|
||||
// ->afterInstantiate(function(Technique $technique): void {})
|
||||
}
|
||||
|
||||
protected static function getClass(): string
|
||||
{
|
||||
return Technique::class;
|
||||
}
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
podman run --rm --name ag-dojo-postgres -e POSTGRES_USER=foo -e POSTGRES_PASSWORD=bar -e POSTGRES_HOST_AUTH_METHOD=trust -p "5432:5432" docker.io/library/postgres:14.5
|
||||
podman run --rm --name ag-dojo-postgres -e POSTGRES_USER=foo -e POSTGRES_PASSWORD=bar -e POSTGRES_HOST_AUTH_METHOD=trust -p "5432:5432" docker.io/library/postgres:14.10
|
||||
|
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
namespace App\Tests;
|
||||
|
||||
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
|
||||
use App\Factory\CharacterFactory;
|
||||
use App\Factory\DojoFactory;
|
||||
use App\Factory\UserFactory;
|
||||
use Zenstruck\Foundry\Test\Factories;
|
||||
use Zenstruck\Foundry\Test\ResetDatabase;
|
||||
use DateTimeZone;
|
||||
|
||||
class CharacterTest extends ApiTestCase
|
||||
{
|
||||
use ResetDatabase, Factories;
|
||||
|
||||
private function generateAuthToken(string $authName)
|
||||
{
|
||||
$sign_seed = sodium_base642bin($_ENV['AUTH_SEED'], SODIUM_BASE64_VARIANT_ORIGINAL);
|
||||
$sign_pair = sodium_crypto_sign_seed_keypair($sign_seed);
|
||||
$sign_secret = sodium_crypto_sign_secretkey($sign_pair);
|
||||
$now = new \DateTimeImmutable("now", new DateTimeZone("UTC"));
|
||||
$message = $authName . "|" . $now->format("c");
|
||||
|
||||
return sodium_bin2base64(sodium_crypto_sign($message, $sign_secret), SODIUM_BASE64_VARIANT_URLSAFE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requirement: A user should be able see all characters from a dojo, but only the public fields!
|
||||
*/
|
||||
public function testRetrieveCharactersFromDojoPublic(): void
|
||||
{
|
||||
$requestUser = UserFactory::createOne();
|
||||
$dojo = DojoFactory::createOne();
|
||||
CharacterFactory::createMany(4, [
|
||||
'dojo' => $dojo
|
||||
]);
|
||||
CharacterFactory::createMany(10);
|
||||
|
||||
$response = static::createClient()->request('GET', '/api/dojo/' . $dojo->id . '/characters',
|
||||
[
|
||||
'headers' => [
|
||||
'accept' => 'application/json',
|
||||
'X-AUTH-TOKEN' => $this->generateAuthToken($requestUser->authName)
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(200);
|
||||
|
||||
// Because test fixtures are automatically loaded between each test, you can assert on them
|
||||
$this->assertCount(4, $response->toArray());
|
||||
|
||||
$this->assertNotEquals("[[],[],[],[]]", $response->getContent());
|
||||
|
||||
$chars = $response->toArray();
|
||||
$this->assertArrayHasKey('name', $chars[0]);
|
||||
$this->assertArrayHasKey('dojo', $chars[0]);
|
||||
$this->assertArrayNotHasKey('strength', $chars[0]); // not accessible via this route
|
||||
$this->assertArrayNotHasKey('constitution', $chars[0]); // not accessible via this route
|
||||
$this->assertArrayNotHasKey('agility', $chars[0]); // not accessible via this route
|
||||
$this->assertArrayNotHasKey('techniques', $chars[0]); // not accessible via this route
|
||||
}
|
||||
|
||||
/**
|
||||
* Requirement: A user should be able see all characters from a dojo, but only the public fields!
|
||||
*/
|
||||
public function testRetrieveCharactersFromOwnDojoDetail(): void
|
||||
{
|
||||
$dojo = DojoFactory::createOne([
|
||||
'owner' => UserFactory::createOne()
|
||||
]);
|
||||
CharacterFactory::createMany(4, [
|
||||
'dojo' => $dojo
|
||||
]);
|
||||
CharacterFactory::createMany(10);
|
||||
|
||||
$response = static::createClient()->request('GET', '/api/dojo/characters',
|
||||
[
|
||||
'headers' => [
|
||||
'accept' => 'application/json',
|
||||
'X-AUTH-TOKEN' => $this->generateAuthToken($dojo->getOwner()->authName)
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertResponseStatusCodeSame(200);
|
||||
|
||||
// Because test fixtures are automatically loaded between each test, you can assert on them
|
||||
$this->assertCount(4, $response->toArray());
|
||||
|
||||
$this->assertNotEquals("[[],[],[],[]]", $response->getContent());
|
||||
|
||||
$chars = $response->toArray();
|
||||
$this->assertArrayHasKey('name', $chars[0]);
|
||||
$this->assertArrayHasKey('dojo', $chars[0]);
|
||||
$this->assertArrayHasKey('strength', $chars[0]); // not accessible via this route
|
||||
$this->assertArrayHasKey('constitution', $chars[0]); // not accessible via this route
|
||||
$this->assertArrayHasKey('agility', $chars[0]); // not accessible via this route
|
||||
$this->assertArrayHasKey('techniques', $chars[0]); // not accessible via this route
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue