Daniel пре 2 година
родитељ
комит
69d3cc25dd
9 измењених фајлова са 202 додато и 91 уклоњено
  1. +2
    -0
      src/ApiResource/ContactApi.php
  2. +2
    -1
      src/ApiResource/PostingApi.php
  3. +1
    -1
      src/ApiResource/UserApi.php
  4. +2
    -1
      src/Entity/Contact.php
  5. +4
    -8
      src/Entity/Posting.php
  6. +17
    -3
      src/Mapper/ContactApiToEntityMapper.php
  7. +27
    -14
      src/Mapper/PostingApiToEntityMapper.php
  8. +81
    -0
      tests/Functional/PostingResourceTest.php
  9. +66
    -63
      tests/Functional/UserResourceTest.php

+ 2
- 0
src/ApiResource/ContactApi.php Прегледај датотеку

@@ -78,7 +78,9 @@ class ContactApi
/** /**
* @var array<int, PostingApi> * @var array<int, PostingApi>
*/ */
#[ApiProperty(writable: false)]
public array $postings = []; public array $postings = [];


#[ApiProperty(writable: false)]
public ?\DateTimeImmutable $createdAt = null; public ?\DateTimeImmutable $createdAt = null;
} }

+ 2
- 1
src/ApiResource/PostingApi.php Прегледај датотеку

@@ -60,7 +60,8 @@ class PostingApi
#[NotBlank] #[NotBlank]
public ?string $message = null; public ?string $message = null;


#[IsValidOwner]
//#[IsValidOwner]
#[ApiProperty(writable: false)]
public ?UserApi $owner = null; public ?UserApi $owner = null;


#[ApiProperty(writable: false)] #[ApiProperty(writable: false)]


+ 1
- 1
src/ApiResource/UserApi.php Прегледај датотеку

@@ -29,7 +29,7 @@ use Symfony\Component\Validator\Constraints as Assert;
security: 'is_granted("ROLE_USER")' security: 'is_granted("ROLE_USER")'
), ),
new Post( new Post(
security: 'is_granted("PUBLIC_ACCESS")',
security: 'is_granted("ROLE_ADMIN")',
validationContext: ['groups' => ['Default', 'postValidation']], validationContext: ['groups' => ['Default', 'postValidation']],
), ),
new Patch( new Patch(


+ 2
- 1
src/Entity/Contact.php Прегледај датотеку

@@ -48,8 +48,9 @@ class Contact
#[ORM\OneToMany(mappedBy: 'contact', targetEntity: Posting::class, orphanRemoval: true)] #[ORM\OneToMany(mappedBy: 'contact', targetEntity: Posting::class, orphanRemoval: true)]
private Collection $postings; private Collection $postings;


public function __construct()
public function __construct(Partner $partner)
{ {
$this->partner = $partner;
$this->createdAt = new \DateTimeImmutable(); $this->createdAt = new \DateTimeImmutable();
$this->postings = new ArrayCollection(); $this->postings = new ArrayCollection();
} }


+ 4
- 8
src/Entity/Posting.php Прегледај датотеку

@@ -39,8 +39,11 @@ class Posting
#[ORM\OneToMany(mappedBy: 'posting', targetEntity: Comment::class, orphanRemoval: true)] #[ORM\OneToMany(mappedBy: 'posting', targetEntity: Comment::class, orphanRemoval: true)]
private Collection $comments; private Collection $comments;


public function __construct()
public function __construct(User $owner, Partner $partner, Contact $contact = null)
{ {
$this->owner = $owner;
$this->partner = $partner;
$this->contact = $contact;
$this->createdAt = new \DateTimeImmutable(); $this->createdAt = new \DateTimeImmutable();
$this->comments = new ArrayCollection(); $this->comments = new ArrayCollection();
} }
@@ -72,13 +75,6 @@ class Posting
return $this->owner; return $this->owner;
} }


public function setOwner(?User $owner): static
{
$this->owner = $owner;

return $this;
}

public function getHeadline(): ?string public function getHeadline(): ?string
{ {
return $this->headline; return $this->headline;


+ 17
- 3
src/Mapper/ContactApiToEntityMapper.php Прегледај датотеку

@@ -4,6 +4,8 @@ namespace App\Mapper;


use App\ApiResource\ContactApi; use App\ApiResource\ContactApi;
use App\Entity\Contact; use App\Entity\Contact;
use App\Entity\Partner;
use App\Repository\ContactRepository;
use App\Repository\PartnerRepository; use App\Repository\PartnerRepository;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper; use Symfonycasts\MicroMapper\AsMapper;
@@ -14,7 +16,7 @@ use Symfonycasts\MicroMapper\MicroMapperInterface;
class ContactApiToEntityMapper implements MapperInterface class ContactApiToEntityMapper implements MapperInterface
{ {
public function __construct( public function __construct(
private PartnerRepository $repository,
private ContactRepository $repository,
private Security $security, private Security $security,
private MicroMapperInterface $microMapper, private MicroMapperInterface $microMapper,
) )
@@ -27,9 +29,21 @@ class ContactApiToEntityMapper implements MapperInterface
$dto = $from; $dto = $from;
assert($dto instanceof ContactApi); assert($dto instanceof ContactApi);


$entity = $dto->id ? $this->repository->find($dto->id) : new Contact();
if ($dto->id) {
$entity = $this->repository->find($dto->id);
} else {
if ($dto->partner === null) {
throw new \Exception('Partner missing');
}
$partner = $this->microMapper->map($dto->partner, Partner::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);
$entity = new Contact($partner);
}


if (!$entity) { if (!$entity) {
throw new \Exception('Partner not found');
throw new \Exception('Contact not found');
} }


return $entity; return $entity;


+ 27
- 14
src/Mapper/PostingApiToEntityMapper.php Прегледај датотеку

@@ -2,12 +2,12 @@


namespace App\Mapper; namespace App\Mapper;


use App\ApiResource\DragonTreasureApi;
use App\ApiResource\ContactApi;
use App\ApiResource\PostingApi; use App\ApiResource\PostingApi;
use App\Entity\DragonTreasure;
use App\Entity\Contact;
use App\Entity\Partner;
use App\Entity\User; use App\Entity\User;
use App\Entity\Posting; use App\Entity\Posting;
use App\Repository\DragonTreasureRepository;
use App\Repository\PostingRepository; use App\Repository\PostingRepository;
use Symfony\Bundle\SecurityBundle\Security; use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper; use Symfonycasts\MicroMapper\AsMapper;
@@ -31,7 +31,29 @@ class PostingApiToEntityMapper implements MapperInterface
$dto = $from; $dto = $from;
assert($dto instanceof PostingApi); assert($dto instanceof PostingApi);


$entity = $dto->id ? $this->repository->find($dto->id) : new Posting();
if ($dto->id) {
$entity = $this->repository->find($dto->id);
} else {
$user = $this->security->getUser();
assert($user instanceof User);
if ($dto->partner === null) {
throw new \Exception('Partner missing');
}
$partner = $this->microMapper->map($dto->partner, Partner::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);
$contact = null;
if ($dto->contact) {
assert($dto->contact instanceof ContactApi);
$contact = $this->microMapper->map($dto->contact, Contact::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);
}
assert($partner instanceof Partner);
assert($contact === null || $contact instanceof Contact);
$entity = new Posting($user, $partner, $contact);
}

if (!$entity) { if (!$entity) {
throw new \Exception('Posting not found'); throw new \Exception('Posting not found');
} }
@@ -46,16 +68,7 @@ class PostingApiToEntityMapper implements MapperInterface
$entity = $to; $entity = $to;
assert($entity instanceof Posting); assert($entity instanceof Posting);


if ($dto->owner) {
$entity->setOwner($this->microMapper->map($dto->owner, User::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]));
} else {
$entity->setOwner($this->security->getUser());
}

$entity->setPartner($dto->partner);
$entity->setContact($dto->contact);
$entity->setHeadline($dto->headline);
$entity->setMessage($dto->message); $entity->setMessage($dto->message);


return $entity; return $entity;


+ 81
- 0
tests/Functional/PostingResourceTest.php Прегледај датотеку

@@ -0,0 +1,81 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 12.12.23
*/


namespace App\Tests\Functional;

use App\Factory\ContactFactory;
use App\Factory\MediaObjectLogoFactory;
use App\Factory\MediaObjectProfileFactory;
use App\Factory\PartnerFactory;
use App\Factory\PostingFactory;
use App\Factory\UserFactory;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Zenstruck\Browser\Test\HasBrowser;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;

class PostingResourceTest extends KernelTestCase
{
use HasBrowser;
use ResetDatabase;
use Factories;

public function testPostPosting(): void
{
UserFactory::createOne(
[
'email' => 'peter@test.de',
'firstName' => 'Peter',
'lastName' => 'Test',
'password' => 'test',
]
);

MediaObjectProfileFactory::createOne();
MediaObjectLogoFactory::createOne();
$partner = PartnerFactory::createOne();
$contact = ContactFactory::createOne();
PostingFactory::createOne();

$response = $this->browser()
->post('/auth', [
'json' => [
'email' => 'peter@test.de',
'password' => 'test',
]
])
->assertSuccessful()
->content();
$authResponseData = json_decode($response, true);
$token = $authResponseData['token'];

$this->browser()
->post('/api/posts' , [
'json' => [
'headline' => 'hello',
'message' => 'world',
'partner' => '/api/partners/' . $partner->getId(),
'contact' => '/api/contacts/' . $contact->getId(),
],
'headers' => [
'Authorization' => 'Bearer ' . $token,
]
])
->assertSuccessful()
;

$this->browser()
->get('/api/posts', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
],
])
->assertSuccessful()
->assertJsonMatches('"hydra:totalItems"', 2)
;
}
}

+ 66
- 63
tests/Functional/UserResourceTest.php Прегледај датотеку

@@ -20,95 +20,98 @@ class UserResourceTest extends KernelTestCase
use ResetDatabase; use ResetDatabase;
use Factories; use Factories;


public function testPostToCreateUser(): void
public function testPostUser(): void
{ {
$this->browser()
->post('/api/users', [
UserFactory::createOne(
[
'email' => 'peter@test.de',
'firstName' => 'Peter',
'lastName' => 'Test',
'password' => 'test',
'roles' => ["ROLE_ADMIN"]
]
);
$response = $this->browser()
->post('/auth', [
'json' => [ 'json' => [
'email' => 'draggin_in_the_morning@coffee.com',
'firstName' => 'Danny',
'lastName' => 'Boy',
'password' => 'password',
'email' => 'peter@test.de',
'password' => 'test',
] ]
]) ])
->assertStatus(201)
->use(function (Json $json) { ->use(function (Json $json) {
$json->assertMissing('password');
$json->assertMissing('id');
$json->assertHas('token');
$json->assertHas('id');
$json->assertHas('email');
$json->assertHas('firstName');
$json->assertHas('lastName');
$json->assertHas('roles');
}) })
->post('/auth', [
->assertSuccessful()
->content();
$authResponseData = json_decode($response, true);
$token = $authResponseData['token'];

$this->browser()
->post('/api/users' , [
'json' => [ 'json' => [
'email' => 'draggin_in_the_morning@coffee.com',
'password' => 'password',
'email' => 'norbert@test.de',
'firstName' => 'Norbert',
'lastName' => 'Test',
'password' => 'sehr geheim',
],
'headers' => [
'Authorization' => 'Bearer ' . $token,
] ]
]) ])
->assertSuccessful() ->assertSuccessful()
; ;
}

public function testGetUsersWithoutAuthentication()
{
UserFactory::createMany(2);
$this->browser()
->get('/api/users')
->assertStatus(401)
;
}

public function testGetOneUserWithoutAuthentication()
{
UserFactory::createOne();
$this->browser()
->get('/api/users/1')
->assertStatus(401)
;
}

public function testPatchUserAsSameUser()
{
$user = UserFactory::createOne(
[
'firstName' => 'John',
'lastName' => 'Doe'
]
);


$this->browser() $this->browser()
->actingAs($user)
->patch('/api/users/' . $user->getId(), [
->post('/auth', [
'json' => [ 'json' => [
'firstName' => 'Joe',
'lastName' => 'Black'
],
'headers' => ['Content-Type' => 'application/merge-patch+json']
'email' => 'norbert@test.de',
'password' => 'sehr geheim',
]
]) ])
->assertStatus(200)
->get('/api/users/' . $user->getId())
->assertStatus(200)
->assertJsonMatches('firstName', 'Joe')
->assertJsonMatches('lastName', 'Black')
;
->assertSuccessful()
->assertJsonMatches('email', 'norbert@test.de');
} }


public function testPatchUserInactiveAsSameUser()
public function testPostUserNoAdmin(): void
{ {
$user = UserFactory::createOne(
UserFactory::createOne(
[ [
'firstName' => 'John'
'email' => 'peter@test.de',
'firstName' => 'Peter',
'lastName' => 'Test',
'password' => 'test',
] ]
); );
$response = $this->browser()
->post('/auth', [
'json' => [
'email' => 'peter@test.de',
'password' => 'test',
]
])
->assertSuccessful()
->content();
$authResponseData = json_decode($response, true);
$token = $authResponseData['token'];


$this->browser() $this->browser()
->actingAs($user)
->patch('/api/users/' . $user->getId(), [
->post('/api/users' , [
'json' => [ 'json' => [
'firstName' => 'Joe'
'email' => 'norbert@test.de',
'firstName' => 'Norbert',
'lastName' => 'Test',
'password' => 'sehr geheim',
], ],
'headers' => ['Content-Type' => 'application/merge-patch+json']
'headers' => [
'Authorization' => 'Bearer ' . $token,
]
]) ])
->assertStatus(200)
->get('/api/users/' . $user->getId())
->assertJsonMatches('firstName', 'A shiny thing')
->assertStatus(403);
; ;
} }
} }

Loading…
Откажи
Сачувај