From b204a5d93f93b13fad929172429c3365fce04185 Mon Sep 17 00:00:00 2001 From: Aleksandr Burov Date: Thu, 19 Nov 2020 14:51:52 +0300 Subject: [PATCH 1/4] [Item] CAES-1512: Refactoring meta, implemented endpoint to check exists items. --- src/Controller/Api/Item/ItemController.php | 36 +++++++++++++ src/Entity/Embedded/ItemMeta.php | 42 +++++++++++----- src/Entity/Item.php | 17 ------- src/Factory/Entity/ItemFactory.php | 11 ++-- src/Factory/Entity/MemberFactory.php | 5 +- src/Factory/Entity/ShareFactory.php | 5 +- src/Factory/Entity/VaultFactory.php | 5 +- src/Factory/View/Item/ItemMetaViewFactory.php | 5 +- src/Factory/View/Item/ItemViewFactory.php | 2 - .../Request/Item/CreateItemRequestType.php | 1 - .../Type/Request/Item/EditItemRequestType.php | 1 - src/Form/Type/Request/Item/ItemMetaType.php | 5 +- .../Item/ItemsIdCollectionRequestType.php | 33 ++++++++++++ .../2020/11/Version20201119102626.php | 35 +++++++++++++ src/Model/View/Item/ItemMetaView.php | 35 +++++++++---- src/Model/View/Item/ItemView.php | 19 +------ src/Modifier/ItemModifier.php | 6 +-- src/Repository/ItemRepository.php | 20 ++++++++ src/Request/Item/CreateItemRequest.php | 15 ------ src/Request/Item/EditItemRequest.php | 21 ++------ src/Request/Item/ItemMetaRequest.php | 41 ++++++++++----- src/Request/Item/ItemsIdCollectionRequest.php | 29 +++++++++++ tests/_support/factories/item.php | 8 ++- tests/_support/schemas/item/definitions.json | 19 +++---- tests/api/Item/ItemTest.php | 50 +++++++++++++++---- tests/api/Item/LimiterTest.php | 4 +- tests/api/Item/ShareTest.php | 4 +- tests/api/Limiter/DatabaseSizeTest.php | 4 +- tests/api/Team/ItemTest.php | 20 ++++++-- tests/api/User/PermissionTest.php | 4 +- 30 files changed, 354 insertions(+), 148 deletions(-) create mode 100644 src/Form/Type/Request/Item/ItemsIdCollectionRequestType.php create mode 100644 src/Migrations/2020/11/Version20201119102626.php create mode 100644 src/Request/Item/ItemsIdCollectionRequest.php diff --git a/src/Controller/Api/Item/ItemController.php b/src/Controller/Api/Item/ItemController.php index 3bab18d9b..65774c19c 100644 --- a/src/Controller/Api/Item/ItemController.php +++ b/src/Controller/Api/Item/ItemController.php @@ -14,6 +14,7 @@ use App\Form\Type\Request\Item\CreateBatchKeypairsRequestType; use App\Form\Type\Request\Item\CreateItemRequestType; use App\Form\Type\Request\Item\ItemsCollectionRequestType; +use App\Form\Type\Request\Item\ItemsIdCollectionRequestType; use App\Limiter\Inspector\ItemCountInspector; use App\Limiter\LimiterInterface; use App\Limiter\Model\LimitCheck; @@ -27,6 +28,7 @@ use App\Request\Item\CreateBatchKeypairsRequest; use App\Request\Item\CreateItemRequest; use App\Request\Item\ItemsCollectionRequest; +use App\Request\Item\ItemsIdCollectionRequest; use App\Security\Voter\ItemVoter; use App\Security\Voter\TeamItemVoter; use Fourxxi\RestRequestError\Exception\FormInvalidRequestException; @@ -87,6 +89,40 @@ public function items(Request $request, ItemRepository $repository, BatchItemVie ); } + /** + * Get all items information. + * + * @SWG\Tag(name="Item") + * @SWG\Parameter( + * name="body", + * in="body", + * @Model(type=ItemsIdCollectionRequestType::class) + * ) + * @SWG\Response( + * response=200, + * description="Success item created", + * @SWG\Schema(type="array", @SWG\Items(type="string")) + * ) + * + * @Route( + * path="/unexists", + * name="api_items_unexists", + * methods={"POST"} + * ) + */ + public function unexists(Request $request, ItemRepository $repository): array + { + $collectionRequest = new ItemsIdCollectionRequest(); + + $form = $this->createForm(ItemsIdCollectionRequestType::class, $collectionRequest); + $form->submit($request->request->all()); + if (!$form->isValid()) { + throw new FormInvalidRequestException($form); + } + + return $repository->getDiffItems($collectionRequest->getItems()); + } + /** * Get single raws item. * diff --git a/src/Entity/Embedded/ItemMeta.php b/src/Entity/Embedded/ItemMeta.php index 836ce04b8..8822f302b 100644 --- a/src/Entity/Embedded/ItemMeta.php +++ b/src/Entity/Embedded/ItemMeta.php @@ -14,36 +14,52 @@ class ItemMeta /** * @ORM\Column(type="integer", options={"default"=0}) */ - private int $attachCount; + private int $attachmentsCount; /** * @ORM\Column(nullable=true) */ - private ?string $webSite; + private ?string $website; - public function __construct(int $attachCount = 0, ?string $webSite = null) + /** + * @ORM\Column(nullable=true) + */ + private ?string $title; + + public function __construct(int $attachmentsCount = 0, ?string $website = null, ?string $title = null) + { + $this->attachmentsCount = $attachmentsCount; + $this->website = $website; + $this->title = $title; + } + + public function getAttachmentsCount(): int + { + return $this->attachmentsCount; + } + + public function setAttachmentsCount(int $attachmentsCount): void { - $this->attachCount = $attachCount; - $this->webSite = $webSite; + $this->attachmentsCount = $attachmentsCount; } - public function getAttachCount(): int + public function getWebsite(): ?string { - return $this->attachCount; + return $this->website; } - public function setAttachCount(int $attachCount): void + public function setWebsite(?string $website): void { - $this->attachCount = $attachCount; + $this->website = $website; } - public function getWebSite(): ?string + public function getTitle(): ?string { - return $this->webSite; + return $this->title; } - public function setWebSite(?string $webSite): void + public function setTitle(?string $title): void { - $this->webSite = $webSite; + $this->title = $title; } } diff --git a/src/Entity/Item.php b/src/Entity/Item.php index e4b6dd99b..31b119f41 100644 --- a/src/Entity/Item.php +++ b/src/Entity/Item.php @@ -51,13 +51,6 @@ class Item implements ChildItemAwareInterface */ protected $previousList; - /** - * @var string|null - * - * @ORM\Column(type="text", nullable=true) - */ - protected $title; - /** * @var string|null * @@ -581,16 +574,6 @@ public function moveTo(Directory $directory): void $this->setTeam($directory->getTeam()); } - public function getTitle(): ?string - { - return $this->title; - } - - public function setTitle(?string $title): void - { - $this->title = $title; - } - public function getTeamKeypairGroupKey(): string { $groups = []; diff --git a/src/Factory/Entity/ItemFactory.php b/src/Factory/Entity/ItemFactory.php index 7da5aea05..4c23b69a7 100644 --- a/src/Factory/Entity/ItemFactory.php +++ b/src/Factory/Entity/ItemFactory.php @@ -25,12 +25,15 @@ public function createTeamKeypairFromRequest(CreateKeypairRequest $request): Ite { $item = new Item($request->getOwner() ?: $request->getUser()); $item->setParentList($request->getTeam()->getDefaultDirectory()); - $item->setTitle(NodeEnumType::TYPE_KEYPAIR); $item->setType(NodeEnumType::TYPE_KEYPAIR); $item->setSecret($request->getSecret()); $item->setRelatedItem($request->getRelatedItem()); $item->setTeam($request->getTeam()); + $meta = new ItemMeta(); + $meta->setTitle(NodeEnumType::TYPE_KEYPAIR); + $item->setMeta($meta); + return $item; } @@ -45,13 +48,13 @@ public function createFromRequest(CreateItemRequest $request): Item $item->setParentList($parentList); $item->setType($request->getType()); $item->setSecret($request->getSecret()); - $item->setTitle($request->getTitle()); $item->setFavorite($request->isFavorite()); $item->setTags(new ArrayCollection($this->transformer->transform($request->getTags()))); $item->setTeam($request->getTeam()); $item->setMeta(new ItemMeta( - $request->getMeta()->getAttachCount() ?: 0, - $request->getMeta()->getWebSite() + $request->getMeta()->getAttachmentsCount() ?: 0, + $request->getMeta()->getWebsite(), + $request->getMeta()->getTitle() )); $item->setRaws($request->getRaws()); diff --git a/src/Factory/Entity/MemberFactory.php b/src/Factory/Entity/MemberFactory.php index d31706efa..760cd462e 100644 --- a/src/Factory/Entity/MemberFactory.php +++ b/src/Factory/Entity/MemberFactory.php @@ -5,6 +5,7 @@ namespace App\Factory\Entity; use App\DBAL\Types\Enum\NodeEnumType; +use App\Entity\Embedded\ItemMeta; use App\Model\DTO\Member; use App\Request\Team\CreateMemberRequest; @@ -33,10 +34,12 @@ public function createFromRequest(CreateMemberRequest $request): Member $keypair = $this->itemFactory->create(); $keypair->setOwner($user); $keypair->setTeam($team); - $keypair->setTitle(NodeEnumType::TYPE_KEYPAIR); $keypair->setType(NodeEnumType::TYPE_KEYPAIR); $keypair->setParentList($team->getDefaultDirectory()); $keypair->setSecret($request->getSecret()); + $meta = new ItemMeta(); + $meta->setTitle(NodeEnumType::TYPE_KEYPAIR); + $keypair->setMeta($meta); return new Member($userTeam, $keypair); } diff --git a/src/Factory/Entity/ShareFactory.php b/src/Factory/Entity/ShareFactory.php index fc1252178..18a6df01e 100644 --- a/src/Factory/Entity/ShareFactory.php +++ b/src/Factory/Entity/ShareFactory.php @@ -5,6 +5,7 @@ namespace App\Factory\Entity; use App\DBAL\Types\Enum\NodeEnumType; +use App\Entity\Embedded\ItemMeta; use App\Model\DTO\Share; use App\Request\Item\ShareBatchItemRequest; @@ -33,11 +34,13 @@ public function createFromRequest(ShareBatchItemRequest $request): array $item = $this->itemFactory->create(); $item->setOwner($user); - $item->setTitle(NodeEnumType::TYPE_KEYPAIR); $item->setType(NodeEnumType::TYPE_KEYPAIR); $item->setParentList($user->getInbox()); $item->setSecret($userRequest->getSecret()); $item->setRelatedItem($relatedItem); + $meta = new ItemMeta(); + $meta->setTitle(NodeEnumType::TYPE_KEYPAIR); + $item->setMeta($meta); $result[$user->getId()->toString()] = new Share($user, $item); } diff --git a/src/Factory/Entity/VaultFactory.php b/src/Factory/Entity/VaultFactory.php index 3f691bc46..09110b9de 100644 --- a/src/Factory/Entity/VaultFactory.php +++ b/src/Factory/Entity/VaultFactory.php @@ -5,6 +5,7 @@ namespace App\Factory\Entity; use App\DBAL\Types\Enum\NodeEnumType; +use App\Entity\Embedded\ItemMeta; use App\Entity\UserTeam; use App\Model\DTO\Vault; use App\Request\Team\CreateVaultRequest; @@ -43,10 +44,12 @@ public function createFromRequest(CreateVaultRequest $request): Vault $item = $this->itemFactory->create(); $item->setOwner($user); $item->setTeam($team); - $item->setTitle(NodeEnumType::TYPE_KEYPAIR); $item->setType(NodeEnumType::TYPE_KEYPAIR); $item->setParentList($team->getDefaultDirectory()); $item->setSecret($keypairRequest->getSecret()); + $meta = new ItemMeta(); + $meta->setTitle(NodeEnumType::TYPE_KEYPAIR); + $item->setMeta($meta); return new Vault($team, $item); } diff --git a/src/Factory/View/Item/ItemMetaViewFactory.php b/src/Factory/View/Item/ItemMetaViewFactory.php index f9ccc308b..4cb5b3683 100644 --- a/src/Factory/View/Item/ItemMetaViewFactory.php +++ b/src/Factory/View/Item/ItemMetaViewFactory.php @@ -12,8 +12,9 @@ class ItemMetaViewFactory public function createSingle(ItemMeta $meta): ItemMetaView { $view = new ItemMetaView(); - $view->setAttachCount($meta->getAttachCount()); - $view->setWebSite($meta->getWebSite()); + $view->setAttachmentsCount($meta->getAttachmentsCount()); + $view->setWebsite($meta->getWebsite()); + $view->setTitle($meta->getTitle()); return $view; } diff --git a/src/Factory/View/Item/ItemViewFactory.php b/src/Factory/View/Item/ItemViewFactory.php index 40705e310..7988500e1 100644 --- a/src/Factory/View/Item/ItemViewFactory.php +++ b/src/Factory/View/Item/ItemViewFactory.php @@ -41,8 +41,6 @@ public function createSingle(Item $item): ItemView $view->setListId($item->getParentList()->getId()->toString()); $view->setPreviousListId($item->getPreviousListId()); $view->setSecret($item->getSecret()); - $view->setTitle($item->getTitle()); - $view->setInvited($this->inviteItemViewFactory->createCollection($item->getKeyPairItemsWithoutRoot())); $view->setOwnerId($item->getOwner()->getId()->toString()); if (null === $item->getTeam()) { diff --git a/src/Form/Type/Request/Item/CreateItemRequestType.php b/src/Form/Type/Request/Item/CreateItemRequestType.php index a1108651f..eb22d365a 100644 --- a/src/Form/Type/Request/Item/CreateItemRequestType.php +++ b/src/Form/Type/Request/Item/CreateItemRequestType.php @@ -42,7 +42,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) NodeEnumType::TYPE_SYSTEM, ], ]) - ->add('title', TextType::class) ->add('secret', TextType::class) ->add('raws', TextType::class) ->add('meta', ItemMetaType::class) diff --git a/src/Form/Type/Request/Item/EditItemRequestType.php b/src/Form/Type/Request/Item/EditItemRequestType.php index b1106cd22..e363d01d7 100644 --- a/src/Form/Type/Request/Item/EditItemRequestType.php +++ b/src/Form/Type/Request/Item/EditItemRequestType.php @@ -24,7 +24,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'choice_value' => 'id', 'property_path' => 'owner', ]) - ->add('title', TextType::class) ->add('secret', TextType::class) ->add('raws', TextType::class) ->add('meta', ItemMetaType::class) diff --git a/src/Form/Type/Request/Item/ItemMetaType.php b/src/Form/Type/Request/Item/ItemMetaType.php index b9a9cf4a3..86df0fd56 100644 --- a/src/Form/Type/Request/Item/ItemMetaType.php +++ b/src/Form/Type/Request/Item/ItemMetaType.php @@ -16,12 +16,13 @@ class ItemMetaType extends AbstractType public function buildForm(FormBuilderInterface $builder, array $options) { $builder - ->add('attachCount', IntegerType::class, [ + ->add('attachmentsCount', IntegerType::class, [ 'required' => false, ]) - ->add('webSite', TextType::class, [ + ->add('website', TextType::class, [ 'required' => false, ]) + ->add('title', TextType::class) ; } diff --git a/src/Form/Type/Request/Item/ItemsIdCollectionRequestType.php b/src/Form/Type/Request/Item/ItemsIdCollectionRequestType.php new file mode 100644 index 000000000..8704845dc --- /dev/null +++ b/src/Form/Type/Request/Item/ItemsIdCollectionRequestType.php @@ -0,0 +1,33 @@ +add('items', CollectionType::class, [ + 'entry_type' => TextType::class, + 'allow_add' => true, + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults([ + 'data_class' => ItemsIdCollectionRequest::class, + 'csrf_protection' => false, + ]); + } +} diff --git a/src/Migrations/2020/11/Version20201119102626.php b/src/Migrations/2020/11/Version20201119102626.php new file mode 100644 index 000000000..facff795c --- /dev/null +++ b/src/Migrations/2020/11/Version20201119102626.php @@ -0,0 +1,35 @@ +abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE item RENAME COLUMN meta_attach_count TO meta_attachments_count'); + $this->addSql('ALTER TABLE item RENAME COLUMN meta_web_site TO meta_website'); + + $this->addSql('ALTER TABLE item ADD meta_title VARCHAR(255) DEFAULT NULL'); + $this->addSql('UPDATE item SET meta_title = title'); + $this->addSql('ALTER TABLE item DROP title'); + } + + public function down(Schema $schema): void + { + $this->abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE item RENAME COLUMN meta_attachments_count TO meta_attach_count'); + $this->addSql('ALTER TABLE item RENAME COLUMN meta_website TO meta_web_site'); + + $this->addSql('ALTER TABLE item ADD title TEXT DEFAULT NULL'); + $this->addSql('UPDATE item SET title = meta_title'); + $this->addSql('ALTER TABLE item DROP meta_title'); + } +} diff --git a/src/Model/View/Item/ItemMetaView.php b/src/Model/View/Item/ItemMetaView.php index ae07ce231..58669e915 100644 --- a/src/Model/View/Item/ItemMetaView.php +++ b/src/Model/View/Item/ItemMetaView.php @@ -11,30 +11,45 @@ final class ItemMetaView /** * @SWG\Property(type="integer", example=1) */ - private int $attachCount; + private int $attachmentsCount; /** * @SWG\Property(type="string", example="http://example.com") */ - private ?string $webSite; + private ?string $website; - public function getAttachCount(): int + /** + * @SWG\Property(type="string") + */ + private ?string $title; + + public function getAttachmentsCount(): int + { + return $this->attachmentsCount; + } + + public function setAttachmentsCount(int $attachmentsCount): void + { + $this->attachmentsCount = $attachmentsCount; + } + + public function getWebsite(): ?string { - return $this->attachCount; + return $this->website; } - public function setAttachCount(int $attachCount): void + public function setWebsite(?string $website): void { - $this->attachCount = $attachCount; + $this->website = $website; } - public function getWebSite(): ?string + public function getTitle(): ?string { - return $this->webSite; + return $this->title; } - public function setWebSite(?string $webSite): void + public function setTitle(?string $title): void { - $this->webSite = $webSite; + $this->title = $title; } } diff --git a/src/Model/View/Item/ItemView.php b/src/Model/View/Item/ItemView.php index 361dc24a1..5b5eaea9c 100644 --- a/src/Model/View/Item/ItemView.php +++ b/src/Model/View/Item/ItemView.php @@ -140,18 +140,13 @@ final class ItemView */ private ?string $listId; - /** - * @SWG\Property(type="string", example="Title") - */ - private ?string $title; - /** * @SWG\Property(type="string", example="-----BEGIN PGP MESSAGE----- Version: OpenPGP.js v4.2.2 ....") */ private ?string $secret; /** - * @SWG\Property(@Model(type=SharedChildItemView::class)) + * @SWG\Property(@Model(type=ItemMetaView::class)) */ private ItemMetaView $meta; @@ -163,7 +158,7 @@ final class ItemView private array $invited; /** - * @SWG\Property(@Model(type=SharedChildItemView::class)) + * @SWG\Property(@Model(type=SharedItemView::class)) */ private ?SharedItemView $shared; @@ -395,16 +390,6 @@ public function setTeamId(?string $teamId): void $this->teamId = $teamId; } - public function getTitle(): ?string - { - return $this->title; - } - - public function setTitle(?string $title): void - { - $this->title = $title; - } - public function getMeta(): ItemMetaView { return $this->meta; diff --git a/src/Modifier/ItemModifier.php b/src/Modifier/ItemModifier.php index bc8af124d..e4031cb6e 100644 --- a/src/Modifier/ItemModifier.php +++ b/src/Modifier/ItemModifier.php @@ -31,11 +31,11 @@ public function modifyByRequest(EditItemRequest $request): Item } $item->setSecret($request->getSecret()); $item->setMeta(new ItemMeta( - $request->getMeta()->getAttachCount() ?: 0, - $request->getMeta()->getWebSite() + $request->getMeta()->getAttachmentsCount() ?: 0, + $request->getMeta()->getWebsite(), + $request->getMeta()->getTitle() )); $item->setRaws($request->getRaws()); - $item->setTitle($request->getTitle()); $item->setTags(new ArrayCollection($this->transformer->transform($request->getTags()))); $this->repository->save($item); diff --git a/src/Repository/ItemRepository.php b/src/Repository/ItemRepository.php index 4fcc9d0a9..560525b63 100644 --- a/src/Repository/ItemRepository.php +++ b/src/Repository/ItemRepository.php @@ -33,6 +33,26 @@ public function __construct(ManagerRegistry $registry, LoggerInterface $logger) $this->logger = $logger; } + /** + * @param string[] $itemIds + * + * @return string[] + */ + public function getDiffItems(array $itemIds): array + { + $queryBuilder = $this->createQueryBuilder('item'); + $queryBuilder + ->select('item.id') + ->where('item.id IN (:items)') + ->setParameter('items', $itemIds) + ; + + $existItems = $queryBuilder->getQuery()->getScalarResult(); + $existItems = array_column($existItems, 'id'); + + return array_values(array_diff($itemIds, $existItems)); + } + /** * @return Item[] */ diff --git a/src/Request/Item/CreateItemRequest.php b/src/Request/Item/CreateItemRequest.php index 754cb82b6..cb84e5acc 100644 --- a/src/Request/Item/CreateItemRequest.php +++ b/src/Request/Item/CreateItemRequest.php @@ -20,11 +20,6 @@ final class CreateItemRequest */ private ?string $type; - /** - * @Assert\NotBlank() - */ - private ?string $title; - /** * @Assert\Valid */ @@ -126,16 +121,6 @@ public function getTeam(): ?Team return null !== $this->getList() ? $this->getList()->getTeam() : null; } - public function getTitle(): ?string - { - return $this->title; - } - - public function setTitle(?string $title): void - { - $this->title = $title; - } - public function getMeta(): ItemMetaRequest { return $this->meta; diff --git a/src/Request/Item/EditItemRequest.php b/src/Request/Item/EditItemRequest.php index 66a9fd75e..c0869c781 100644 --- a/src/Request/Item/EditItemRequest.php +++ b/src/Request/Item/EditItemRequest.php @@ -12,11 +12,6 @@ final class EditItemRequest { private ?User $owner; - /** - * @Assert\NotBlank() - */ - private ?string $title; - /** * @Assert\NotBlank() */ @@ -37,12 +32,12 @@ public function __construct(Item $item) { $this->tags = $item->getTags()->toArray(); $this->secret = $item->getSecret(); - $this->title = $item->getTitle(); $this->owner = $item->getSignedOwner(); $this->item = $item; $this->meta = new ItemMetaRequest(); - $this->meta->setAttachCount($item->getMeta()->getAttachCount()); - $this->meta->setWebSite($item->getMeta()->getWebSite()); + $this->meta->setAttachmentsCount($item->getMeta()->getAttachmentsCount()); + $this->meta->setWebsite($item->getMeta()->getWebsite()); + $this->meta->setTitle($item->getMeta()->getTitle()); $this->raws = $item->getRaws(); } @@ -81,16 +76,6 @@ public function getItem(): Item return $this->item; } - public function getTitle(): ?string - { - return $this->title; - } - - public function setTitle(?string $title): void - { - $this->title = $title; - } - public function getMeta(): ItemMetaRequest { return $this->meta; diff --git a/src/Request/Item/ItemMetaRequest.php b/src/Request/Item/ItemMetaRequest.php index dda9a14dd..49d988e79 100644 --- a/src/Request/Item/ItemMetaRequest.php +++ b/src/Request/Item/ItemMetaRequest.php @@ -4,35 +4,52 @@ namespace App\Request\Item; +use Symfony\Component\Validator\Constraints as Assert; + final class ItemMetaRequest { - private ?int $attachCount; + private ?int $attachmentsCount; + + private ?string $website; - private ?string $webSite; + /** + * @Assert\NotBlank() + */ + private ?string $title; public function __construct() { - $this->attachCount = null; - $this->webSite = null; + $this->attachmentsCount = null; + $this->website = null; + } + + public function getAttachmentsCount(): ?int + { + return $this->attachmentsCount; + } + + public function setAttachmentsCount(?int $attachmentsCount): void + { + $this->attachmentsCount = $attachmentsCount; } - public function getAttachCount(): ?int + public function getWebsite(): ?string { - return $this->attachCount; + return $this->website; } - public function setAttachCount(?int $attachCount): void + public function setWebsite(?string $website): void { - $this->attachCount = $attachCount; + $this->website = $website; } - public function getWebSite(): ?string + public function getTitle(): ?string { - return $this->webSite; + return $this->title; } - public function setWebSite(?string $webSite): void + public function setTitle(?string $title): void { - $this->webSite = $webSite; + $this->title = $title; } } diff --git a/src/Request/Item/ItemsIdCollectionRequest.php b/src/Request/Item/ItemsIdCollectionRequest.php new file mode 100644 index 000000000..4cd81b293 --- /dev/null +++ b/src/Request/Item/ItemsIdCollectionRequest.php @@ -0,0 +1,29 @@ +items; + } + + /** + * @param string[] $items + */ + public function setItems(array $items): void + { + $this->items = $items; + } +} diff --git a/tests/_support/factories/item.php b/tests/_support/factories/item.php index 0988608a2..8dc7cbc03 100644 --- a/tests/_support/factories/item.php +++ b/tests/_support/factories/item.php @@ -2,6 +2,7 @@ use App\DBAL\Types\Enum\NodeEnumType; use App\Entity\Directory; +use App\Entity\Embedded\ItemMeta; use App\Entity\Item; use App\Entity\User; use League\FactoryMuffin\FactoryMuffin; @@ -11,7 +12,6 @@ $fm->define(Item::class)->setDefinitions([ 'parent_list' => 'entity|'.Directory::class, 'secret' => Faker::word(), - 'title' => Faker::word(), 'raws' => Faker::word(), 'original_item_id' => null, 'favorite' => false, @@ -24,4 +24,10 @@ 'previous_list_id' => '', 'owner' => 'entity|'.User::class, 'item' => null, + 'meta' => function () { + $meta = new ItemMeta(); + $meta->setTitle(Faker::word()()); + + return $meta; + }, ]); diff --git a/tests/_support/schemas/item/definitions.json b/tests/_support/schemas/item/definitions.json index 72e4240ac..142b45073 100644 --- a/tests/_support/schemas/item/definitions.json +++ b/tests/_support/schemas/item/definitions.json @@ -19,16 +19,20 @@ "meta": { "type": "object", "properties": { - "attachCount": { + "attachmentsCount": { "type": "integer" }, - "webSite": { + "website": { + "type": ["null", "string"] + }, + "title": { "type": ["null", "string"] } }, "required": [ - "attachCount", - "webSite" + "attachmentsCount", + "website", + "title" ] }, "invited": { @@ -115,16 +119,12 @@ }, "isShared": { "type": "boolean" - } , - "title": { - "type": ["string", "null"] } }, "required": [ "id", "type", "listId", - "title", "secret", "invited", "shared", @@ -134,7 +134,8 @@ "favorite", "ownerId", "originalItemId", - "previousListId" + "previousListId", + "meta" ] }, "item_raw": { diff --git a/tests/api/Item/ItemTest.php b/tests/api/Item/ItemTest.php index 0f547d40e..344559d5b 100644 --- a/tests/api/Item/ItemTest.php +++ b/tests/api/Item/ItemTest.php @@ -12,6 +12,7 @@ use Codeception\Module\REST; use Codeception\Test\Unit; use Codeception\Util\HttpCode; +use Ramsey\Uuid\Uuid; class ItemTest extends Unit { @@ -42,6 +43,34 @@ public function getItem() $I->seeResponseIsValidOnJsonSchemaString($I->getSchema('item/item_raw.json')); } + /** @test */ + public function getUnExists() + { + $I = $this->tester; + + /** @var User $user */ + $user = $I->have(User::class); + + $item = $I->createUserItem($user); + $item1 = $I->createUserItem($user); + + $unexists = Uuid::uuid4()->toString(); + $unexists1 = Uuid::uuid4()->toString(); + + $I->login($user); + $I->sendPOST('/items/unexists', ['items' => [ + $item->getId()->toString(), + $item1->getId()->toString(), + $unexists, + $unexists1, + ]]); + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContains($unexists); + $I->seeResponseContains($unexists1); + $I->dontSeeResponseContains($item->getId()->toString()); + $I->dontSeeResponseContains($item1->getId()->toString()); + } + /** @test */ public function getBatchItem() { @@ -200,7 +229,8 @@ public function createCredItem() 'listId' => 'invalid-uuid', 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + ], 'favorite' => false, 'tags' => ['tag'], ]); @@ -210,10 +240,10 @@ public function createCredItem() 'listId' => $directory->getId()->toString(), 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', 'favorite' => false, 'meta' => [ - 'attachCount' => 2, + 'attachmentsCount' => 2, + 'title' => 'item title', ], 'raws' => uniqid(), 'tags' => ['tag'], @@ -225,9 +255,9 @@ public function createCredItem() 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), 'meta' => [ - 'webSite' => 'http://examle.com', + 'website' => 'http://examle.com', + 'title' => 'item title', ], - 'title' => 'item title', ]); $I->seeResponseCodeIs(HttpCode::OK); $I->seeResponseContainsJson(['listId' => $user->getDefaultDirectory()->getId()->toString()]); @@ -248,10 +278,10 @@ public function editItem() $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendPATCH(sprintf('items/%s', $item->getId()->toString()), [ 'secret' => 'secret-edit', - 'title' => 'item title (edited)', 'meta' => [ - 'attachCount' => 3, - 'webSite' => 'http://examle.com/login', + 'attachmentsCount' => 3, + 'website' => 'http://examle.com/login', + 'title' => 'item title (edited)', ], 'raws' => uniqid(), ]); @@ -259,7 +289,9 @@ public function editItem() $I->sendPATCH(sprintf('/items/%s', $otherItem->getId()), [ 'secret' => 'secret-edit', - 'title' => 'item title (edited)', + 'meta' => [ + 'title' => 'item title (edited)', + ], ]); $I->seeResponseCodeIs(HttpCode::FORBIDDEN); } diff --git a/tests/api/Item/LimiterTest.php b/tests/api/Item/LimiterTest.php index 793704df9..a97a005f1 100644 --- a/tests/api/Item/LimiterTest.php +++ b/tests/api/Item/LimiterTest.php @@ -89,7 +89,9 @@ private function getItemBody(User $user, array $options = []): array 'listId' => $directory->getId()->toString(), 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + 'title' => 'item title', + ], 'favorite' => false, 'tags' => ['tag'], ], $options); diff --git a/tests/api/Item/ShareTest.php b/tests/api/Item/ShareTest.php index 66c337a78..f04eb242c 100644 --- a/tests/api/Item/ShareTest.php +++ b/tests/api/Item/ShareTest.php @@ -142,7 +142,9 @@ public function lastUpdatedRelatedItem() $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendPATCH(sprintf('items/%s', $item->getId()->toString()), [ 'secret' => 'secret-edit', - 'title' => 'item title (edited)', + 'meta' => [ + 'title' => 'item title (edited)', + ], ]); $I->seeResponseCodeIs(HttpCode::OK); diff --git a/tests/api/Limiter/DatabaseSizeTest.php b/tests/api/Limiter/DatabaseSizeTest.php index 263c49757..b4a35db30 100644 --- a/tests/api/Limiter/DatabaseSizeTest.php +++ b/tests/api/Limiter/DatabaseSizeTest.php @@ -60,7 +60,9 @@ private function getItemBody(User $user, array $options = []): array 'listId' => $user->getDefaultDirectory()->getId()->toString(), 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + 'title' => 'item title', + ], 'favorite' => false, 'tags' => ['tag'], ], $options); diff --git a/tests/api/Team/ItemTest.php b/tests/api/Team/ItemTest.php index 224884833..ae8db1eee 100644 --- a/tests/api/Team/ItemTest.php +++ b/tests/api/Team/ItemTest.php @@ -54,7 +54,9 @@ public function createTeamItem() 'listId' => $directory->getId()->toString(), 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + 'title' => 'item title', + ], 'favorite' => false, 'tags' => ['tag'], ]); @@ -309,7 +311,9 @@ private function canEditTeamItem(User $user, Item $item) $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendPATCH(sprintf('items/%s', $item->getId()->toString()), [ 'secret' => 'secret-edit', - 'title' => 'item title (edited)', + 'meta' => [ + 'title' => 'item title (edited)', + ], ]); $I->seeResponseCodeIs(HttpCode::OK); @@ -324,7 +328,9 @@ private function dontEditTeamItem(User $user, Item $item) $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendPATCH(sprintf('items/%s', $item->getId()->toString()), [ 'secret' => 'secret-edit', - 'title' => 'item title (edited)', + 'meta' => [ + 'title' => 'item title (edited)', + ], ]); $I->seeResponseCodeIs(HttpCode::FORBIDDEN); } @@ -338,7 +344,9 @@ private function canCreateTeamItem(User $user, Directory $directory): void 'listId' => $directory->getId()->toString(), 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + 'title' => 'item title', + ], 'favorite' => false, 'tags' => ['tag'], ]); @@ -355,7 +363,9 @@ private function dontCreateTeamItem(User $user, Directory $directory): void 'listId' => $directory->getId()->toString(), 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + 'title' => 'item title', + ], 'favorite' => false, 'tags' => ['tag'], ]); diff --git a/tests/api/User/PermissionTest.php b/tests/api/User/PermissionTest.php index 0fe13f1f5..ccf21ce9b 100644 --- a/tests/api/User/PermissionTest.php +++ b/tests/api/User/PermissionTest.php @@ -96,7 +96,9 @@ public function itemPermissions() $I->sendPOST('items', [ 'type' => NodeEnumType::TYPE_CRED, 'secret' => uniqid(), - 'title' => 'item title', + 'meta' => [ + 'title' => 'item title', + ], 'favorite' => false, 'tags' => ['tag'], ]); From 7412021c86482467cbd2d6051db25587212b1d4d Mon Sep 17 00:00:00 2001 From: Aleksandr Burov Date: Mon, 23 Nov 2020 14:53:08 +0300 Subject: [PATCH 2/4] [Team] CAES-1517: Return teamView after leave team. --- src/Controller/Api/Team/MemberController.php | 11 +++++++---- tests/api/Team/MemberTest.php | 4 ++-- tests/api/Team/TeamTest.php | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Controller/Api/Team/MemberController.php b/src/Controller/Api/Team/MemberController.php index 9fd5788a9..7a3b0cbce 100644 --- a/src/Controller/Api/Team/MemberController.php +++ b/src/Controller/Api/Team/MemberController.php @@ -9,11 +9,13 @@ use App\Entity\User; use App\Entity\UserTeam; use App\Factory\View\Team\MemberViewFactory; +use App\Factory\View\Team\TeamViewFactory; use App\Form\Type\Request\Team\BatchCreateMemberRequestType; use App\Form\Type\Request\Team\CreateMemberRequestType; use App\Form\Type\Request\Team\EditUserTeamType; use App\Model\Query\MemberListQuery; use App\Model\View\Team\MemberView; +use App\Model\View\Team\TeamView; use App\Repository\UserTeamRepository; use App\Request\Team\BatchCreateMemberRequest; use App\Request\Team\CreateMemberRequest; @@ -239,8 +241,9 @@ public function removeMember( * * @SWG\Tag(name="Team / Member") * @SWG\Response( - * response=204, - * description="Leave team member" + * response=200, + * description="Leave team member", + * @Model(type=TeamView::class) * ) * * @Route( @@ -249,14 +252,14 @@ public function removeMember( * methods={"POST"} * ) */ - public function leaveTeam(Team $team, UserTeamRepository $userTeamRepository): JsonResponse + public function leaveTeam(Team $team, TeamViewFactory $viewFactory, UserTeamRepository $userTeamRepository): TeamView { $this->denyAccessUnlessGranted(TeamVoter::LEAVE, $team); $userTeam = $team->getUserTeamByUser($this->getUser()); $userTeamRepository->remove($userTeam); - return new JsonResponse([], Response::HTTP_NO_CONTENT); + return $viewFactory->createSingle($team); } /** diff --git a/tests/api/Team/MemberTest.php b/tests/api/Team/MemberTest.php index 9f0b0624f..2d067fcfc 100644 --- a/tests/api/Team/MemberTest.php +++ b/tests/api/Team/MemberTest.php @@ -287,7 +287,7 @@ public function leaveTeam() $I->login($member); $I->sendPOST(sprintf('teams/%s/leave', $team->getId()->toString())); - $I->seeResponseCodeIs(HttpCode::NO_CONTENT); + $I->seeResponseCodeIs(HttpCode::OK); $I->sendPOST(sprintf('teams/%s/leave', $otherTeam->getId()->toString())); $I->seeResponseCodeIs(HttpCode::FORBIDDEN); @@ -295,7 +295,7 @@ public function leaveTeam() $I->login($user); $I->sendPOST(sprintf('teams/%s/leave', $otherTeam->getId()->toString())); - $I->seeResponseCodeIs(HttpCode::NO_CONTENT); + $I->seeResponseCodeIs(HttpCode::OK); $I->dontSeeInDatabase('groups', ['id' => $otherTeam->getId()->toString()]); } } diff --git a/tests/api/Team/TeamTest.php b/tests/api/Team/TeamTest.php index e0dc900e2..1192c52a8 100644 --- a/tests/api/Team/TeamTest.php +++ b/tests/api/Team/TeamTest.php @@ -173,7 +173,7 @@ public function pinnedTeam() $I->seeResponseContainsJson(['pinned' => true]); $I->sendPOST(sprintf('teams/%s/leave', $team->getId()->toString())); - $I->seeResponseCodeIs(HttpCode::NO_CONTENT); + $I->seeResponseCodeIs(HttpCode::OK); $I->sendGET(sprintf('teams/%s', $team->getId()->toString())); $I->seeResponseCodeIs(HttpCode::OK); From 4fc00caf9bc758cfd7c5acdd1e030c1399cb3b3b Mon Sep 17 00:00:00 2001 From: Aleksandr Burov Date: Tue, 24 Nov 2020 10:20:50 +0300 Subject: [PATCH 3/4] [Item] CAES-1521: Rework handle request form. --- composer.json | 5 +++++ src/Controller/Api/Item/UpdateController.php | 2 +- src/Controller/Api/Team/TeamController.php | 2 +- src/Form/Type/Request/Item/EditItemRequestType.php | 6 ++++++ src/Form/Type/Request/Team/EditTeamRequestType.php | 6 ++++++ tests/api/Item/ItemTest.php | 13 ++++++++++++- 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/composer.json b/composer.json index 320e0fe60..3d33d904c 100755 --- a/composer.json +++ b/composer.json @@ -105,6 +105,11 @@ ], "post-update-cmd": [ "@auto-scripts" + ], + "analyse": [ + "@php vendor/bin/php-cs-fixer fix --config=.php_cs.dist -vv", + "@php vendor/bin/phpstan analyse --memory-limit=-1", + "@php vendor/bin/psalm --show-info=false" ] }, "conflict": { diff --git a/src/Controller/Api/Item/UpdateController.php b/src/Controller/Api/Item/UpdateController.php index c67d7ad41..5c7e6a1c4 100644 --- a/src/Controller/Api/Item/UpdateController.php +++ b/src/Controller/Api/Item/UpdateController.php @@ -87,7 +87,7 @@ public function edit( $editRequest = new EditItemRequest($item); $form = $this->createForm(EditItemRequestType::class, $editRequest); - $form->submit($request->request->all()); + $form->handleRequest($request); if (!$form->isValid()) { throw new FormInvalidRequestException($form); } diff --git a/src/Controller/Api/Team/TeamController.php b/src/Controller/Api/Team/TeamController.php index 8ebaa542c..d2a786e7f 100644 --- a/src/Controller/Api/Team/TeamController.php +++ b/src/Controller/Api/Team/TeamController.php @@ -87,7 +87,7 @@ public function update( $editRequest = new EditTeamRequest($team); $form = $this->createForm(EditTeamRequestType::class, $editRequest); - $form->submit($request->request->all()); + $form->handleRequest($request); if (!$form->isValid()) { throw new FormInvalidRequestException($form); } diff --git a/src/Form/Type/Request/Item/EditItemRequestType.php b/src/Form/Type/Request/Item/EditItemRequestType.php index e363d01d7..7e8776afa 100644 --- a/src/Form/Type/Request/Item/EditItemRequestType.php +++ b/src/Form/Type/Request/Item/EditItemRequestType.php @@ -40,8 +40,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ + 'method' => 'PATCH', 'data_class' => EditItemRequest::class, 'csrf_protection' => false, ]); } + + public function getBlockPrefix() + { + return ''; + } } diff --git a/src/Form/Type/Request/Team/EditTeamRequestType.php b/src/Form/Type/Request/Team/EditTeamRequestType.php index bf64aa073..acca2a460 100644 --- a/src/Form/Type/Request/Team/EditTeamRequestType.php +++ b/src/Form/Type/Request/Team/EditTeamRequestType.php @@ -22,8 +22,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ + 'method' => 'PATCH', 'data_class' => EditTeamRequest::class, 'csrf_protection' => false, ]); } + + public function getBlockPrefix() + { + return ''; + } } diff --git a/tests/api/Item/ItemTest.php b/tests/api/Item/ItemTest.php index 344559d5b..5e0b4ae52 100644 --- a/tests/api/Item/ItemTest.php +++ b/tests/api/Item/ItemTest.php @@ -283,10 +283,21 @@ public function editItem() 'website' => 'http://examle.com/login', 'title' => 'item title (edited)', ], - 'raws' => uniqid(), + 'raws' => 'some-raws-data', ]); $I->seeResponseCodeIs(HttpCode::OK); + $I->haveHttpHeader('Content-Type', 'application/json'); + $I->sendPATCH(sprintf('items/%s', $item->getId()->toString()), [ + 'secret' => 'secret-edit (edited)', + ]); + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContainsJson(['secret' => 'secret-edit (edited)', 'meta' => ['title' => 'item title (edited)']]); + + $I->sendGET(sprintf('/items/%s/raws', $item->getId()->toString())); + $I->seeResponseCodeIs(HttpCode::OK); + $I->seeResponseContains('some-raws-data'); + $I->sendPATCH(sprintf('/items/%s', $otherItem->getId()), [ 'secret' => 'secret-edit', 'meta' => [ From df30b7903d64b09f100f0ae342462cb24eaeb1f8 Mon Sep 17 00:00:00 2001 From: Aleksandr Burov Date: Thu, 26 Nov 2020 10:32:34 +0300 Subject: [PATCH 4/4] [Item] CAES-1527: Fixed save long website. --- src/Entity/Embedded/ItemMeta.php | 2 +- .../2020/11/Version20201126072730.php | 32 +++++++++++++++++++ src/Request/Item/ItemMetaRequest.php | 1 + 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/Migrations/2020/11/Version20201126072730.php diff --git a/src/Entity/Embedded/ItemMeta.php b/src/Entity/Embedded/ItemMeta.php index 8822f302b..ea191a8cc 100644 --- a/src/Entity/Embedded/ItemMeta.php +++ b/src/Entity/Embedded/ItemMeta.php @@ -17,7 +17,7 @@ class ItemMeta private int $attachmentsCount; /** - * @ORM\Column(nullable=true) + * @ORM\Column(type="text", nullable=true) */ private ?string $website; diff --git a/src/Migrations/2020/11/Version20201126072730.php b/src/Migrations/2020/11/Version20201126072730.php new file mode 100644 index 000000000..81571d4d2 --- /dev/null +++ b/src/Migrations/2020/11/Version20201126072730.php @@ -0,0 +1,32 @@ +abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE item ALTER meta_website TYPE TEXT'); + $this->addSql('ALTER TABLE item ALTER meta_website DROP DEFAULT'); + } + + public function down(Schema $schema): void + { + $this->abortIf('postgresql' !== $this->connection->getDatabasePlatform()->getName(), 'Migration can only be executed safely on \'postgresql\'.'); + + $this->addSql('ALTER TABLE item ALTER meta_website TYPE VARCHAR(255)'); + $this->addSql('ALTER TABLE item ALTER meta_website DROP DEFAULT'); + } +} diff --git a/src/Request/Item/ItemMetaRequest.php b/src/Request/Item/ItemMetaRequest.php index 49d988e79..f719a0a5d 100644 --- a/src/Request/Item/ItemMetaRequest.php +++ b/src/Request/Item/ItemMetaRequest.php @@ -14,6 +14,7 @@ final class ItemMetaRequest /** * @Assert\NotBlank() + * @Assert\Length(max="255") */ private ?string $title;