| @@ -54,13 +54,13 @@ class CommentApi | |||
| #[NotBlank] | |||
| public ?string $message = null; | |||
| #[IsValidOwner] | |||
| #[ApiProperty(writable: false)] | |||
| public ?UserApi $owner = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?string $ownerName = null; | |||
| public ?PostingApi $posting = null; | |||
| public ?PostingApi $post = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?\DateTimeImmutable $createdAt = null; | |||
| @@ -35,7 +35,7 @@ use Symfony\Component\Validator\Constraints\NotBlank; | |||
| security: 'is_granted("ROLE_USER")', | |||
| ), | |||
| new Patch( | |||
| security: 'is_granted("EDIT", object)', | |||
| security: 'is_granted("ROLE_USER")', | |||
| ), | |||
| new Delete( | |||
| security: 'is_granted("ROLE_ADMIN")', | |||
| @@ -59,6 +59,7 @@ class ContactApi | |||
| #[NotBlank] | |||
| public ?string $lastName = null; | |||
| #[NotBlank] | |||
| public ?PartnerApi $partner = null; | |||
| public ?\DateTimeInterface $birthday = null; | |||
| @@ -79,7 +80,7 @@ class ContactApi | |||
| * @var array<int, PostingApi> | |||
| */ | |||
| #[ApiProperty(writable: false)] | |||
| public array $postings = []; | |||
| public array $posts = []; | |||
| #[ApiProperty(writable: false)] | |||
| public ?\DateTimeImmutable $createdAt = null; | |||
| @@ -37,7 +37,7 @@ use Symfony\Component\Validator\Constraints\NotBlank; | |||
| security: 'is_granted("ROLE_USER")', | |||
| ), | |||
| new Patch( | |||
| security: 'is_granted("EDIT", object)', | |||
| security: 'is_granted("ROLE_USER")', | |||
| ), | |||
| new Delete( | |||
| security: 'is_granted("ROLE_ADMIN")', | |||
| @@ -84,5 +84,6 @@ class PartnerApi | |||
| /** | |||
| * @var array<int, ContactApi> | |||
| */ | |||
| #[ApiProperty(writable: false)] | |||
| public array $contacts = []; | |||
| } | |||
| @@ -20,8 +20,9 @@ use ApiPlatform\Metadata\Get; | |||
| use ApiPlatform\Metadata\GetCollection; | |||
| use ApiPlatform\Metadata\Patch; | |||
| use ApiPlatform\Metadata\Post; | |||
| use App\Validator\IsValidOwner; | |||
| use Symfony\Component\PropertyInfo\Type; | |||
| use Symfony\Component\Serializer\Attribute\Groups; | |||
| use Symfony\Component\Validator\Constraints as Assert; | |||
| use Symfony\Component\Validator\Constraints\NotBlank; | |||
| #[ApiResource( | |||
| @@ -34,9 +35,11 @@ use Symfony\Component\Validator\Constraints\NotBlank; | |||
| security: 'is_granted("ROLE_USER")', | |||
| ), | |||
| new Post( | |||
| denormalizationContext: ['groups' => 'posting_create'], | |||
| security: 'is_granted("ROLE_USER")', | |||
| ), | |||
| new Patch( | |||
| denormalizationContext: ['groups' => 'posting_patch'], | |||
| security: 'is_granted("EDIT", object)', | |||
| ), | |||
| new Delete( | |||
| @@ -55,28 +58,35 @@ class PostingApi | |||
| public ?int $id = null; | |||
| #[NotBlank] | |||
| #[Groups(['posting_create', 'posting_patch'])] | |||
| public ?string $headline = null; | |||
| #[NotBlank] | |||
| #[Groups(['posting_create', 'posting_patch'])] | |||
| public ?string $message = null; | |||
| //#[IsValidOwner] | |||
| #[ApiProperty(writable: false)] | |||
| public ?UserApi $owner = null; | |||
| #[ApiProperty(writable: false)] | |||
| public ?string $ownerName = null; | |||
| #[ApiProperty(writable: true)] | |||
| #[Groups(['posting_create'])] | |||
| #[Assert\NotBlank(groups: ['posting_create'])] | |||
| public ?PartnerApi $partner = null; | |||
| #[ApiProperty(writable: true)] | |||
| #[Groups(['posting_create'])] | |||
| public ?ContactApi $contact = null; | |||
| /** | |||
| * @var array<int, CommentApi> | |||
| */ | |||
| #[ApiProperty( | |||
| writable: false, | |||
| readableLink: true, | |||
| writableLink: true, | |||
| writableLink: false, | |||
| fetchEager: true, | |||
| builtinTypes: [ | |||
| new Type( | |||
| @@ -30,10 +30,10 @@ use Symfony\Component\Validator\Constraints as Assert; | |||
| ), | |||
| new Post( | |||
| security: 'is_granted("ROLE_ADMIN")', | |||
| validationContext: ['groups' => ['Default', 'postValidation']], | |||
| validationContext: ['groups' => ['Default', 'postValidation']] | |||
| ), | |||
| new Patch( | |||
| security: 'is_granted("ROLE_USER")' | |||
| security: 'is_granted("is_granted("EDIT", object)")' | |||
| ), | |||
| ], | |||
| security: 'is_granted("ROLE_USER")', | |||
| @@ -74,7 +74,8 @@ class UserApi | |||
| /** | |||
| * @var array<int, PostingApi> | |||
| */ | |||
| public array $postings = []; | |||
| #[ApiProperty(writable: false)] | |||
| public array $posts = []; | |||
| #[ApiProperty(writable: false)] | |||
| public ?\DateTimeImmutable $createdAt = null; | |||
| @@ -28,8 +28,10 @@ class Comment | |||
| #[ORM\Column] | |||
| private ?\DateTimeImmutable $createdAt = null; | |||
| public function __construct() | |||
| public function __construct(User $owner, Posting $posting) | |||
| { | |||
| $this->owner = $owner; | |||
| $this->posting = $posting; | |||
| $this->createdAt = new \DateTimeImmutable(); | |||
| } | |||
| @@ -62,25 +64,11 @@ class Comment | |||
| return $this->owner; | |||
| } | |||
| public function setOwner(?User $owner): static | |||
| { | |||
| $this->owner = $owner; | |||
| return $this; | |||
| } | |||
| public function getPosting(): ?Posting | |||
| { | |||
| return $this->posting; | |||
| } | |||
| public function setPosting(?Posting $posting): static | |||
| { | |||
| $this->posting = $posting; | |||
| return $this; | |||
| } | |||
| public function getCreatedAt(): ?\DateTimeImmutable | |||
| { | |||
| return $this->createdAt; | |||
| @@ -46,13 +46,13 @@ class Contact | |||
| private ?\DateTimeImmutable $createdAt = null; | |||
| #[ORM\OneToMany(mappedBy: 'contact', targetEntity: Posting::class, orphanRemoval: true)] | |||
| private Collection $postings; | |||
| private Collection $posts; | |||
| public function __construct(Partner $partner) | |||
| { | |||
| $this->partner = $partner; | |||
| $this->createdAt = new \DateTimeImmutable(); | |||
| $this->postings = new ArrayCollection(); | |||
| $this->posts = new ArrayCollection(); | |||
| } | |||
| public function getId(): ?int | |||
| @@ -169,15 +169,15 @@ class Contact | |||
| /** | |||
| * @return Collection<int, Posting> | |||
| */ | |||
| public function getPostings(): Collection | |||
| public function getPosts(): Collection | |||
| { | |||
| return $this->postings; | |||
| return $this->posts; | |||
| } | |||
| public function addPosting(Posting $posting): static | |||
| { | |||
| if (!$this->postings->contains($posting)) { | |||
| $this->postings->add($posting); | |||
| if (!$this->posts->contains($posting)) { | |||
| $this->posts->add($posting); | |||
| $posting->setContact($this); | |||
| } | |||
| @@ -186,7 +186,7 @@ class Contact | |||
| public function removePosting(Posting $posting): static | |||
| { | |||
| if ($this->postings->removeElement($posting)) { | |||
| if ($this->posts->removeElement($posting)) { | |||
| // set the owning side to null (unless already changed) | |||
| if ($posting->getContact() === $this) { | |||
| $posting->setContact(null); | |||
| @@ -23,6 +23,7 @@ use Vich\UploaderBundle\Mapping\Annotation as Vich; | |||
| #[Vich\Uploadable] | |||
| #[ORM\Entity] | |||
| #[ApiResource( | |||
| shortName: 'Media', | |||
| types: ['https://schema.org/MediaObject'], | |||
| operations: [ | |||
| new Get(), | |||
| @@ -70,6 +70,11 @@ class Posting | |||
| return $this->createdAt; | |||
| } | |||
| public function setOwner(?User $owner): void | |||
| { | |||
| $this->owner = $owner; | |||
| } | |||
| public function getOwner(): ?User | |||
| { | |||
| return $this->owner; | |||
| @@ -38,7 +38,7 @@ class AuthenticationSuccessListener | |||
| } | |||
| $userApi = $this->microMapper->map($user, UserApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 3, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $data['id'] = $this->iriConverter->getIriFromResource($userApi); | |||
| @@ -46,7 +46,7 @@ final class PostingFactory extends ModelFactory | |||
| */ | |||
| protected function getDefaults(): array | |||
| { | |||
| $randomBoolean = (bool)random_int(0, 1); | |||
| $randomBoolean = ContactFactory::count() > 0 && (bool)random_int(0, 1); | |||
| return [ | |||
| 'headline' => self::faker()->words(random_int(1, 5), true), | |||
| 'message' => $randomBoolean ? self::faker()->sentence() : self::faker()->sentences(random_int(1, 3), true), | |||
| @@ -4,6 +4,7 @@ namespace App\Mapper; | |||
| use App\ApiResource\CommentApi; | |||
| use App\Entity\Comment; | |||
| use App\Entity\Posting; | |||
| use App\Entity\User; | |||
| use App\Repository\CommentRepository; | |||
| use Symfony\Bundle\SecurityBundle\Security; | |||
| @@ -28,7 +29,21 @@ class CommentApiToEntityMapper implements MapperInterface | |||
| $dto = $from; | |||
| assert($dto instanceof CommentApi); | |||
| $entity = $dto->id ? $this->repository->find($dto->id) : new Comment(); | |||
| if ($dto->id) { | |||
| $entity = $this->repository->find($dto->id); | |||
| } else { | |||
| $user = $this->security->getUser(); | |||
| assert($user instanceof User); | |||
| if ($dto->post === null) { | |||
| throw new \Exception('Posting missing'); | |||
| } | |||
| $posting = $this->microMapper->map($dto->post, Posting::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| assert($posting instanceof Posting); | |||
| $entity = new Comment($user, $posting); | |||
| } | |||
| if (!$entity) { | |||
| throw new \Exception('Comment not found'); | |||
| } | |||
| @@ -42,15 +57,6 @@ class CommentApiToEntityMapper implements MapperInterface | |||
| assert($dto instanceof CommentApi); | |||
| $entity = $to; | |||
| assert($entity instanceof Comment); | |||
| if ($dto->owner) { | |||
| $entity->setOwner($this->microMapper->map($dto->owner, User::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ])); | |||
| } else { | |||
| $entity->setOwner($this->security->getUser()); | |||
| } | |||
| $entity->setPosting($dto->posting); | |||
| $entity->setMessage($dto->message); | |||
| return $entity; | |||
| @@ -15,8 +15,7 @@ use Symfonycasts\MicroMapper\MicroMapperInterface; | |||
| class CommentEntityToApiMapper implements MapperInterface | |||
| { | |||
| public function __construct( | |||
| private MicroMapperInterface $microMapper, | |||
| private Security $security, | |||
| private MicroMapperInterface $microMapper | |||
| ) | |||
| { | |||
| } | |||
| @@ -41,12 +40,12 @@ class CommentEntityToApiMapper implements MapperInterface | |||
| $dto->message = $entity->getMessage(); | |||
| $dto->owner = $this->microMapper->map($entity->getOwner(), UserApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $dto->ownerName = $entity->getOwner()?->getFirstName()." ".$entity->getOwner()?->getLastName(); | |||
| $dto->posting = $this->microMapper->map($entity->getPosting(), PostingApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $dto->createdAt = $entity->getCreatedAt(); | |||
| @@ -17,7 +17,6 @@ class ContactApiToEntityMapper implements MapperInterface | |||
| { | |||
| public function __construct( | |||
| private ContactRepository $repository, | |||
| private Security $security, | |||
| private MicroMapperInterface $microMapper, | |||
| ) | |||
| { | |||
| @@ -36,7 +35,7 @@ class ContactApiToEntityMapper implements MapperInterface | |||
| throw new \Exception('Partner missing'); | |||
| } | |||
| $partner = $this->microMapper->map($dto->partner, Partner::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $entity = new Contact($partner); | |||
| } | |||
| @@ -58,7 +57,6 @@ class ContactApiToEntityMapper implements MapperInterface | |||
| $entity->setFirstName($dto->firstName); | |||
| $entity->setLastName($dto->lastName); | |||
| $entity->setPartner($dto->partner); | |||
| $entity->setBirthday($dto->birthday); | |||
| $entity->setImage($dto->image); | |||
| $entity->setPosition($dto->position); | |||
| @@ -44,7 +44,7 @@ class ContactEntityToApiMapper implements MapperInterface | |||
| $dto->lastName = $entity->getLastName(); | |||
| $dto->partner = $this->microMapper->map( | |||
| $entity->getPartner(), PartnerApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ] | |||
| ); | |||
| $dto->birthday = $entity->getBirthday(); | |||
| @@ -55,11 +55,11 @@ class ContactEntityToApiMapper implements MapperInterface | |||
| $dto->email = $entity->getEmail(); | |||
| $dto->createdAt = $entity->getCreatedAt(); | |||
| $dto->postings = array_map(function(Posting $posting) { | |||
| $dto->posts = array_map(function(Posting $posting) { | |||
| return $this->microMapper->map($posting, PostingApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| }, $entity->getPostings()->getValues()); | |||
| }, $entity->getPosts()->getValues()); | |||
| return $dto; | |||
| } | |||
| @@ -19,10 +19,7 @@ use Symfonycasts\MicroMapper\MicroMapperInterface; | |||
| class PartnerApiToEntityMapper implements MapperInterface | |||
| { | |||
| public function __construct( | |||
| private PartnerRepository $repository, | |||
| private Security $security, | |||
| private MicroMapperInterface $microMapper, | |||
| private PropertyAccessorInterface $propertyAccessor, | |||
| private PartnerRepository $repository | |||
| ) | |||
| { | |||
| @@ -58,14 +55,6 @@ class PartnerApiToEntityMapper implements MapperInterface | |||
| $entity->setWebsite($dto->website); | |||
| $entity->setLogo($dto->logo); | |||
| $contactEntities = []; | |||
| foreach ($dto->contacts as $contactApi) { | |||
| $contactEntities[] = $this->microMapper->map($contactApi, Contact::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| ]); | |||
| } | |||
| $this->propertyAccessor->setValue($entity, 'contacts', $contactEntities); | |||
| return $entity; | |||
| } | |||
| } | |||
| @@ -52,7 +52,7 @@ class PartnerEntityToApiMapper implements MapperInterface | |||
| $dto->createdAt = $entity->getCreatedAt(); | |||
| $dto->contacts = array_map(function(Contact $contact) { | |||
| return $this->microMapper->map($contact, ContactApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| }, $entity->getContacts()->getValues()); | |||
| return $dto; | |||
| @@ -40,13 +40,13 @@ class PostingApiToEntityMapper implements MapperInterface | |||
| throw new \Exception('Partner missing'); | |||
| } | |||
| $partner = $this->microMapper->map($dto->partner, Partner::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| $contact = null; | |||
| if ($dto->contact) { | |||
| assert($dto->contact instanceof ContactApi); | |||
| $contact = $this->microMapper->map($dto->contact, Contact::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| } | |||
| assert($partner instanceof Partner); | |||
| @@ -53,9 +53,9 @@ class UserApiToEntityMapper implements MapperInterface | |||
| } | |||
| $userPostsEntities = new ArrayCollection(); | |||
| foreach ($dto->postings as $userPostApi) { | |||
| foreach ($dto->posts as $userPostApi) { | |||
| $userPostsEntities[] = $this->microMapper->map($userPostApi, Posting::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| } | |||
| $this->propertyAccessor->setValue($entity, 'postings', $userPostsEntities); | |||
| @@ -41,9 +41,9 @@ class UserEntityToApiMapper implements MapperInterface | |||
| $dto->firstName = $entity->getFirstName(); | |||
| $dto->lastName = $entity->getLastName(); | |||
| $dto->postings = array_map(function(Posting $posting) { | |||
| $dto->posts = array_map(function(Posting $posting) { | |||
| return $this->microMapper->map($posting, PostingApi::class, [ | |||
| MicroMapperInterface::MAX_DEPTH => 0, | |||
| MicroMapperInterface::MAX_DEPTH => 1, | |||
| ]); | |||
| }, $entity->getPostings()->getValues()); | |||
| @@ -0,0 +1,46 @@ | |||
| <?php | |||
| namespace App\Voter; | |||
| use App\ApiResource\CommentApi; | |||
| use App\ApiResource\PostingApi; | |||
| use App\Entity\User; | |||
| use Symfony\Bundle\SecurityBundle\Security; | |||
| use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |||
| use Symfony\Component\Security\Core\Authorization\Voter\Voter; | |||
| class CommentApiVoter extends Voter | |||
| { | |||
| public const EDIT = 'EDIT'; | |||
| public function __construct() | |||
| { | |||
| } | |||
| protected function supports(string $attribute, mixed $subject): bool | |||
| { | |||
| return $attribute === self::EDIT && $subject instanceof CommentApi; | |||
| } | |||
| protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool | |||
| { | |||
| $user = $token->getUser(); | |||
| // if the user is anonymous, do not grant access | |||
| if (!$user instanceof User) { | |||
| return false; | |||
| } | |||
| assert($subject instanceof CommentApi); | |||
| // ... (check conditions and return true to grant permission) ... | |||
| switch ($attribute) { | |||
| case self::EDIT: | |||
| if ($subject->owner?->id === $user->getId()) { | |||
| return true; | |||
| } | |||
| break; | |||
| } | |||
| return false; | |||
| } | |||
| } | |||
| @@ -12,13 +12,13 @@ class PostingApiVoter extends Voter | |||
| { | |||
| public const EDIT = 'EDIT'; | |||
| public function __construct(private Security $security) | |||
| public function __construct() | |||
| { | |||
| } | |||
| protected function supports(string $attribute, mixed $subject): bool | |||
| { | |||
| return in_array($attribute, [self::EDIT]) && $subject instanceof PostingApi; | |||
| return $attribute === self::EDIT && $subject instanceof PostingApi; | |||
| } | |||
| protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool | |||
| @@ -29,10 +29,6 @@ class PostingApiVoter extends Voter | |||
| return false; | |||
| } | |||
| if ($this->security->isGranted('ROLE_ADMIN')) { | |||
| return true; | |||
| } | |||
| assert($subject instanceof PostingApi); | |||
| // ... (check conditions and return true to grant permission) ... | |||
| @@ -18,12 +18,11 @@ class UserApiVoter extends Voter | |||
| protected function supports(string $attribute, mixed $subject): bool | |||
| { | |||
| return in_array($attribute, [self::EDIT]) && $subject instanceof UserApi; | |||
| return $attribute === self::EDIT && $subject instanceof UserApi; | |||
| } | |||
| protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool | |||
| { | |||
| //dd($subject); | |||
| $user = $token->getUser(); | |||
| // if the user is anonymous, do not grant access | |||
| if (!$user instanceof User) { | |||
| @@ -0,0 +1,78 @@ | |||
| <?php | |||
| /** | |||
| * @author Daniel Knudsen <d.knudsen@spawntree.de> | |||
| * @date 12.12.23 | |||
| */ | |||
| namespace App\Tests\Functional; | |||
| use App\Enum\PartnerType; | |||
| use App\Factory\CommentFactory; | |||
| use App\Factory\MediaObjectLogoFactory; | |||
| use App\Factory\MediaObjectProfileFactory; | |||
| use App\Factory\PartnerFactory; | |||
| use App\Factory\PostingFactory; | |||
| use App\Factory\UserFactory; | |||
| use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; | |||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
| use Zenstruck\Browser\Test\HasBrowser; | |||
| use Zenstruck\Foundry\Test\Factories; | |||
| use Zenstruck\Foundry\Test\ResetDatabase; | |||
| class CommentResourceTest extends KernelTestCase | |||
| { | |||
| use HasBrowser; | |||
| use ResetDatabase; | |||
| use Factories; | |||
| private JWTTokenManagerInterface $JWTManager; | |||
| protected function setUp(): void | |||
| { | |||
| parent::setUp(); | |||
| $this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager'); | |||
| } | |||
| public function testPostComment(): void | |||
| { | |||
| $user = UserFactory::createOne( | |||
| [ | |||
| 'firstName' => 'Peter', | |||
| 'lastName' => 'Test', | |||
| 'password' => 'test', | |||
| 'email' => 'peter@test.de', | |||
| ] | |||
| ); | |||
| MediaObjectLogoFactory::createOne(); | |||
| PartnerFactory::createOne(); | |||
| $posting = PostingFactory::createOne(); | |||
| CommentFactory::createOne(); | |||
| $token = $this->JWTManager->create($user->object()); | |||
| $this->browser() | |||
| ->post('/api/comments' , [ | |||
| 'json' => [ | |||
| 'message' => 'my comment', | |||
| 'post' => '/api/posts/' . $posting->getId(), | |||
| ], | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| ] | |||
| ]) | |||
| ->assertSuccessful() | |||
| ; | |||
| $this->browser() | |||
| ->get('/api/comments', [ | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| ], | |||
| ]) | |||
| ->assertSuccessful() | |||
| ->assertJsonMatches('"hydra:totalItems"', 2) | |||
| ->assertJsonMatches('"hydra:member"[1].message', 'my comment') | |||
| ; | |||
| } | |||
| } | |||
| @@ -0,0 +1,82 @@ | |||
| <?php | |||
| /** | |||
| * @author Daniel Knudsen <d.knudsen@spawntree.de> | |||
| * @date 12.12.23 | |||
| */ | |||
| namespace App\Tests\Functional; | |||
| use App\Enum\PartnerType; | |||
| use App\Factory\MediaObjectLogoFactory; | |||
| use App\Factory\MediaObjectProfileFactory; | |||
| use App\Factory\PartnerFactory; | |||
| use App\Factory\UserFactory; | |||
| use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; | |||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
| use Zenstruck\Browser\Test\HasBrowser; | |||
| use Zenstruck\Foundry\Test\Factories; | |||
| use Zenstruck\Foundry\Test\ResetDatabase; | |||
| class ContactResourceTest extends KernelTestCase | |||
| { | |||
| use HasBrowser; | |||
| use ResetDatabase; | |||
| use Factories; | |||
| private JWTTokenManagerInterface $JWTManager; | |||
| protected function setUp(): void | |||
| { | |||
| parent::setUp(); | |||
| $this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager'); | |||
| } | |||
| public function testPostContact(): void | |||
| { | |||
| MediaObjectLogoFactory::createOne(); | |||
| $partner = PartnerFactory::createOne(); | |||
| $user = UserFactory::createOne( | |||
| [ | |||
| 'firstName' => 'Peter', | |||
| 'lastName' => 'Test', | |||
| 'password' => 'test', | |||
| 'email' => 'peter@test.de', | |||
| ] | |||
| ); | |||
| $mediaObject = MediaObjectProfileFactory::createOne(); | |||
| $token = $this->JWTManager->create($user->object()); | |||
| $this->browser() | |||
| ->post('/api/contacts' , [ | |||
| 'json' => [ | |||
| 'firstName' => 'Peter', | |||
| 'lastName' => 'Test', | |||
| 'partner' => '/api/partners/' . $partner->getId(), | |||
| 'birthday' => '1984-02-10', | |||
| 'image' => '/api/medias/' . $mediaObject->getId(), | |||
| 'position' => 'CEO', | |||
| 'phone' => '123456789', | |||
| 'email' => 'peter@test2.de', | |||
| ], | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| ] | |||
| ]) | |||
| ->assertSuccessful() | |||
| ; | |||
| $this->browser() | |||
| ->get('/api/contacts', [ | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| ], | |||
| ]) | |||
| ->assertSuccessful() | |||
| ->assertJsonMatches('"hydra:totalItems"', 1) | |||
| ->assertJsonMatches('"hydra:member"[0].position', 'CEO') | |||
| ; | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| <?php | |||
| /** | |||
| * @author Daniel Knudsen <d.knudsen@spawntree.de> | |||
| * @date 01.03.24 | |||
| */ | |||
| namespace App\Tests\Functional; | |||
| use App\Factory\UserFactory; | |||
| use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; | |||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
| use Symfony\Component\HttpFoundation\File\UploadedFile; | |||
| use Zenstruck\Browser\Test\HasBrowser; | |||
| use Zenstruck\Foundry\Test\Factories; | |||
| use Zenstruck\Foundry\Test\ResetDatabase; | |||
| class MediaObjectResourceTest extends KernelTestCase | |||
| { | |||
| use HasBrowser; | |||
| use ResetDatabase; | |||
| use Factories; | |||
| private JWTTokenManagerInterface $JWTManager; | |||
| private string $projectDir; | |||
| protected function setUp(): void | |||
| { | |||
| parent::setUp(); | |||
| $this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager'); | |||
| $this->projectDir = self::getContainer()->get('kernel')->getProjectDir(); | |||
| } | |||
| public function testCreateAMediaObject(): void | |||
| { | |||
| $path = $this->projectDir . '/tests/fixtures/'; | |||
| $srcFile = $path . '1176.png'; | |||
| $dstFile = $path . '1176_upload.png'; | |||
| copy($srcFile, $dstFile); | |||
| $file = new UploadedFile($dstFile, 'image.png'); | |||
| $user = UserFactory::createOne( | |||
| [ | |||
| 'firstName' => 'Peter', | |||
| 'lastName' => 'Test', | |||
| 'password' => 'test', | |||
| 'email' => 'peter@test.de', | |||
| ] | |||
| ); | |||
| $token = $this->JWTManager->create($user->object()); | |||
| $this->browser() | |||
| ->post('/api/medias', [ | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| 'Content-Type' => 'multipart/form-data' | |||
| ], | |||
| 'files' => [ | |||
| 'file' => $file, | |||
| ], | |||
| ]) | |||
| ->assertSuccessful() | |||
| ; | |||
| } | |||
| } | |||
| @@ -0,0 +1,79 @@ | |||
| <?php | |||
| /** | |||
| * @author Daniel Knudsen <d.knudsen@spawntree.de> | |||
| * @date 12.12.23 | |||
| */ | |||
| namespace App\Tests\Functional; | |||
| use App\Enum\PartnerType; | |||
| use App\Factory\MediaObjectLogoFactory; | |||
| use App\Factory\UserFactory; | |||
| use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; | |||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
| use Zenstruck\Browser\Test\HasBrowser; | |||
| use Zenstruck\Foundry\Test\Factories; | |||
| use Zenstruck\Foundry\Test\ResetDatabase; | |||
| class PartnerResourceTest extends KernelTestCase | |||
| { | |||
| use HasBrowser; | |||
| use ResetDatabase; | |||
| use Factories; | |||
| private JWTTokenManagerInterface $JWTManager; | |||
| protected function setUp(): void | |||
| { | |||
| parent::setUp(); | |||
| $this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager'); | |||
| } | |||
| public function testPostPartner(): void | |||
| { | |||
| $user = UserFactory::createOne( | |||
| [ | |||
| 'email' => 'peter@test.de', | |||
| 'firstName' => 'Peter', | |||
| 'lastName' => 'Test', | |||
| 'password' => 'test', | |||
| ] | |||
| ); | |||
| $mediaObject = MediaObjectLogoFactory::createOne(); | |||
| $token = $this->JWTManager->create($user->object()); | |||
| $this->browser() | |||
| ->post('/api/partners' , [ | |||
| 'json' => [ | |||
| 'name' => 'test customer', | |||
| 'type' => PartnerType::Customer, | |||
| 'street' => 'test street', | |||
| 'streetNo' => '11', | |||
| 'zip' => '22335', | |||
| 'city' => 'test city', | |||
| 'country' => 'test country', | |||
| 'website' => 'wwe.test.de', | |||
| 'logo' => '/api/medias/' . $mediaObject->getId(), | |||
| ], | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| 'Content-Type' => 'application/ld+json' | |||
| ] | |||
| ]) | |||
| ->assertSuccessful() | |||
| ; | |||
| $this->browser() | |||
| ->get('/api/partners', [ | |||
| 'headers' => [ | |||
| 'Authorization' => 'Bearer ' . $token, | |||
| ], | |||
| ]) | |||
| ->assertSuccessful() | |||
| ->assertJsonMatches('"hydra:totalItems"', 1) | |||
| ->assertJsonMatches('"hydra:member"[0].name', 'test customer') | |||
| ; | |||
| } | |||
| } | |||
| @@ -13,6 +13,7 @@ use App\Factory\MediaObjectProfileFactory; | |||
| use App\Factory\PartnerFactory; | |||
| use App\Factory\PostingFactory; | |||
| use App\Factory\UserFactory; | |||
| use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; | |||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
| use Zenstruck\Browser\Test\HasBrowser; | |||
| use Zenstruck\Foundry\Test\Factories; | |||
| @@ -24,9 +25,17 @@ class PostingResourceTest extends KernelTestCase | |||
| use ResetDatabase; | |||
| use Factories; | |||
| private JWTTokenManagerInterface $JWTManager; | |||
| protected function setUp(): void | |||
| { | |||
| parent::setUp(); | |||
| $this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager'); | |||
| } | |||
| public function testPostPosting(): void | |||
| { | |||
| UserFactory::createOne( | |||
| $user = UserFactory::createOne( | |||
| [ | |||
| 'email' => 'peter@test.de', | |||
| 'firstName' => 'Peter', | |||
| @@ -41,17 +50,7 @@ class PostingResourceTest extends KernelTestCase | |||
| $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']; | |||
| $token = $this->JWTManager->create($user->object()); | |||
| $this->browser() | |||
| ->post('/api/posts' , [ | |||
| @@ -8,6 +8,7 @@ | |||
| namespace App\Tests\Functional; | |||
| use App\Factory\UserFactory; | |||
| use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface; | |||
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |||
| use Zenstruck\Browser\Json; | |||
| use Zenstruck\Browser\Test\HasBrowser; | |||
| @@ -20,6 +21,14 @@ class UserResourceTest extends KernelTestCase | |||
| use ResetDatabase; | |||
| use Factories; | |||
| private JWTTokenManagerInterface $JWTManager; | |||
| protected function setUp(): void | |||
| { | |||
| parent::setUp(); | |||
| $this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager'); | |||
| } | |||
| public function testPostUser(): void | |||
| { | |||
| UserFactory::createOne( | |||
| @@ -79,7 +88,7 @@ class UserResourceTest extends KernelTestCase | |||
| public function testPostUserNoAdmin(): void | |||
| { | |||
| UserFactory::createOne( | |||
| $user = UserFactory::createOne( | |||
| [ | |||
| 'email' => 'peter@test.de', | |||
| 'firstName' => 'Peter', | |||
| @@ -87,18 +96,8 @@ class UserResourceTest extends KernelTestCase | |||
| 'password' => 'test', | |||
| ] | |||
| ); | |||
| $response = $this->browser() | |||
| ->post('/auth', [ | |||
| 'json' => [ | |||
| 'email' => 'peter@test.de', | |||
| 'password' => 'test', | |||
| ] | |||
| ]) | |||
| ->assertSuccessful() | |||
| ->content(); | |||
| $authResponseData = json_decode($response, true); | |||
| $token = $authResponseData['token']; | |||
| $token = $this->JWTManager->create($user->object()); | |||
| $this->browser() | |||
| ->post('/api/users' , [ | |||
| 'json' => [ | |||